From 563d7b9d17c913198554aad2d37e60c1d3ffc196 Mon Sep 17 00:00:00 2001 From: Matt Pietal Date: Thu, 25 Jun 2020 15:56:03 -0400 Subject: Sharesheet - Cache loading of icons For sharesheet, assume that the reordering of elements will make the last assigned ViewHolder invalid for async icon loading. If we already have an async task for the particular ResolveInfo, update the ViewHolder target when it's complete. Fixes: 158172791 Test: atest ChooserActivityTest ResolverActivityTest Change-Id: I0ea9f443512f91e8fa4c5d6b72a35e9231e69e51 --- .../android/internal/app/ChooserListAdapter.java | 38 ++++++++- .../android/internal/app/ResolverListAdapter.java | 93 ++++++++++++---------- 2 files changed, 87 insertions(+), 44 deletions(-) diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java index 5efd46c4c64a..c4e0536c975a 100644 --- a/core/java/com/android/internal/app/ChooserListAdapter.java +++ b/core/java/com/android/internal/app/ChooserListAdapter.java @@ -95,6 +95,7 @@ public class ChooserListAdapter extends ResolverListAdapter { mSelectableTargetInfoCommunicator; private int mNumShortcutResults = 0; + private Map mIconLoaders = new HashMap<>(); // Reserve spots for incoming direct share targets by adding placeholders private ChooserTargetInfo @@ -239,11 +240,42 @@ public class ChooserListAdapter extends ResolverListAdapter { @Override protected void onBindView(View view, TargetInfo info, int position) { - super.onBindView(view, info, position); - if (info == null) return; + final ViewHolder holder = (ViewHolder) view.getTag(); + if (info == null) { + holder.icon.setImageDrawable( + mContext.getDrawable(R.drawable.resolver_icon_placeholder)); + return; + } + + if (!(info instanceof DisplayResolveInfo)) { + holder.bindLabel(info.getDisplayLabel(), info.getExtendedInfo(), alwaysShowSubLabel()); + holder.bindIcon(info); + + if (info instanceof SelectableTargetInfo) { + // direct share targets should append the application name for a better readout + DisplayResolveInfo rInfo = ((SelectableTargetInfo) info).getDisplayResolveInfo(); + CharSequence appName = rInfo != null ? rInfo.getDisplayLabel() : ""; + CharSequence extendedInfo = info.getExtendedInfo(); + String contentDescription = String.join(" ", info.getDisplayLabel(), + extendedInfo != null ? extendedInfo : "", appName); + holder.updateContentDescription(contentDescription); + } + } else { + DisplayResolveInfo dri = (DisplayResolveInfo) info; + holder.bindLabel(dri.getDisplayLabel(), dri.getExtendedInfo(), alwaysShowSubLabel()); + LoadIconTask task = mIconLoaders.get(dri); + if (task == null) { + task = new LoadIconTask(dri, holder); + mIconLoaders.put(dri, task); + task.execute(); + } else { + // The holder was potentially changed as the underlying items were + // reshuffled, so reset the target holder + task.setViewHolder(holder); + } + } // If target is loading, show a special placeholder shape in the label, make unclickable - final ViewHolder holder = (ViewHolder) view.getTag(); if (info instanceof ChooserActivity.PlaceHolderTargetInfo) { final int maxWidth = mContext.getResources().getDimensionPixelSize( R.dimen.chooser_direct_share_label_placeholder_max_width); diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java index 094fb1e2f23c..eef722e32bdc 100644 --- a/core/java/com/android/internal/app/ResolverListAdapter.java +++ b/core/java/com/android/internal/app/ResolverListAdapter.java @@ -54,7 +54,6 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ResolverActivity.ResolvedComponentInfo; import com.android.internal.app.chooser.DisplayResolveInfo; -import com.android.internal.app.chooser.SelectableTargetInfo; import com.android.internal.app.chooser.TargetInfo; import java.util.ArrayList; @@ -68,7 +67,7 @@ public class ResolverListAdapter extends BaseAdapter { private final List mBaseResolveList; private final PackageManager mPm; protected final Context mContext; - private final ColorMatrixColorFilter mSuspendedMatrixColorFilter; + private static ColorMatrixColorFilter sSuspendedMatrixColorFilter; private final int mIconDpi; protected ResolveInfo mLastChosen; private DisplayResolveInfo mOtherProfile; @@ -103,7 +102,6 @@ public class ResolverListAdapter extends BaseAdapter { mDisplayList = new ArrayList<>(); mFilterLastUsed = filterLastUsed; mResolverListController = resolverListController; - mSuspendedMatrixColorFilter = createSuspendedColorMatrix(); mResolverListCommunicator = resolverListCommunicator; mIsAudioCaptureDevice = isAudioCaptureDevice; final ActivityManager am = (ActivityManager) mContext.getSystemService(ACTIVITY_SERVICE); @@ -541,28 +539,13 @@ public class ResolverListAdapter extends BaseAdapter { getLoadLabelTask((DisplayResolveInfo) info, holder).execute(); } else { holder.bindLabel(info.getDisplayLabel(), info.getExtendedInfo(), alwaysShowSubLabel()); - if (info instanceof SelectableTargetInfo) { - // direct share targets should append the application name for a better readout - DisplayResolveInfo rInfo = ((SelectableTargetInfo) info).getDisplayResolveInfo(); - CharSequence appName = rInfo != null ? rInfo.getDisplayLabel() : ""; - CharSequence extendedInfo = info.getExtendedInfo(); - String contentDescription = String.join(" ", info.getDisplayLabel(), - extendedInfo != null ? extendedInfo : "", appName); - holder.updateContentDescription(contentDescription); - } - } - - if (info.isSuspended()) { - holder.icon.setColorFilter(mSuspendedMatrixColorFilter); - } else { - holder.icon.setColorFilter(null); } if (info instanceof DisplayResolveInfo && !((DisplayResolveInfo) info).hasDisplayIcon()) { - new ResolverListAdapter.LoadIconTask((DisplayResolveInfo) info, holder.icon).execute(); + new LoadIconTask((DisplayResolveInfo) info, holder).execute(); } else { - holder.icon.setImageDrawable(info.getDisplayIcon(mContext)); + holder.bindIcon(info); } } @@ -580,23 +563,27 @@ public class ResolverListAdapter extends BaseAdapter { } } - private ColorMatrixColorFilter createSuspendedColorMatrix() { - int grayValue = 127; - float scale = 0.5f; // half bright + private static ColorMatrixColorFilter getSuspendedColorMatrix() { + if (sSuspendedMatrixColorFilter == null) { + + int grayValue = 127; + float scale = 0.5f; // half bright - ColorMatrix tempBrightnessMatrix = new ColorMatrix(); - float[] mat = tempBrightnessMatrix.getArray(); - mat[0] = scale; - mat[6] = scale; - mat[12] = scale; - mat[4] = grayValue; - mat[9] = grayValue; - mat[14] = grayValue; + ColorMatrix tempBrightnessMatrix = new ColorMatrix(); + float[] mat = tempBrightnessMatrix.getArray(); + mat[0] = scale; + mat[6] = scale; + mat[12] = scale; + mat[4] = grayValue; + mat[9] = grayValue; + mat[14] = grayValue; - ColorMatrix matrix = new ColorMatrix(); - matrix.setSaturation(0.0f); - matrix.preConcat(tempBrightnessMatrix); - return new ColorMatrixColorFilter(matrix); + ColorMatrix matrix = new ColorMatrix(); + matrix.setSaturation(0.0f); + matrix.preConcat(tempBrightnessMatrix); + sSuspendedMatrixColorFilter = new ColorMatrixColorFilter(matrix); + } + return sSuspendedMatrixColorFilter; } ActivityInfoPresentationGetter makePresentationGetter(ActivityInfo ai) { @@ -615,7 +602,17 @@ public class ResolverListAdapter extends BaseAdapter { void loadFilteredItemIconTaskAsync(@NonNull ImageView iconView) { final DisplayResolveInfo iconInfo = getFilteredItem(); if (iconView != null && iconInfo != null) { - new LoadIconTask(iconInfo, iconView).execute(); + new AsyncTask() { + @Override + protected Drawable doInBackground(Void... params) { + return loadIconForResolveInfo(iconInfo.getResolveInfo()); + } + + @Override + protected void onPostExecute(Drawable d) { + iconView.setImageDrawable(d); + } + }.execute(); } } @@ -708,6 +705,15 @@ public class ResolverListAdapter extends BaseAdapter { public void updateContentDescription(String description) { itemView.setContentDescription(description); } + + public void bindIcon(TargetInfo info) { + icon.setImageDrawable(info.getDisplayIcon(itemView.getContext())); + if (info.isSuspended()) { + icon.setColorFilter(getSuspendedColorMatrix()); + } else { + icon.setColorFilter(null); + } + } } protected class LoadLabelTask extends AsyncTask { @@ -761,14 +767,14 @@ public class ResolverListAdapter extends BaseAdapter { } class LoadIconTask extends AsyncTask { - protected final com.android.internal.app.chooser.DisplayResolveInfo mDisplayResolveInfo; + protected final DisplayResolveInfo mDisplayResolveInfo; private final ResolveInfo mResolveInfo; - private final ImageView mTargetView; + private ViewHolder mHolder; - LoadIconTask(DisplayResolveInfo dri, ImageView target) { + LoadIconTask(DisplayResolveInfo dri, ViewHolder holder) { mDisplayResolveInfo = dri; mResolveInfo = dri.getResolveInfo(); - mTargetView = target; + mHolder = holder; } @Override @@ -782,9 +788,14 @@ public class ResolverListAdapter extends BaseAdapter { mResolverListCommunicator.updateProfileViewButton(); } else { mDisplayResolveInfo.setDisplayIcon(d); - mTargetView.setImageDrawable(d); + mHolder.bindIcon(mDisplayResolveInfo); } } + + public void setViewHolder(ViewHolder holder) { + mHolder = holder; + mHolder.bindIcon(mDisplayResolveInfo); + } } /** -- cgit v1.2.3-59-g8ed1b