diff options
| author | 2022-12-16 22:19:31 +0000 | |
|---|---|---|
| committer | 2022-12-16 22:19:31 +0000 | |
| commit | 2ce213c2243c1240cd64b7c44fed750695b4a17d (patch) | |
| tree | 2ffddc2c7dec95286cfa34882c79815f5f4340fd /java/src | |
| parent | 4ebf21f578b78ed83de87f829c4a126c9bb40759 (diff) | |
| parent | 1d4f1782d24d8d881713de4e3ad9ca9156913455 (diff) | |
Merge "Create an action row view" into tm-qpr-dev
Diffstat (limited to 'java/src')
3 files changed, 200 insertions, 111 deletions
diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java index 6d5304d9..6cf1aef4 100644 --- a/java/src/com/android/intentresolver/ChooserActivity.java +++ b/java/src/com/android/intentresolver/ChooserActivity.java @@ -77,7 +77,6 @@ import android.util.Log; import android.util.Size; import android.util.Slog; import android.util.SparseArray; -import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; @@ -86,7 +85,6 @@ import android.view.WindowInsets; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.LinearInterpolator; -import android.widget.Button; import android.widget.TextView; import androidx.annotation.MainThread; @@ -97,7 +95,6 @@ import androidx.viewpager.widget.ViewPager; import com.android.intentresolver.AbstractMultiProfilePagerAdapter.EmptyState; import com.android.intentresolver.AbstractMultiProfilePagerAdapter.EmptyStateProvider; import com.android.intentresolver.NoCrossProfileEmptyStateProvider.DevicePolicyBlockerEmptyState; -import com.android.intentresolver.ResolverListAdapter.ViewHolder; import com.android.intentresolver.chooser.DisplayResolveInfo; import com.android.intentresolver.chooser.MultiDisplayResolveInfo; import com.android.intentresolver.chooser.TargetInfo; @@ -108,6 +105,7 @@ import com.android.intentresolver.model.AppPredictionServiceResolverComparator; import com.android.intentresolver.model.ResolverRankerServiceResolverComparator; import com.android.intentresolver.shortcuts.AppPredictorFactory; import com.android.intentresolver.shortcuts.ShortcutLoader; +import com.android.intentresolver.widget.ActionRow; import com.android.intentresolver.widget.ResolverDrawerLayout; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; @@ -629,7 +627,7 @@ public class ChooserActivity extends ResolverActivity implements updateProfileViewButton(); } - private void onCopyButtonClicked(View v) { + private void onCopyButtonClicked() { Intent targetIntent = getTargetIntent(); if (targetIntent == null) { finish(); @@ -752,21 +750,23 @@ public class ChooserActivity extends ResolverActivity implements int previewType = ChooserContentPreviewUi.findPreferredContentPreview( targetIntent, getContentResolver(), this::isImageType); - ChooserContentPreviewUi.ActionButtonFactory buttonFactory = - new ChooserContentPreviewUi.ActionButtonFactory() { + ChooserContentPreviewUi.ActionFactory actionFactory = + new ChooserContentPreviewUi.ActionFactory() { @Override - public Button createCopyButton() { - return ChooserActivity.this.createCopyButton(); + public ActionRow.Action createCopyButton() { + return ChooserActivity.this.createCopyAction(); } + @Nullable @Override - public Button createEditButton() { - return ChooserActivity.this.createEditButton(targetIntent); + public ActionRow.Action createEditButton() { + return ChooserActivity.this.createEditAction(targetIntent); } + @Nullable @Override - public Button createNearbyButton() { - return ChooserActivity.this.createNearbyButton(targetIntent); + public ActionRow.Action createNearbyButton() { + return ChooserActivity.this.createNearbyAction(targetIntent); } }; @@ -775,7 +775,7 @@ public class ChooserActivity extends ResolverActivity implements targetIntent, getResources(), getLayoutInflater(), - buttonFactory, + actionFactory, parent, previewCoordinator, getContentResolver(), @@ -902,54 +902,46 @@ public class ChooserActivity extends ResolverActivity implements return dri; } - private Button createActionButton(Drawable icon, CharSequence title, View.OnClickListener r) { - Button b = (Button) LayoutInflater.from(this).inflate(R.layout.chooser_action_button, null); - if (icon != null) { - final int size = getResources() - .getDimensionPixelSize(R.dimen.chooser_action_button_icon_size); - icon.setBounds(0, 0, size, size); - b.setCompoundDrawablesRelative(icon, null, null, null); - } - b.setText(title); - b.setOnClickListener(r); - return b; - } - - private Button createCopyButton() { - final Button b = createActionButton( + private ActionRow.Action createCopyAction() { + return new ActionRow.Action( + com.android.internal.R.id.chooser_copy_button, + getString(com.android.internal.R.string.copy), getDrawable(com.android.internal.R.drawable.ic_menu_copy_material), - getString(com.android.internal.R.string.copy), this::onCopyButtonClicked); - b.setId(com.android.internal.R.id.chooser_copy_button); - return b; + this::onCopyButtonClicked); } - private @Nullable Button createNearbyButton(Intent originalIntent) { + @Nullable + private ActionRow.Action createNearbyAction(Intent originalIntent) { final TargetInfo ti = getNearbySharingTarget(originalIntent); - if (ti == null) return null; + if (ti == null) { + return null; + } - final Button b = createActionButton( - ti.getDisplayIconHolder().getDisplayIcon(), + return new ActionRow.Action( + com.android.internal.R.id.chooser_nearby_button, ti.getDisplayLabel(), - (View unused) -> { + ti.getDisplayIconHolder().getDisplayIcon(), + () -> { getChooserActivityLogger().logActionSelected( ChooserActivityLogger.SELECTION_TYPE_NEARBY); // Action bar is user-independent, always start as primary safelyStartActivityAsUser(ti, getPersonalProfileUserHandle()); finish(); - } - ); - b.setId(com.android.internal.R.id.chooser_nearby_button); - return b; + }); } - private @Nullable Button createEditButton(Intent originalIntent) { + @Nullable + private ActionRow.Action createEditAction(Intent originalIntent) { final TargetInfo ti = getEditSharingTarget(originalIntent); - if (ti == null) return null; + if (ti == null) { + return null; + } - final Button b = createActionButton( - ti.getDisplayIconHolder().getDisplayIcon(), + return new ActionRow.Action( + com.android.internal.R.id.chooser_edit_button, ti.getDisplayLabel(), - (View unused) -> { + ti.getDisplayIconHolder().getDisplayIcon(), + () -> { // Log share completion via edit getChooserActivityLogger().logActionSelected( ChooserActivityLogger.SELECTION_TYPE_EDIT); @@ -967,8 +959,6 @@ public class ChooserActivity extends ResolverActivity implements } } ); - b.setId(com.android.internal.R.id.chooser_edit_button); - return b; } @Nullable @@ -977,17 +967,6 @@ public class ChooserActivity extends ResolverActivity implements return firstImage != null && firstImage.isVisibleToUser() ? firstImage : null; } - private void addActionButton(ViewGroup parent, Button b) { - if (b == null) return; - final ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams( - LayoutParams.WRAP_CONTENT, - LayoutParams.WRAP_CONTENT - ); - final int gap = getResources().getDimensionPixelSize(R.dimen.resolver_icon_margin) / 2; - lp.setMarginsRelative(gap, 0, gap, 0); - parent.addView(b, lp); - } - /** * Wrapping the ContentResolver call to expose for easier mocking, * and to avoid mocking Android core classes. diff --git a/java/src/com/android/intentresolver/ChooserContentPreviewUi.java b/java/src/com/android/intentresolver/ChooserContentPreviewUi.java index 22ff55db..f9f4ee98 100644 --- a/java/src/com/android/intentresolver/ChooserContentPreviewUi.java +++ b/java/src/com/android/intentresolver/ChooserContentPreviewUi.java @@ -34,11 +34,12 @@ import android.util.PluralsMessageFormatter; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.ViewGroup.LayoutParams; -import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.Nullable; + +import com.android.intentresolver.widget.ActionRow; import com.android.intentresolver.widget.RoundedRectImageView; import com.android.internal.annotations.VisibleForTesting; @@ -88,15 +89,17 @@ public final class ChooserContentPreviewUi { * they're determined to be appropriate for the particular preview we display. * TODO: clarify why action buttons are part of preview logic. */ - public interface ActionButtonFactory { - /** Create a button that copies the share content to the clipboard. */ - Button createCopyButton(); + public interface ActionFactory { + /** Create an action that copies the share content to the clipboard. */ + ActionRow.Action createCopyButton(); - /** Create a button that opens the share content in a system-default editor. */ - Button createEditButton(); + /** Create an action that opens the share content in a system-default editor. */ + @Nullable + ActionRow.Action createEditButton(); - /** Create a "Share to Nearby" button. */ - Button createNearbyButton(); + /** Create an "Share to Nearby" action. */ + @Nullable + ActionRow.Action createNearbyButton(); } /** @@ -173,7 +176,7 @@ public final class ChooserContentPreviewUi { Intent targetIntent, Resources resources, LayoutInflater layoutInflater, - ActionButtonFactory buttonFactory, + ActionFactory actionFactory, ViewGroup parent, ContentPreviewCoordinator previewCoord, ContentResolver contentResolver, @@ -184,18 +187,16 @@ public final class ChooserContentPreviewUi { case CONTENT_PREVIEW_TEXT: layout = displayTextContentPreview( targetIntent, - resources, layoutInflater, - buttonFactory, + createTextPreviewActions(actionFactory), parent, previewCoord); break; case CONTENT_PREVIEW_IMAGE: layout = displayImageContentPreview( targetIntent, - resources, layoutInflater, - buttonFactory, + createImagePreviewActions(actionFactory), parent, previewCoord, contentResolver, @@ -206,7 +207,7 @@ public final class ChooserContentPreviewUi { targetIntent, resources, layoutInflater, - buttonFactory, + createFilePreviewActions(actionFactory), parent, previewCoord, contentResolver); @@ -235,20 +236,18 @@ public final class ChooserContentPreviewUi { private static ViewGroup displayTextContentPreview( Intent targetIntent, - Resources resources, LayoutInflater layoutInflater, - ActionButtonFactory buttonFactory, + List<ActionRow.Action> actions, ViewGroup parent, ContentPreviewCoordinator previewCoord) { ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate( R.layout.chooser_grid_preview_text, parent, false); - final ViewGroup actionRow = - (ViewGroup) contentPreviewLayout.findViewById( - com.android.internal.R.id.chooser_action_row); - final int iconMargin = resources.getDimensionPixelSize(R.dimen.resolver_icon_margin); - addActionButton(actionRow, buttonFactory.createCopyButton(), iconMargin); - addActionButton(actionRow, buttonFactory.createNearbyButton(), iconMargin); + final ActionRow actionRow = + contentPreviewLayout.findViewById(com.android.internal.R.id.chooser_action_row); + if (actionRow != null) { + actionRow.setActions(actions); + } CharSequence sharingText = targetIntent.getCharSequenceExtra(Intent.EXTRA_TEXT); if (sharingText == null) { @@ -296,11 +295,20 @@ public final class ChooserContentPreviewUi { return contentPreviewLayout; } + private static List<ActionRow.Action> createTextPreviewActions(ActionFactory actionFactory) { + ArrayList<ActionRow.Action> actions = new ArrayList<>(2); + actions.add(actionFactory.createCopyButton()); + ActionRow.Action nearbyAction = actionFactory.createNearbyButton(); + if (nearbyAction != null) { + actions.add(nearbyAction); + } + return actions; + } + private static ViewGroup displayImageContentPreview( Intent targetIntent, - Resources resources, LayoutInflater layoutInflater, - ActionButtonFactory buttonFactory, + List<ActionRow.Action> actions, ViewGroup parent, ContentPreviewCoordinator previewCoord, ContentResolver contentResolver, @@ -310,13 +318,11 @@ public final class ChooserContentPreviewUi { ViewGroup imagePreview = contentPreviewLayout.findViewById( com.android.internal.R.id.content_preview_image_area); - final ViewGroup actionRow = - (ViewGroup) contentPreviewLayout.findViewById( - com.android.internal.R.id.chooser_action_row); - final int iconMargin = resources.getDimensionPixelSize(R.dimen.resolver_icon_margin); - //TODO: addActionButton(actionRow, buttonFactory.createCopyButton(), iconMargin); - addActionButton(actionRow, buttonFactory.createNearbyButton(), iconMargin); - addActionButton(actionRow, buttonFactory.createEditButton(), iconMargin); + final ActionRow actionRow = + contentPreviewLayout.findViewById(com.android.internal.R.id.chooser_action_row); + if (actionRow != null) { + actionRow.setActions(actions); + } String action = targetIntent.getAction(); if (Intent.ACTION_SEND.equals(action)) { @@ -375,24 +381,37 @@ public final class ChooserContentPreviewUi { return contentPreviewLayout; } + private static List<ActionRow.Action> createImagePreviewActions( + ActionFactory buttonFactory) { + ArrayList<ActionRow.Action> actions = new ArrayList<>(2); + //TODO: add copy action; + ActionRow.Action action = buttonFactory.createNearbyButton(); + if (action != null) { + actions.add(action); + } + action = buttonFactory.createEditButton(); + if (action != null) { + actions.add(action); + } + return actions; + } + private static ViewGroup displayFileContentPreview( Intent targetIntent, Resources resources, LayoutInflater layoutInflater, - ActionButtonFactory buttonFactory, + List<ActionRow.Action> actions, ViewGroup parent, ContentPreviewCoordinator previewCoord, ContentResolver contentResolver) { ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate( R.layout.chooser_grid_preview_file, parent, false); - final ViewGroup actionRow = - (ViewGroup) contentPreviewLayout.findViewById( - com.android.internal.R.id.chooser_action_row); - final int iconMargin = resources.getDimensionPixelSize(R.dimen.resolver_icon_margin); - //TODO(b/120417119): - // addActionButton(actionRow, buttonFactory.createCopyButton(), iconMargin); - addActionButton(actionRow, buttonFactory.createNearbyButton(), iconMargin); + final ActionRow actionRow = + contentPreviewLayout.findViewById(com.android.internal.R.id.chooser_action_row); + if (actionRow != null) { + actionRow.setActions(actions); + } String action = targetIntent.getAction(); if (Intent.ACTION_SEND.equals(action)) { @@ -438,6 +457,17 @@ public final class ChooserContentPreviewUi { return contentPreviewLayout; } + private static List<ActionRow.Action> createFilePreviewActions(ActionFactory actionFactory) { + List<ActionRow.Action> actions = new ArrayList<>(1); + //TODO(b/120417119): + // add action buttonFactory.createCopyButton() + ActionRow.Action action = actionFactory.createNearbyButton(); + if (action != null) { + actions.add(action); + } + return actions; + } + private static void logContentPreviewWarning(Uri uri) { // The ContentResolver already logs the exception. Log something more informative. Log.w(TAG, "Could not load (" + uri.toString() + ") thumbnail/name for preview. If " @@ -475,19 +505,6 @@ public final class ChooserContentPreviewUi { } } - private static void addActionButton(ViewGroup parent, Button b, int iconMargin) { - if (b == null) { - return; - } - final ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams( - LayoutParams.WRAP_CONTENT, - LayoutParams.WRAP_CONTENT - ); - final int gap = iconMargin / 2; - lp.setMarginsRelative(gap, 0, gap, 0); - parent.addView(b, lp); - } - private static FileInfo extractFileInfo(Uri uri, ContentResolver resolver) { String fileName = null; boolean hasThumbnail = false; diff --git a/java/src/com/android/intentresolver/widget/ActionRow.kt b/java/src/com/android/intentresolver/widget/ActionRow.kt new file mode 100644 index 00000000..1be48f34 --- /dev/null +++ b/java/src/com/android/intentresolver/widget/ActionRow.kt @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.intentresolver.widget + +import android.annotation.LayoutRes +import android.content.Context +import android.content.res.Resources.ID_NULL +import android.graphics.drawable.Drawable +import android.os.Parcelable +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.Button +import android.widget.LinearLayout +import com.android.intentresolver.R + +// TODO: extract an interface out of the class, use it in layout hierarchy an have a layout inflater +// to instantiate the right view based on a flag value. +class ActionRow : LinearLayout { + constructor(context: Context) : this(context, null) + constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) + constructor( + context: Context, attrs: AttributeSet?, defStyleAttr: Int + ) : this(context, attrs, defStyleAttr, 0) + + constructor( + context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int + ) : super(context, attrs, defStyleAttr, defStyleRes) { + orientation = HORIZONTAL + } + + @LayoutRes + private val itemLayout = R.layout.chooser_action_button + private val itemMargin = + context.resources.getDimensionPixelSize(R.dimen.resolver_icon_margin) / 2 + private var actions: List<Action> = emptyList() + + override fun onRestoreInstanceState(state: Parcelable?) { + super.onRestoreInstanceState(state) + setActions(actions) + } + + fun setActions(actions: List<Action>) { + removeAllViews() + this.actions = ArrayList(actions) + for (action in actions) { + addAction(action) + } + } + + private fun addAction(action: Action) { + val b = LayoutInflater.from(context).inflate(itemLayout, null) as Button + if (action.icon != null) { + val size = resources + .getDimensionPixelSize(R.dimen.chooser_action_button_icon_size) + action.icon.setBounds(0, 0, size, size) + b.setCompoundDrawablesRelative(action.icon, null, null, null) + } + b.text = action.label ?: "" + b.setOnClickListener { + action.onClicked.run() + } + b.id = action.id + addView(b) + } + + override fun generateDefaultLayoutParams(): LayoutParams = + super.generateDefaultLayoutParams().apply { + setMarginsRelative(itemMargin, 0, itemMargin, 0) + } + + class Action @JvmOverloads constructor( + // TODO: apparently, IDs set to this field are used in unit tests only; evaluate whether we + // get rid of them + val id: Int = ID_NULL, + val label: CharSequence?, + val icon: Drawable?, + val onClicked: Runnable, + ) +} |