Moving slice loading on a background thread

> Also fixing slice icon loading, such that the request is cancelled
  if views are recycled quickly
> Loading widget label on dg thread and cancelling request if views
  are recycled quickly.

Bug: 179068415
Test: verified locally
Change-Id: Id5a524e2bf596862330a8170394aef9ffd708544
This commit is contained in:
Sunny Goyal
2021-02-03 10:22:28 -08:00
parent f4d19f4614
commit 79e52fc23b
8 changed files with 235 additions and 129 deletions
@@ -15,28 +15,22 @@
*/
package com.android.launcher3.search;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.app.search.SearchTarget;
import android.app.search.SearchTargetEvent;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.LiveData;
import androidx.slice.Slice;
import androidx.slice.SliceItem;
import androidx.slice.widget.EventInfo;
import androidx.slice.widget.SliceView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.util.SafeCloseable;
import java.util.ArrayList;
import java.util.List;
@@ -47,13 +41,11 @@ import java.util.List;
public class SearchResultIconSlice extends LinearLayout implements SearchTargetHandler,
SliceView.OnSliceActionListener {
private static final String TAG = "SearchSliceController";
private final Launcher mLauncher;
private SliceView mSliceView;
private SearchResultIcon mIcon;
private LiveData<Slice> mSliceLiveData;
private SafeCloseable mSliceSession;
private String mTargetId;
public SearchResultIconSlice(Context context) {
@@ -87,26 +79,20 @@ public class SearchResultIconSlice extends LinearLayout implements SearchTargetH
mTargetId = parentTarget.getId();
reset();
updateIcon(parentTarget, children);
try {
mSliceLiveData = mLauncher.getLiveSearchManager().getSliceForUri(
parentTarget.getSliceUri());
mSliceLiveData.observe(mLauncher, mSliceView);
} catch (Exception ex) {
Log.e(TAG, "unable to bind slice", ex);
}
mSliceSession = mLauncher.getLiveSearchManager()
.addObserver(parentTarget.getSliceUri(), mSliceView);
}
private void updateIcon(SearchTarget parentTarget, List<SearchTarget> children) {
if (children.size() == 1) {
mIcon.apply(children.get(0), new ArrayList<>());
} else {
LauncherAppState appState = LauncherAppState.getInstance(getContext());
MODEL_EXECUTOR.post(() -> {
PackageItemInfo pkgItem = new PackageItemInfo(parentTarget.getPackageName());
pkgItem.user = parentTarget.getUserHandle();
appState.getIconCache().getTitleAndIconForApp(pkgItem, false);
MAIN_EXECUTOR.post(() -> mIcon.applyFromItemInfoWithIcon(pkgItem));
});
PackageItemInfo pkgItem = new PackageItemInfo(parentTarget.getPackageName());
pkgItem.user = parentTarget.getUserHandle();
if (!pkgItem.equals(mIcon.getTag())) {
// The icon will load and apply high res icon automatically
mIcon.applyFromItemInfoWithIcon(pkgItem);
}
}
}
@@ -124,8 +110,8 @@ public class SearchResultIconSlice extends LinearLayout implements SearchTargetH
private void reset() {
mSliceView.setOnSliceActionListener(null);
if (mSliceLiveData != null) {
mSliceLiveData.removeObservers(mLauncher);
if (mSliceSession != null) {
mSliceSession.close();
}
}
@@ -15,6 +15,9 @@
*/
package com.android.launcher3.search;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.app.search.SearchTarget;
import android.app.search.SearchTargetEvent;
import android.appwidget.AppWidgetHostView;
@@ -36,16 +39,19 @@ import com.android.launcher3.BubbleTextView;
import com.android.launcher3.CheckLongPressHelper;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.search.SearchWidgetInfoContainer;
import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.icons.cache.HandlerRunnable;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.widget.PendingAddWidgetInfo;
import java.util.List;
/**
* displays live version of a widget upon receiving {@link AppWidgetProviderInfo} from Search
* provider
@@ -63,6 +69,7 @@ public class SearchResultWidget extends LinearLayout implements SearchTargetHand
private final float mScaleToFit;
private SearchWidgetInfoContainer mInfoContainer;
private HandlerRunnable mLabelRequest;
private BubbleTextView mWidgetProvider;
private TextView mWidgetLabel;
@@ -124,11 +131,18 @@ public class SearchResultWidget extends LinearLayout implements SearchTargetHand
}
private void showWidgetInfo(AppWidgetProviderInfo providerInfo) {
String title = providerInfo.loadLabel(mLauncher.getPackageManager());
PackageItemInfo pinfo = new PackageItemInfo(providerInfo.provider.getPackageName());
pinfo.user = providerInfo.getProfile();
mWidgetProvider.applyFromItemInfoWithIcon(pinfo);
mWidgetLabel.setText(title);
mLabelRequest = new HandlerRunnable<>(
MODEL_EXECUTOR.getHandler(),
() -> LauncherAppState.getInstance(mLauncher).getIconCache()
.getTitleNoCache(LauncherAppWidgetProviderInfo
.fromProviderInfo(mLauncher, providerInfo)),
MAIN_EXECUTOR,
mWidgetLabel::setText);
Utilities.postAsyncCallback(MODEL_EXECUTOR.getHandler(), mLabelRequest);
}
/**
@@ -137,7 +151,18 @@ public class SearchResultWidget extends LinearLayout implements SearchTargetHand
public void removeListener() {
if (mInfoContainer != null) {
mInfoContainer.detachWidget(mHostView);
mInfoContainer = null;
}
if (mLabelRequest != null) {
mLabelRequest.cancel();
mLabelRequest = null;
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
removeListener();
}
private void reportEvent(int eventType) {
@@ -66,9 +66,9 @@ import com.android.launcher3.graphics.IconShape;
import com.android.launcher3.graphics.PlaceHolderIconDrawable;
import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.icons.DotRenderer;
import com.android.launcher3.icons.IconCache.IconLoadRequest;
import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.icons.cache.HandlerRunnable;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
@@ -171,7 +171,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mDisableRelayout = false;
private IconLoadRequest mIconLoadRequest;
private HandlerRunnable mIconLoadRequest;
private boolean mEnableIconUpdateAnimation = false;
+3 -24
View File
@@ -98,13 +98,9 @@ import android.widget.ImageView;
import android.widget.Toast;
import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
@@ -211,8 +207,7 @@ import java.util.stream.Stream;
* Default launcher application.
*/
public class Launcher extends StatefulActivity<LauncherState> implements LauncherExterns,
Callbacks, InvariantDeviceProfile.OnIDPChangeListener, PluginListener<OverlayPlugin>,
LifecycleOwner {
Callbacks, InvariantDeviceProfile.OnIDPChangeListener, PluginListener<OverlayPlugin> {
public static final String TAG = "Launcher";
public static final ActivityTracker<Launcher> ACTIVITY_TRACKER = new ActivityTracker<>();
@@ -275,8 +270,6 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
private LauncherAppTransitionManager mAppTransitionManager;
private Configuration mOldConfig;
private LifecycleRegistry mLifecycleRegistry;
private LiveSearchManager mLiveSearchManager;
@Thunk
@@ -392,12 +385,12 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
mIconCache = app.getIconCache();
mAccessibilityDelegate = new LauncherAccessibilityDelegate(this);
mLiveSearchManager = new LiveSearchManager(this);
mDragController = new DragController(this);
mAllAppsController = new AllAppsTransitionController(this);
mStateManager = new StateManager<>(this, NORMAL);
mLiveSearchManager = new LiveSearchManager(this);
mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs);
mAppWidgetManager = new WidgetManagerHelper(this);
@@ -486,15 +479,6 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
if (Utilities.ATLEAST_R) {
getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
}
mLifecycleRegistry = new LifecycleRegistry(this);
mLifecycleRegistry.setCurrentState(Lifecycle.State.CREATED);
}
@NonNull
@Override
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
public LiveSearchManager getLiveSearchManager() {
@@ -913,7 +897,6 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
@Override
protected void onStop() {
mLifecycleRegistry.setCurrentState(Lifecycle.State.CREATED);
super.onStop();
if (mDeferOverlayCallbacks) {
checkIfOverlayStillDeferred();
@@ -937,7 +920,6 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
mAppWidgetHost.setListenIfResumed(true);
TraceHelper.INSTANCE.endSection(traceToken);
mLifecycleRegistry.setCurrentState(Lifecycle.State.STARTED);
}
@Override
@@ -1091,7 +1073,6 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
}
TraceHelper.INSTANCE.endSection(traceToken);
mLifecycleRegistry.setCurrentState(Lifecycle.State.RESUMED);
}
@Override
@@ -1099,7 +1080,6 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
// Ensure that items added to Launcher are queued until Launcher returns
ItemInstallQueue.INSTANCE.get(this).pauseModelPush(FLAG_ACTIVITY_PAUSED);
mLifecycleRegistry.setCurrentState(Lifecycle.State.STARTED);
super.onPause();
mDragController.cancelDrag();
mLastTouchUpTime = -1;
@@ -1598,7 +1578,6 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
mAppTransitionManager.unregisterRemoteAnimations();
mAppTransitionManager.unregisterRemoteTransitions();
mUserChangedCallbackCloseable.close();
mLifecycleRegistry.setCurrentState(Lifecycle.State.DESTROYED);
mLiveSearchManager.stop();
}
@@ -268,13 +268,10 @@ public class AllAppsTransitionController implements StateHandler<LauncherState>,
&& !FeatureFlags.DISABLE_INITIAL_IME_IN_ALLAPPS.get() && BuildCompat.isAtLeastR()) {
mInsetController.onAnimationEnd(mProgress);
if (Float.compare(mProgress, 0f) == 0) {
mLauncher.getLiveSearchManager().start();
EditText editText = mAppsView.getSearchUiManager().getEditText();
if (editText != null && !mInsetController.showSearchEduIfNecessary()) {
editText.requestFocus();
}
} else {
mLauncher.getLiveSearchManager().stop();
}
// TODO: should make the controller hide synchronously
}
@@ -15,8 +15,14 @@
*/
package com.android.launcher3.allapps.search;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.widget.WidgetHostViewLoader.getDefaultOptionsForWidget;
import android.app.Activity;
import android.app.Application.ActivityLifecycleCallbacks;
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetManager;
@@ -26,39 +32,49 @@ import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.Log;
import androidx.lifecycle.LiveData;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.annotation.WorkerThread;
import androidx.lifecycle.Observer;
import androidx.slice.Slice;
import androidx.slice.widget.SliceLiveData;
import androidx.slice.SliceViewManager;
import androidx.slice.SliceViewManager.SliceCallback;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherState;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.widget.PendingAddWidgetInfo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Optional;
/**
* Manages Lifecycle for Live search results
*/
public class LiveSearchManager {
public class LiveSearchManager implements StateListener<LauncherState> {
private static final String TAG = "LiveSearchManager";
public static final int SEARCH_APPWIDGET_HOST_ID = 2048;
private final Launcher mLauncher;
private final AppWidgetManager mAppWidgetManger;
private final HashMap<Uri, SliceLifeCycle> mUriSliceMap = new HashMap<>();
private final HashMap<ComponentKey, SearchWidgetInfoContainer> mWidgetPlaceholders =
new HashMap<>();
private final HashMap<Uri, LiveData<Slice>> mUriSliceMap = new HashMap<>();
private SearchWidgetHost mSearchWidgetHost;
private InstanceId mLogInstanceId;
public LiveSearchManager(Launcher launcher) {
mLauncher = launcher;
mAppWidgetManger = AppWidgetManager.getInstance(launcher);
mLauncher.getStateManager().addStateListener(this);
}
/**
@@ -67,78 +83,80 @@ public class LiveSearchManager {
*/
public SearchWidgetInfoContainer getPlaceHolderWidget(AppWidgetProviderInfo providerInfo) {
if (mSearchWidgetHost == null) {
throw new RuntimeException("AppWidgetHost has not been created yet");
mSearchWidgetHost = new SearchWidgetHost(mLauncher);
mSearchWidgetHost.startListening();
}
ComponentName provider = providerInfo.provider;
UserHandle userHandle = providerInfo.getProfile();
ComponentKey key = new ComponentKey(provider, userHandle);
SearchWidgetInfoContainer view = mWidgetPlaceholders.getOrDefault(key, null);
if (mWidgetPlaceholders.containsKey(key)) {
return mWidgetPlaceholders.get(key);
}
LauncherAppWidgetProviderInfo pinfo = LauncherAppWidgetProviderInfo.fromProviderInfo(
mLauncher, providerInfo);
PendingAddWidgetInfo pendingAddWidgetInfo = new PendingAddWidgetInfo(pinfo);
Bundle options = getDefaultOptionsForWidget(mLauncher, pendingAddWidgetInfo);
int appWidgetId = mSearchWidgetHost.allocateAppWidgetId();
boolean success = mAppWidgetManger.bindAppWidgetIdIfAllowed(appWidgetId, userHandle,
provider, options);
boolean success = AppWidgetManager.getInstance(mLauncher)
.bindAppWidgetIdIfAllowed(appWidgetId, userHandle, provider, options);
if (!success) {
mSearchWidgetHost.deleteAppWidgetId(appWidgetId);
mWidgetPlaceholders.put(key, null);
return null;
}
view = (SearchWidgetInfoContainer) mSearchWidgetHost.createView(mLauncher, appWidgetId,
providerInfo);
SearchWidgetInfoContainer view = (SearchWidgetInfoContainer) mSearchWidgetHost.createView(
mLauncher, appWidgetId, providerInfo);
view.setTag(pendingAddWidgetInfo);
mWidgetPlaceholders.put(key, view);
return view;
}
/**
* Creates {@link LiveData<Slice>} from Slice Uri. Caches created live data to be reused
* within the same search session. Removes previous observers when new SliceView request a
* live data for observation.
*/
public LiveData<Slice> getSliceForUri(Uri sliceUri) {
LiveData<Slice> sliceLiveData = mUriSliceMap.getOrDefault(sliceUri, null);
if (sliceLiveData == null) {
sliceLiveData = SliceLiveData.fromUri(mLauncher, sliceUri);
mUriSliceMap.put(sliceUri, sliceLiveData);
}
return sliceLiveData;
}
/**
* Start search session
*/
public void start() {
stop();
mLogInstanceId = new InstanceIdSequence().newInstanceId();
mSearchWidgetHost = new SearchWidgetHost(mLauncher);
mSearchWidgetHost.startListening();
}
/**
* Stop search session
*/
public void stop() {
clearWidgetHost();
}
private void clearWidgetHost() {
if (mSearchWidgetHost != null) {
mSearchWidgetHost.stopListening();
mSearchWidgetHost.clearViews();
mSearchWidgetHost.deleteHost();
for (SearchWidgetInfoContainer placeholder : mWidgetPlaceholders.values()) {
placeholder.clearListeners();
}
mWidgetPlaceholders.clear();
mSearchWidgetHost = null;
}
for (LiveData<Slice> liveData : mUriSliceMap.values()) {
liveData.removeObservers(mLauncher);
}
@Override
public void onStateTransitionComplete(LauncherState finalState) {
if (finalState != ALL_APPS) {
// Clear all search session related objects
mUriSliceMap.values().forEach(SliceLifeCycle::destroy);
mUriSliceMap.clear();
clearWidgetHost();
}
mUriSliceMap.clear();
}
/**
* Adds a new observer for the provided uri and returns a callback to cancel this observer
*/
public SafeCloseable addObserver(Uri uri, Observer<Slice> listener) {
SliceLifeCycle slc = mUriSliceMap.get(uri);
if (slc == null) {
slc = new SliceLifeCycle(uri, mLauncher);
mUriSliceMap.put(uri, slc);
}
slc.addListener(listener);
final SliceLifeCycle sliceLifeCycle = slc;
return () -> sliceLifeCycle.removeListener(listener);
}
/**
@@ -159,5 +177,121 @@ public class LiveSearchManager {
AppWidgetProviderInfo appWidget) {
return new SearchWidgetInfoContainer(context);
}
@Override
public void clearViews() {
super.clearViews();
}
}
private static class SliceLifeCycle
implements ActivityLifecycleCallbacks, SliceCallback {
private final Uri mUri;
private final Launcher mLauncher;
private final SliceViewManager mSliceViewManager;
private final ArrayList<Observer<Slice>> mListeners = new ArrayList<>();
private boolean mDestroyed = false;
private boolean mWasListening = false;
SliceLifeCycle(Uri uri, Launcher launcher) {
mUri = uri;
mLauncher = launcher;
mSliceViewManager = SliceViewManager.getInstance(launcher);
launcher.registerActivityLifecycleCallbacks(this);
if (launcher.isDestroyed()) {
onActivityDestroyed(launcher);
} else if (launcher.isStarted()) {
onActivityStarted(launcher);
}
}
@Override
public void onActivityDestroyed(Activity activity) {
destroy();
}
@Override
public void onActivityStarted(Activity activity) {
updateListening();
}
@Override
public void onActivityStopped(Activity activity) {
updateListening();
}
private void updateListening() {
boolean isListening = mDestroyed
? false
: (mLauncher.isStarted() && !mListeners.isEmpty());
UI_HELPER_EXECUTOR.execute(() -> uploadListeningBg(isListening));
}
@WorkerThread
private void uploadListeningBg(boolean isListening) {
if (mWasListening != isListening) {
mWasListening = isListening;
if (isListening) {
mSliceViewManager.registerSliceCallback(mUri, MAIN_EXECUTOR, this);
// Update slice one-time on the different thread so that we can display
// multiple slices in parallel
THREAD_POOL_EXECUTOR.execute(this::updateSlice);
} else {
mSliceViewManager.unregisterSliceCallback(mUri, this);
}
}
}
@UiThread
private void addListener(Observer<Slice> listener) {
mListeners.add(listener);
updateListening();
}
@UiThread
private void removeListener(Observer<Slice> listener) {
mListeners.remove(listener);
updateListening();
}
@WorkerThread
private void updateSlice() {
try {
Slice s = mSliceViewManager.bindSlice(mUri);
MAIN_EXECUTOR.execute(() -> onSliceUpdated(s));
} catch (Exception e) {
Log.d(TAG, "Error fetching slice", e);
}
}
@UiThread
@Override
public void onSliceUpdated(@Nullable Slice s) {
mListeners.forEach(l -> l.onChanged(s));
}
private void destroy() {
if (mDestroyed) {
return;
}
mDestroyed = true;
mLauncher.unregisterActivityLifecycleCallbacks(this);
mListeners.clear();
}
@Override
public void onActivityCreated(Activity activity, Bundle bundle) { }
@Override
public void onActivityPaused(Activity activity) { }
@Override
public void onActivityResumed(Activity activity) { }
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { }
}
}
@@ -70,10 +70,4 @@ public class SearchWidgetInfoContainer extends AppWidgetHostView {
mListeners.remove(hostView);
}
/**
* Removes all AppWidgetHost update listeners
*/
public void clearListeners() {
mListeners.clear();
}
}
+13 -22
View File
@@ -31,7 +31,6 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ShortcutInfo;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Process;
import android.os.UserHandle;
import android.util.Log;
@@ -134,7 +133,7 @@ public class IconCache extends BaseIconCache {
* Fetches high-res icon for the provided ItemInfo and updates the caller when done.
* @return a request ID that can be used to cancel the request.
*/
public IconLoadRequest updateIconInBackground(final ItemInfoUpdateReceiver caller,
public HandlerRunnable updateIconInBackground(final ItemInfoUpdateReceiver caller,
final ItemInfoWithIcon info) {
Preconditions.assertUIThread();
if (mPendingIconRequestCount <= 0) {
@@ -142,20 +141,18 @@ public class IconCache extends BaseIconCache {
}
mPendingIconRequestCount ++;
IconLoadRequest request = new IconLoadRequest(mWorkerHandler, this::onIconRequestEnd) {
@Override
public void run() {
if (info instanceof AppInfo || info instanceof WorkspaceItemInfo) {
getTitleAndIcon(info, false);
} else if (info instanceof PackageItemInfo) {
getTitleAndIconForApp((PackageItemInfo) info, false);
}
MAIN_EXECUTOR.execute(() -> {
caller.reapplyItemInfo(info);
onEnd();
});
}
};
HandlerRunnable<ItemInfoWithIcon> request = new HandlerRunnable<>(mWorkerHandler,
() -> {
if (info instanceof AppInfo || info instanceof WorkspaceItemInfo) {
getTitleAndIcon(info, false);
} else if (info instanceof PackageItemInfo) {
getTitleAndIconForApp((PackageItemInfo) info, false);
}
return info;
},
MAIN_EXECUTOR,
caller::reapplyItemInfo,
this::onIconRequestEnd);
Utilities.postAsyncCallback(mWorkerHandler, request);
return request;
}
@@ -336,12 +333,6 @@ public class IconCache extends BaseIconCache {
return super.getEntryFromDB(cacheKey, entry, lowRes);
}
public static abstract class IconLoadRequest extends HandlerRunnable {
IconLoadRequest(Handler handler, Runnable endRunnable) {
super(handler, endRunnable);
}
}
/**
* Interface for receiving itemInfo with high-res icon.
*/