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:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user