summaryrefslogtreecommitdiff
path: root/java/src/com
diff options
context:
space:
mode:
author Andrey Epin <ayepin@google.com> 2023-12-11 06:57:52 -0800
committer Andrey Epin <ayepin@google.com> 2023-12-14 10:09:07 -0800
commitc5657c5eae0c049c99753a18ad38acd0f15a6f9c (patch)
tree8c6945c172c2711790e7ebefb2783d07c7448b68 /java/src/com
parent3007d9f481e92ed57ca9e3783719b3d84797ef2c (diff)
Use a bespoke label view
Create a bespoke label view that centers text more precisely in the presense of a end-side badge. The view is used under a flag. One unflagged trivial refactoring was made: some of the ResolverListAdapter$ViewHolder's methods that were only used inside ChooserListAdapter were moved there for a better cohesion; the reset method is split similarly. Bug: 302188527 Test: The view is tested in both Chooser and a stand-alone test app Flag: ACONFIG com.android.intentresolver.bespoke_label_view DEVELOPMENT Change-Id: Iec871afcdc634f2ce50a4b31a8cc34b88ebb496c
Diffstat (limited to 'java/src/com')
-rw-r--r--java/src/com/android/intentresolver/ChooserActivity.java3
-rw-r--r--java/src/com/android/intentresolver/ChooserListAdapter.java73
-rw-r--r--java/src/com/android/intentresolver/ResolverListAdapter.java23
-rw-r--r--java/src/com/android/intentresolver/v2/ChooserActivity.java3
-rw-r--r--java/src/com/android/intentresolver/widget/BadgeTextView.kt88
5 files changed, 153 insertions, 37 deletions
diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java
index 9000ab3a..fc011aef 100644
--- a/java/src/com/android/intentresolver/ChooserActivity.java
+++ b/java/src/com/android/intentresolver/ChooserActivity.java
@@ -1252,7 +1252,8 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
maxTargetsPerRow,
initialIntentsUserSpace,
targetDataLoader,
- null);
+ null,
+ mFeatureFlags);
}
@Override
diff --git a/java/src/com/android/intentresolver/ChooserListAdapter.java b/java/src/com/android/intentresolver/ChooserListAdapter.java
index 876ad5c3..94a89722 100644
--- a/java/src/com/android/intentresolver/ChooserListAdapter.java
+++ b/java/src/com/android/intentresolver/ChooserListAdapter.java
@@ -54,6 +54,7 @@ import com.android.intentresolver.chooser.SelectableTargetInfo;
import com.android.intentresolver.chooser.TargetInfo;
import com.android.intentresolver.icons.TargetDataLoader;
import com.android.intentresolver.logging.EventLog;
+import com.android.intentresolver.widget.BadgeTextView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
@@ -109,6 +110,7 @@ public class ChooserListAdapter extends ResolverListAdapter {
// Reserve spots for incoming direct share targets by adding placeholders
private final TargetInfo mPlaceHolderTargetInfo;
private final TargetDataLoader mTargetDataLoader;
+ private final boolean mUseBadgeTextViewForLabels;
private final List<TargetInfo> mServiceTargets = new ArrayList<>();
private final List<DisplayResolveInfo> mCallerTargets = new ArrayList<>();
@@ -166,7 +168,8 @@ public class ChooserListAdapter extends ResolverListAdapter {
int maxRankedTargets,
UserHandle initialIntentsUserSpace,
TargetDataLoader targetDataLoader,
- @Nullable PackageChangeCallback packageChangeCallback) {
+ @Nullable PackageChangeCallback packageChangeCallback,
+ FeatureFlags featureFlags) {
this(
context,
payloadIntents,
@@ -185,7 +188,8 @@ public class ChooserListAdapter extends ResolverListAdapter {
targetDataLoader,
packageChangeCallback,
AsyncTask.SERIAL_EXECUTOR,
- context.getMainExecutor());
+ context.getMainExecutor(),
+ featureFlags);
}
@VisibleForTesting
@@ -207,7 +211,8 @@ public class ChooserListAdapter extends ResolverListAdapter {
TargetDataLoader targetDataLoader,
@Nullable PackageChangeCallback packageChangeCallback,
Executor bgExecutor,
- Executor mainExecutor) {
+ Executor mainExecutor,
+ FeatureFlags featureFlags) {
// Don't send the initial intents through the shared ResolverActivity path,
// we want to separate them into a different section.
super(
@@ -231,6 +236,7 @@ public class ChooserListAdapter extends ResolverListAdapter {
mPlaceHolderTargetInfo = NotSelectableTargetInfo.newPlaceHolderTargetInfo(context);
mTargetDataLoader = targetDataLoader;
mPackageChangeCallback = packageChangeCallback;
+ mUseBadgeTextViewForLabels = featureFlags.bespokeLabelView();
createPlaceHolders();
mEventLog = eventLog;
mShortcutSelectionLogic = new ShortcutSelectionLogic(
@@ -332,7 +338,12 @@ public class ChooserListAdapter extends ResolverListAdapter {
@Override
View onCreateView(ViewGroup parent) {
- return mInflater.inflate(R.layout.resolve_grid_item, parent, false);
+ return mInflater.inflate(
+ mUseBadgeTextViewForLabels
+ ? R.layout.chooser_grid_item
+ : R.layout.resolve_grid_item,
+ parent,
+ false);
}
@VisibleForTesting
@@ -340,7 +351,7 @@ public class ChooserListAdapter extends ResolverListAdapter {
public void onBindView(View view, TargetInfo info, int position) {
final ViewHolder holder = (ViewHolder) view.getTag();
- holder.reset();
+ resetViewHolder(holder);
// Always remove the spacing listener, attach as needed to direct share targets below.
holder.text.removeOnLayoutChangeListener(mPinTextSpacingListener);
@@ -377,16 +388,18 @@ public class ChooserListAdapter extends ResolverListAdapter {
contentDescription,
mContext.getResources().getString(R.string.pinned));
}
- holder.updateContentDescription(contentDescription);
+ updateContentDescription(holder, contentDescription);
if (!info.hasDisplayIcon()) {
loadDirectShareIcon((SelectableTargetInfo) info);
}
} else if (info.isDisplayResolveInfo()) {
if (info.isPinned()) {
- holder.updateContentDescription(String.join(
- ". ",
- info.getDisplayLabel(),
- mContext.getResources().getString(R.string.pinned)));
+ updateContentDescription(
+ holder,
+ String.join(
+ ". ",
+ info.getDisplayLabel(),
+ mContext.getResources().getString(R.string.pinned)));
}
DisplayResolveInfo dri = (DisplayResolveInfo) info;
if (!dri.hasDisplayIcon()) {
@@ -398,22 +411,56 @@ public class ChooserListAdapter extends ResolverListAdapter {
}
if (info.isPlaceHolderTargetInfo()) {
- holder.bindPlaceholder();
+ bindPlaceholder(holder);
}
if (info.isMultiDisplayResolveInfo()) {
// If the target is grouped show an indicator
- holder.bindGroupIndicator(
+ bindGroupIndicator(
+ holder,
mContext.getDrawable(R.drawable.chooser_group_background));
} else if (info.isPinned() && (getPositionTargetType(position) == TARGET_STANDARD
|| getPositionTargetType(position) == TARGET_SERVICE)) {
// If the appShare or directShare target is pinned and in the suggested row show a
// pinned indicator
- holder.bindPinnedIndicator(mContext.getDrawable(R.drawable.chooser_pinned_background));
+ bindPinnedIndicator(holder, mContext.getDrawable(R.drawable.chooser_pinned_background));
holder.text.addOnLayoutChangeListener(mPinTextSpacingListener);
}
}
+ private void resetViewHolder(ViewHolder holder) {
+ holder.reset();
+ holder.itemView.setBackground(holder.defaultItemViewBackground);
+
+ if (mUseBadgeTextViewForLabels) {
+ ((BadgeTextView) holder.text).setBadgeDrawable(null);
+ }
+ holder.text.setBackground(null);
+ holder.text.setPaddingRelative(0, 0, 0, 0);
+ }
+
+ private void updateContentDescription(ViewHolder holder, String description) {
+ holder.itemView.setContentDescription(description);
+ }
+
+ private void bindPlaceholder(ViewHolder holder) {
+ holder.itemView.setBackground(null);
+ }
+
+ private void bindGroupIndicator(ViewHolder holder, Drawable indicator) {
+ if (mUseBadgeTextViewForLabels) {
+ ((BadgeTextView) holder.text).setBadgeDrawable(indicator);
+ } else {
+ holder.text.setPaddingRelative(0, 0, /*end = */indicator.getIntrinsicWidth(), 0);
+ holder.text.setBackground(indicator);
+ }
+ }
+
+ private void bindPinnedIndicator(ViewHolder holder, Drawable indicator) {
+ holder.text.setPaddingRelative(/*start = */indicator.getIntrinsicWidth(), 0, 0, 0);
+ holder.text.setBackground(indicator);
+ }
+
private void loadDirectShareIcon(SelectableTargetInfo info) {
if (mRequestedIcons.add(info)) {
mTargetDataLoader.loadDirectShareIcon(
diff --git a/java/src/com/android/intentresolver/ResolverListAdapter.java b/java/src/com/android/intentresolver/ResolverListAdapter.java
index 564d8d19..262d180a 100644
--- a/java/src/com/android/intentresolver/ResolverListAdapter.java
+++ b/java/src/com/android/intentresolver/ResolverListAdapter.java
@@ -25,7 +25,6 @@ import android.content.pm.ResolveInfo;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.drawable.Drawable;
-import android.net.Uri;
import android.os.AsyncTask;
import android.os.RemoteException;
import android.os.Trace;
@@ -930,7 +929,7 @@ public class ResolverListAdapter extends BaseAdapter {
@VisibleForTesting
public static class ViewHolder {
public View itemView;
- public Drawable defaultItemViewBackground;
+ public final Drawable defaultItemViewBackground;
public TextView text;
public TextView text2;
@@ -940,8 +939,6 @@ public class ResolverListAdapter extends BaseAdapter {
text.setText("");
text.setMaxLines(2);
text.setMaxWidth(Integer.MAX_VALUE);
- text.setBackground(null);
- text.setPaddingRelative(0, 0, 0, 0);
text2.setVisibility(View.GONE);
text2.setText("");
@@ -982,10 +979,6 @@ public class ResolverListAdapter extends BaseAdapter {
itemView.setContentDescription(null);
}
- public void updateContentDescription(String description) {
- itemView.setContentDescription(description);
- }
-
/**
* Bind view holder to a TargetInfo.
*/
@@ -998,19 +991,5 @@ public class ResolverListAdapter extends BaseAdapter {
icon.setColorFilter(null);
}
}
-
- public void bindPlaceholder() {
- itemView.setBackground(null);
- }
-
- public void bindGroupIndicator(Drawable indicator) {
- text.setPaddingRelative(0, 0, /*end = */indicator.getIntrinsicWidth(), 0);
- text.setBackground(indicator);
- }
-
- public void bindPinnedIndicator(Drawable indicator) {
- text.setPaddingRelative(/*start = */indicator.getIntrinsicWidth(), 0, 0, 0);
- text.setBackground(indicator);
- }
}
}
diff --git a/java/src/com/android/intentresolver/v2/ChooserActivity.java b/java/src/com/android/intentresolver/v2/ChooserActivity.java
index 70812642..d3c97075 100644
--- a/java/src/com/android/intentresolver/v2/ChooserActivity.java
+++ b/java/src/com/android/intentresolver/v2/ChooserActivity.java
@@ -1263,7 +1263,8 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
if (record != null && record.shortcutLoader != null) {
record.shortcutLoader.reset();
}
- });
+ },
+ mFeatureFlags);
}
@Override
diff --git a/java/src/com/android/intentresolver/widget/BadgeTextView.kt b/java/src/com/android/intentresolver/widget/BadgeTextView.kt
new file mode 100644
index 00000000..b6cadd86
--- /dev/null
+++ b/java/src/com/android/intentresolver/widget/BadgeTextView.kt
@@ -0,0 +1,88 @@
+package com.android.intentresolver.widget
+
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.util.AttributeSet
+import android.view.Gravity
+import android.widget.TextView
+
+/**
+ * A TextView that supports a badge at the end of the text. If the text, when centered in the view,
+ * leaves enough room for the badge, the badge is just displayed at the end of the view. Otherwise,
+ * the necessary amount of space for the badge is reserved and the text gets centered in the
+ * remaining free space.
+ */
+class BadgeTextView : TextView {
+ 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) {
+ super.setGravity(Gravity.CENTER)
+ defaultPaddingLeft = paddingLeft
+ defaultPaddingRight = paddingRight
+ }
+
+ private var defaultPaddingLeft = 0
+ private var defaultPaddingRight = 0
+
+ override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) {
+ super.setPadding(left, top, right, bottom)
+ defaultPaddingLeft = paddingLeft
+ defaultPaddingRight = paddingRight
+ }
+
+ override fun setPaddingRelative(start: Int, top: Int, end: Int, bottom: Int) {
+ super.setPaddingRelative(start, top, end, bottom)
+ defaultPaddingLeft = paddingLeft
+ defaultPaddingRight = paddingRight
+ }
+
+ /** Sets end-sided badge. */
+ var badgeDrawable: Drawable? = null
+ set(value) {
+ if (field !== value) {
+ field = value
+ super.setBackground(value)
+ }
+ }
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ super.setPadding(defaultPaddingLeft, paddingTop, defaultPaddingRight, paddingBottom)
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+ val badge = badgeDrawable ?: return
+ if (badge.intrinsicWidth <= paddingEnd) return
+ var maxLineWidth = 0f
+ for (i in 0 until layout.lineCount) {
+ maxLineWidth = maxOf(maxLineWidth, layout.getLineWidth(i))
+ }
+ val sideSpace = (measuredWidth - maxLineWidth) / 2
+ if (sideSpace < badge.intrinsicWidth) {
+ super.setPaddingRelative(
+ paddingStart,
+ paddingTop,
+ paddingEnd + badge.intrinsicWidth - sideSpace.toInt(),
+ paddingBottom
+ )
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+ }
+ }
+
+ override fun setBackground(background: Drawable?) {
+ badgeDrawable = null
+ super.setBackground(background)
+ }
+
+ override fun setGravity(gravity: Int): Unit = error("Not supported")
+}