From af044aefd99a3452539a409fec596ee312aa0990 Mon Sep 17 00:00:00 2001 From: Matt Pietal Date: Fri, 29 Mar 2019 06:53:53 -0400 Subject: [PATCH] Sharesheet - Make UI more responsive to touches when loading ListView will try to prevent errant touches while data is being loaded. With Sharesheet, this can happen quite frequently so 1: eliminate unnecessary notifyDataSetChanged calls and 2: batch up the remaining calls and release a single call on an interval. Bug: 126568576 Test: atest ChooserActivityTest && atest ResolverActivityTest Change-Id: I3207f207910a0c9223a1b562243d9db612f93b0a --- .../android/internal/app/ChooserActivity.java | 48 ++++++++++++++--- .../internal/app/ResolverActivity.java | 52 ++++--------------- 2 files changed, 51 insertions(+), 49 deletions(-) diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index f14b50dcd04de..07d28eba793d3 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -24,7 +24,6 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.IntDef; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.ActivityManager; import android.app.prediction.AppPredictionContext; @@ -197,6 +196,11 @@ public class ChooserActivity extends ResolverActivity { private static final int CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT = 2; private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT = 3; private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED = 4; + private static final int LIST_VIEW_UPDATE_MESSAGE = 5; + + private static final int LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS = 250; + + private boolean mListViewDataChanged = false; @Retention(SOURCE) @IntDef({CONTENT_PREVIEW_FILE, CONTENT_PREVIEW_IMAGE, CONTENT_PREVIEW_TEXT}) @@ -213,10 +217,13 @@ public class ChooserActivity extends ResolverActivity { private final Handler mChooserHandler = new Handler() { @Override public void handleMessage(Message msg) { + if (mChooserListAdapter == null || isDestroyed()) { + return; + } + switch (msg.what) { case CHOOSER_TARGET_SERVICE_RESULT: if (DEBUG) Log.d(TAG, "CHOOSER_TARGET_SERVICE_RESULT"); - if (isDestroyed()) break; final ServiceResultInfo sri = (ServiceResultInfo) msg.obj; if (!mServiceConnections.contains(sri.connection)) { Log.w(TAG, "ChooserTargetServiceConnection " + sri.connection @@ -240,17 +247,22 @@ public class ChooserActivity extends ResolverActivity { if (DEBUG) { Log.d(TAG, "CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT; unbinding services"); } - if (mChooserListAdapter == null || isDestroyed()) { - break; - } + unbindRemainingServices(); sendVoiceChoicesIfNeeded(); mChooserListAdapter.completeServiceTargetLoading(); break; + case LIST_VIEW_UPDATE_MESSAGE: + if (DEBUG) { + Log.d(TAG, "LIST_VIEW_UPDATE_MESSAGE; "); + } + + mChooserListAdapter.refreshListView(); + break; + case SHORTCUT_MANAGER_SHARE_TARGET_RESULT: if (DEBUG) Log.d(TAG, "SHORTCUT_MANAGER_SHARE_TARGET_RESULT"); - if (isDestroyed()) break; final ServiceResultInfo resultInfo = (ServiceResultInfo) msg.obj; if (resultInfo.resultTargets != null) { mChooserListAdapter.addServiceResults(resultInfo.originalTarget, @@ -829,6 +841,7 @@ public class ChooserActivity extends ResolverActivity { mRefinementResultReceiver = null; } unbindRemainingServices(); + mChooserHandler.removeMessages(LIST_VIEW_UPDATE_MESSAGE); mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT); mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_RESULT); if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) { @@ -1872,6 +1885,23 @@ public class ChooserActivity extends ResolverActivity { } } + @Override + public void notifyDataSetChanged() { + if (!mListViewDataChanged) { + mChooserHandler.sendEmptyMessageDelayed(LIST_VIEW_UPDATE_MESSAGE, + LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS); + mListViewDataChanged = true; + } + } + + private void refreshListView() { + if (mListViewDataChanged) { + super.notifyDataSetChanged(); + } + mListViewDataChanged = false; + } + + private void createPlaceHolders() { mServiceTargets.clear(); for (int i = 0; i < MAX_SERVICE_TARGETS; i++) { @@ -1893,7 +1923,7 @@ public class ChooserActivity extends ResolverActivity { } if (mServiceTargets != null) { - if (getDisplayInfoCount() == 0) { + if (getDisplayResolveInfoCount() == 0) { // b/109676071: When packages change, onListRebuilt() is called before // ResolverActivity.mDisplayList is re-populated; pruning now would cause the // list to disappear briefly, so instead we detect this case (the @@ -1906,12 +1936,14 @@ public class ChooserActivity extends ResolverActivity { if (DEBUG) { Log.d(TAG, "querying direct share targets from ShortcutManager"); } + queryDirectShareTargets(this); } if (USE_CHOOSER_TARGET_SERVICE_FOR_DIRECT_TARGETS) { if (DEBUG) { Log.d(TAG, "List built querying services"); } + queryTargetServices(this); } } @@ -2007,7 +2039,7 @@ public class ChooserActivity extends ResolverActivity { offset += callerTargetCount; return filtered ? super.getItem(position - offset) - : getDisplayInfoAt(position - offset); + : getDisplayResolveInfo(position - offset); } public void addServiceResults(DisplayResolveInfo origTarget, List targets) { diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 9f9e083f1fb1c..f47469a0e1b35 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -1230,7 +1230,7 @@ public class ResolverActivity extends Activity { final ImageView iconView = findViewById(R.id.icon); final DisplayResolveInfo iconInfo = mAdapter.getFilteredItem(); if (iconView != null && iconInfo != null) { - new LoadIconIntoViewTask(iconInfo, iconView).execute(); + new LoadIconTask(iconInfo, iconView).execute(); } } @@ -1871,14 +1871,6 @@ public class ResolverActivity extends Activity { return mDisplayList.size(); } - public int getDisplayInfoCount() { - return mDisplayList.size(); - } - - public DisplayResolveInfo getDisplayInfoAt(int index) { - return mDisplayList.get(index); - } - @Nullable public TargetInfo getItem(int position) { if (mFilterLastUsed && mLastChosenPosition >= 0 && position >= mLastChosenPosition) { @@ -1966,9 +1958,10 @@ public class ResolverActivity extends Activity { if (info instanceof DisplayResolveInfo && !((DisplayResolveInfo) info).hasDisplayIcon()) { - new LoadAdapterIconTask((DisplayResolveInfo) info).execute(); + new LoadIconTask((DisplayResolveInfo) info, holder.icon).execute(); + } else { + holder.icon.setImageDrawable(info.getDisplayIcon()); } - holder.icon.setImageDrawable(info.getDisplayIcon()); } } @@ -2087,13 +2080,15 @@ public class ResolverActivity extends Activity { } - abstract class LoadIconTask extends AsyncTask { + class LoadIconTask extends AsyncTask { protected final DisplayResolveInfo mDisplayResolveInfo; private final ResolveInfo mResolveInfo; + private final ImageView mTargetView; - public LoadIconTask(DisplayResolveInfo dri) { + LoadIconTask(DisplayResolveInfo dri, ImageView target) { mDisplayResolveInfo = dri; mResolveInfo = dri.getResolveInfo(); + mTargetView = target; } @Override @@ -2103,37 +2098,12 @@ public class ResolverActivity extends Activity { @Override protected void onPostExecute(Drawable d) { - mDisplayResolveInfo.setDisplayIcon(d); - } - } - - class LoadAdapterIconTask extends LoadIconTask { - public LoadAdapterIconTask(DisplayResolveInfo dri) { - super(dri); - } - - @Override - protected void onPostExecute(Drawable d) { - super.onPostExecute(d); if (mProfileView != null && mAdapter.getOtherProfile() == mDisplayResolveInfo) { bindProfileView(); + } else { + mDisplayResolveInfo.setDisplayIcon(d); + mTargetView.setImageDrawable(d); } - mAdapter.notifyDataSetChanged(); - } - } - - class LoadIconIntoViewTask extends LoadIconTask { - private final ImageView mTargetView; - - public LoadIconIntoViewTask(DisplayResolveInfo dri, ImageView target) { - super(dri); - mTargetView = target; - } - - @Override - protected void onPostExecute(Drawable d) { - super.onPostExecute(d); - mTargetView.setImageDrawable(d); } }