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
This commit is contained in:
Matt Pietal
2020-06-25 15:56:03 -04:00
parent 827c121e78
commit 563d7b9d17
2 changed files with 87 additions and 44 deletions

View File

@@ -95,6 +95,7 @@ public class ChooserListAdapter extends ResolverListAdapter {
mSelectableTargetInfoCommunicator;
private int mNumShortcutResults = 0;
private Map<DisplayResolveInfo, LoadIconTask> 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);

View File

@@ -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<ResolveInfo> 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) {
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;
int grayValue = 127;
float scale = 0.5f; // half bright
ColorMatrix matrix = new ColorMatrix();
matrix.setSaturation(0.0f);
matrix.preConcat(tempBrightnessMatrix);
return new ColorMatrixColorFilter(matrix);
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);
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<Void, Void, Drawable>() {
@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<Void, Void, CharSequence[]> {
@@ -761,14 +767,14 @@ public class ResolverListAdapter extends BaseAdapter {
}
class LoadIconTask extends AsyncTask<Void, Void, Drawable> {
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);
}
}
/**