Loading core/java/android/service/chooser/flags.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,16 @@ flag { bug: "263474465" } flag { name: "notify_single_item_change_on_icon_load" namespace: "intentresolver" description: "ChooserGridAdapter to notify specific items change when the target icon is loaded (instead of all-item change)." bug: "298193161" metadata { purpose: PURPOSE_BUGFIX } } flag { name: "fix_resolver_memory_leak" is_exported: true Loading core/java/com/android/internal/app/ChooserActivity.java +76 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CROSS_PROFILE_BLOCKED_TITLE; import static android.content.ContentProvider.getUriWithoutUserId; import static android.content.ContentProvider.getUserIdFromUri; import static android.service.chooser.Flags.notifySingleItemChangeOnIconLoad; import static android.stats.devicepolicy.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL; import static android.stats.devicepolicy.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK; Loading Loading @@ -163,9 +164,11 @@ import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Supplier; import java.util.stream.Collectors; Loading Loading @@ -3212,6 +3215,8 @@ public class ChooserActivity extends ResolverActivity implements private static final int NUM_EXPANSIONS_TO_HIDE_AZ_LABEL = 20; private final Set<ViewHolderBase> mBoundViewHolders = new HashSet<>(); ChooserGridAdapter(ChooserListAdapter wrappedAdapter) { super(); mChooserListAdapter = wrappedAdapter; Loading @@ -3232,6 +3237,31 @@ public class ChooserActivity extends ResolverActivity implements notifyDataSetChanged(); } }); if (notifySingleItemChangeOnIconLoad()) { wrappedAdapter.setOnIconLoadedListener(this::onTargetIconLoaded); } } private void onTargetIconLoaded(DisplayResolveInfo info) { for (ViewHolderBase holder : mBoundViewHolders) { switch (holder.getViewType()) { case VIEW_TYPE_NORMAL: TargetInfo itemInfo = mChooserListAdapter.getItem( ((ItemViewHolder) holder).mListPosition); if (info == itemInfo) { notifyItemChanged(holder.getAdapterPosition()); } break; case VIEW_TYPE_CALLER_AND_RANK: ItemGroupViewHolder groupHolder = (ItemGroupViewHolder) holder; if (suggestedAppsGroupContainsTarget(groupHolder, info)) { notifyItemChanged(holder.getAdapterPosition()); } break; } } } public void setFooterHeight(int height) { Loading Loading @@ -3382,6 +3412,9 @@ public class ChooserActivity extends ResolverActivity implements @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (notifySingleItemChangeOnIconLoad()) { mBoundViewHolders.add((ViewHolderBase) holder); } int viewType = ((ViewHolderBase) holder).getViewType(); switch (viewType) { case VIEW_TYPE_DIRECT_SHARE: Loading @@ -3395,6 +3428,22 @@ public class ChooserActivity extends ResolverActivity implements } } @Override public void onViewRecycled(RecyclerView.ViewHolder holder) { if (notifySingleItemChangeOnIconLoad()) { mBoundViewHolders.remove((ViewHolderBase) holder); } super.onViewRecycled(holder); } @Override public boolean onFailedToRecycleView(RecyclerView.ViewHolder holder) { if (notifySingleItemChangeOnIconLoad()) { mBoundViewHolders.remove((ViewHolderBase) holder); } return super.onFailedToRecycleView(holder); } @Override public int getItemViewType(int position) { int count; Loading Loading @@ -3604,6 +3653,33 @@ public class ChooserActivity extends ResolverActivity implements } } /** * Checks whether the suggested apps group, {@code holder}, contains the target, * {@code info}. */ private boolean suggestedAppsGroupContainsTarget( ItemGroupViewHolder holder, DisplayResolveInfo info) { int position = holder.getAdapterPosition(); int start = getListPosition(position); int startType = getRowType(start); int columnCount = holder.getColumnCount(); int end = start + columnCount - 1; while (getRowType(end) != startType && end >= start) { end--; } for (int i = 0; i < columnCount; i++) { if (start + i <= end) { if (mChooserListAdapter.getItem(holder.getItemIndex(i)) == info) { return true; } } } return false; } int getListPosition(int position) { position -= getSystemRowCount() + getProfileRowCount(); Loading core/java/com/android/internal/app/ChooserListAdapter.java +20 −0 Original line number Diff line number Diff line Loading @@ -16,9 +16,12 @@ package com.android.internal.app; import static android.service.chooser.Flags.notifySingleItemChangeOnIconLoad; import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE; import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER; import android.annotation.Nullable; import android.app.prediction.AppPredictor; import android.content.ComponentName; import android.content.Context; Loading Loading @@ -56,6 +59,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Consumer; public class ChooserListAdapter extends ResolverListAdapter { private static final String TAG = "ChooserListAdapter"; Loading Loading @@ -108,6 +112,9 @@ public class ChooserListAdapter extends ResolverListAdapter { // Represents the UserSpace in which the Initial Intents should be resolved. private final UserHandle mInitialIntentsUserSpace; @Nullable private Consumer<DisplayResolveInfo> mOnIconLoadedListener; // For pinned direct share labels, if the text spans multiple lines, the TextView will consume // the full width, even if the characters actually take up less than that. Measure the actual // line widths and constrain the View's width based upon that so that the pin doesn't end up Loading Loading @@ -218,6 +225,10 @@ public class ChooserListAdapter extends ResolverListAdapter { true); } public void setOnIconLoadedListener(Consumer<DisplayResolveInfo> onIconLoadedListener) { mOnIconLoadedListener = onIconLoadedListener; } AppPredictor getAppPredictor() { return mAppPredictor; } Loading Loading @@ -329,6 +340,15 @@ public class ChooserListAdapter extends ResolverListAdapter { } } @Override protected void onIconLoaded(DisplayResolveInfo info) { if (notifySingleItemChangeOnIconLoad() && mOnIconLoadedListener != null) { mOnIconLoadedListener.accept(info); } else { notifyDataSetChanged(); } } private void loadDirectShareIcon(SelectableTargetInfo info) { LoadDirectShareIconTask task = (LoadDirectShareIconTask) mIconLoaders.get(info); if (task == null) { Loading core/java/com/android/internal/app/ResolverListAdapter.java +5 −1 Original line number Diff line number Diff line Loading @@ -680,6 +680,10 @@ public class ResolverListAdapter extends BaseAdapter { } } protected void onIconLoaded(DisplayResolveInfo info) { notifyDataSetChanged(); } private void loadLabel(DisplayResolveInfo info) { LoadLabelTask task = mLabelLoaders.get(info); if (task == null) { Loading Loading @@ -1004,7 +1008,7 @@ public class ResolverListAdapter extends BaseAdapter { mResolverListCommunicator.updateProfileViewButton(); } else if (!mDisplayResolveInfo.hasDisplayIcon()) { mDisplayResolveInfo.setDisplayIcon(d); notifyDataSetChanged(); onIconLoaded(mDisplayResolveInfo); } } } Loading Loading
core/java/android/service/chooser/flags.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,16 @@ flag { bug: "263474465" } flag { name: "notify_single_item_change_on_icon_load" namespace: "intentresolver" description: "ChooserGridAdapter to notify specific items change when the target icon is loaded (instead of all-item change)." bug: "298193161" metadata { purpose: PURPOSE_BUGFIX } } flag { name: "fix_resolver_memory_leak" is_exported: true Loading
core/java/com/android/internal/app/ChooserActivity.java +76 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CROSS_PROFILE_BLOCKED_TITLE; import static android.content.ContentProvider.getUriWithoutUserId; import static android.content.ContentProvider.getUserIdFromUri; import static android.service.chooser.Flags.notifySingleItemChangeOnIconLoad; import static android.stats.devicepolicy.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL; import static android.stats.devicepolicy.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK; Loading Loading @@ -163,9 +164,11 @@ import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Supplier; import java.util.stream.Collectors; Loading Loading @@ -3212,6 +3215,8 @@ public class ChooserActivity extends ResolverActivity implements private static final int NUM_EXPANSIONS_TO_HIDE_AZ_LABEL = 20; private final Set<ViewHolderBase> mBoundViewHolders = new HashSet<>(); ChooserGridAdapter(ChooserListAdapter wrappedAdapter) { super(); mChooserListAdapter = wrappedAdapter; Loading @@ -3232,6 +3237,31 @@ public class ChooserActivity extends ResolverActivity implements notifyDataSetChanged(); } }); if (notifySingleItemChangeOnIconLoad()) { wrappedAdapter.setOnIconLoadedListener(this::onTargetIconLoaded); } } private void onTargetIconLoaded(DisplayResolveInfo info) { for (ViewHolderBase holder : mBoundViewHolders) { switch (holder.getViewType()) { case VIEW_TYPE_NORMAL: TargetInfo itemInfo = mChooserListAdapter.getItem( ((ItemViewHolder) holder).mListPosition); if (info == itemInfo) { notifyItemChanged(holder.getAdapterPosition()); } break; case VIEW_TYPE_CALLER_AND_RANK: ItemGroupViewHolder groupHolder = (ItemGroupViewHolder) holder; if (suggestedAppsGroupContainsTarget(groupHolder, info)) { notifyItemChanged(holder.getAdapterPosition()); } break; } } } public void setFooterHeight(int height) { Loading Loading @@ -3382,6 +3412,9 @@ public class ChooserActivity extends ResolverActivity implements @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (notifySingleItemChangeOnIconLoad()) { mBoundViewHolders.add((ViewHolderBase) holder); } int viewType = ((ViewHolderBase) holder).getViewType(); switch (viewType) { case VIEW_TYPE_DIRECT_SHARE: Loading @@ -3395,6 +3428,22 @@ public class ChooserActivity extends ResolverActivity implements } } @Override public void onViewRecycled(RecyclerView.ViewHolder holder) { if (notifySingleItemChangeOnIconLoad()) { mBoundViewHolders.remove((ViewHolderBase) holder); } super.onViewRecycled(holder); } @Override public boolean onFailedToRecycleView(RecyclerView.ViewHolder holder) { if (notifySingleItemChangeOnIconLoad()) { mBoundViewHolders.remove((ViewHolderBase) holder); } return super.onFailedToRecycleView(holder); } @Override public int getItemViewType(int position) { int count; Loading Loading @@ -3604,6 +3653,33 @@ public class ChooserActivity extends ResolverActivity implements } } /** * Checks whether the suggested apps group, {@code holder}, contains the target, * {@code info}. */ private boolean suggestedAppsGroupContainsTarget( ItemGroupViewHolder holder, DisplayResolveInfo info) { int position = holder.getAdapterPosition(); int start = getListPosition(position); int startType = getRowType(start); int columnCount = holder.getColumnCount(); int end = start + columnCount - 1; while (getRowType(end) != startType && end >= start) { end--; } for (int i = 0; i < columnCount; i++) { if (start + i <= end) { if (mChooserListAdapter.getItem(holder.getItemIndex(i)) == info) { return true; } } } return false; } int getListPosition(int position) { position -= getSystemRowCount() + getProfileRowCount(); Loading
core/java/com/android/internal/app/ChooserListAdapter.java +20 −0 Original line number Diff line number Diff line Loading @@ -16,9 +16,12 @@ package com.android.internal.app; import static android.service.chooser.Flags.notifySingleItemChangeOnIconLoad; import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE; import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER; import android.annotation.Nullable; import android.app.prediction.AppPredictor; import android.content.ComponentName; import android.content.Context; Loading Loading @@ -56,6 +59,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Consumer; public class ChooserListAdapter extends ResolverListAdapter { private static final String TAG = "ChooserListAdapter"; Loading Loading @@ -108,6 +112,9 @@ public class ChooserListAdapter extends ResolverListAdapter { // Represents the UserSpace in which the Initial Intents should be resolved. private final UserHandle mInitialIntentsUserSpace; @Nullable private Consumer<DisplayResolveInfo> mOnIconLoadedListener; // For pinned direct share labels, if the text spans multiple lines, the TextView will consume // the full width, even if the characters actually take up less than that. Measure the actual // line widths and constrain the View's width based upon that so that the pin doesn't end up Loading Loading @@ -218,6 +225,10 @@ public class ChooserListAdapter extends ResolverListAdapter { true); } public void setOnIconLoadedListener(Consumer<DisplayResolveInfo> onIconLoadedListener) { mOnIconLoadedListener = onIconLoadedListener; } AppPredictor getAppPredictor() { return mAppPredictor; } Loading Loading @@ -329,6 +340,15 @@ public class ChooserListAdapter extends ResolverListAdapter { } } @Override protected void onIconLoaded(DisplayResolveInfo info) { if (notifySingleItemChangeOnIconLoad() && mOnIconLoadedListener != null) { mOnIconLoadedListener.accept(info); } else { notifyDataSetChanged(); } } private void loadDirectShareIcon(SelectableTargetInfo info) { LoadDirectShareIconTask task = (LoadDirectShareIconTask) mIconLoaders.get(info); if (task == null) { Loading
core/java/com/android/internal/app/ResolverListAdapter.java +5 −1 Original line number Diff line number Diff line Loading @@ -680,6 +680,10 @@ public class ResolverListAdapter extends BaseAdapter { } } protected void onIconLoaded(DisplayResolveInfo info) { notifyDataSetChanged(); } private void loadLabel(DisplayResolveInfo info) { LoadLabelTask task = mLabelLoaders.get(info); if (task == null) { Loading Loading @@ -1004,7 +1008,7 @@ public class ResolverListAdapter extends BaseAdapter { mResolverListCommunicator.updateProfileViewButton(); } else if (!mDisplayResolveInfo.hasDisplayIcon()) { mDisplayResolveInfo.setDisplayIcon(d); notifyDataSetChanged(); onIconLoaded(mDisplayResolveInfo); } } } Loading