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
This commit is contained in:
Matt Pietal
2019-03-29 06:53:53 -04:00
parent bc9f5a518d
commit af044aefd9
2 changed files with 51 additions and 49 deletions

View File

@@ -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<ChooserTarget> targets) {

View File

@@ -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<Void, Void, Drawable> {
class LoadIconTask extends AsyncTask<Void, Void, Drawable> {
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);
}
}