[Search]Implement search session cache in AllApps

- Skips SearchTarget reapplication if the id has not changed
- Resolves Incessant  subtitle on short row

Bug: 181510793
Test: Manual
Change-Id: Ic10ef9682fd3700616b7b1b7a60e82b5f2250fd3
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 1546ee3..c57f621 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -113,7 +113,6 @@
 import com.android.launcher3.allapps.AllAppsStore;
 import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.launcher3.allapps.DiscoveryBounce;
-import com.android.launcher3.allapps.search.LiveSearchManager;
 import com.android.launcher3.anim.PropertyListBuilder;
 import com.android.launcher3.compat.AccessibilityManagerCompat;
 import com.android.launcher3.config.FeatureFlags;
@@ -277,8 +276,6 @@
 
     private Configuration mOldConfig;
 
-    private LiveSearchManager mLiveSearchManager;
-
     @Thunk
     Workspace mWorkspace;
     @Thunk
@@ -401,8 +398,6 @@
         mAllAppsController = new AllAppsTransitionController(this);
         mStateManager = new StateManager<>(this, NORMAL);
 
-        mLiveSearchManager = new LiveSearchManager(this);
-
         mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs);
 
         mAppWidgetManager = new WidgetManagerHelper(this);
@@ -490,10 +485,6 @@
         }
     }
 
-    public LiveSearchManager getLiveSearchManager() {
-        return mLiveSearchManager;
-    }
-
     protected LauncherOverlayManager getDefaultOverlay() {
         return new LauncherOverlayManager() { };
     }
@@ -1594,7 +1585,6 @@
 
         mOverlayManager.onActivityDestroyed(this);
         mUserChangedCallbackCloseable.close();
-        mLiveSearchManager.stop();
     }
 
     public LauncherAccessibilityDelegate getAccessibilityDelegate() {
diff --git a/src/com/android/launcher3/allapps/search/LiveSearchManager.java b/src/com/android/launcher3/allapps/search/LiveSearchManager.java
deleted file mode 100644
index adb882a..0000000
--- a/src/com/android/launcher3/allapps/search/LiveSearchManager.java
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-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;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
-import android.content.Context;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.util.Log;
-
-import androidx.annotation.Nullable;
-import androidx.annotation.UiThread;
-import androidx.annotation.WorkerThread;
-import androidx.lifecycle.Observer;
-import androidx.slice.Slice;
-import androidx.slice.SliceViewManager;
-import androidx.slice.SliceViewManager.SliceCallback;
-
-import com.android.launcher3.Alarm;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.statemanager.StateManager.StateListener;
-import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.SafeCloseable;
-import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.widget.PendingAddWidgetInfo;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.function.Consumer;
-
-/**
- * Manages Lifecycle for Live search results
- */
-public class LiveSearchManager implements StateListener<LauncherState> {
-
-    private static final String TAG = "LiveSearchManager";
-
-    private static final long SLICE_TIMEOUT_MS = 50;
-    public static final int SEARCH_APPWIDGET_HOST_ID = 2048;
-
-    private final Launcher mLauncher;
-    private final HashMap<Uri, SliceLifeCycle> mUriSliceMap = new HashMap<>();
-
-    private final HashMap<ComponentKey, SearchWidgetInfoContainer> mWidgetPlaceholders =
-            new HashMap<>();
-    private SearchWidgetHost mSearchWidgetHost;
-
-    public LiveSearchManager(Launcher launcher) {
-        mLauncher = launcher;
-        mLauncher.getStateManager().addStateListener(this);
-    }
-
-    /**
-     * Creates new {@link AppWidgetHostView} from {@link AppWidgetProviderInfo}. Caches views for
-     * quicker result within the same search session
-     */
-    public SearchWidgetInfoContainer getPlaceHolderWidget(AppWidgetProviderInfo providerInfo) {
-        if (mSearchWidgetHost == null) {
-            mSearchWidgetHost = new SearchWidgetHost(mLauncher);
-            mSearchWidgetHost.startListening();
-        }
-
-        ComponentName provider = providerInfo.provider;
-        UserHandle userHandle = providerInfo.getProfile();
-
-        ComponentKey key = new ComponentKey(provider, userHandle);
-        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 = AppWidgetManager.getInstance(mLauncher)
-                .bindAppWidgetIdIfAllowed(appWidgetId, userHandle, provider, options);
-        if (!success) {
-            mSearchWidgetHost.deleteAppWidgetId(appWidgetId);
-            mWidgetPlaceholders.put(key, null);
-            return null;
-        }
-
-        SearchWidgetInfoContainer view = (SearchWidgetInfoContainer) mSearchWidgetHost.createView(
-                mLauncher, appWidgetId, providerInfo);
-        view.setTag(pendingAddWidgetInfo);
-        mWidgetPlaceholders.put(key, view);
-        return view;
-    }
-
-    /**
-     * Stop search session
-     */
-    public void stop() {
-        clearWidgetHost();
-    }
-
-    private void clearWidgetHost() {
-        if (mSearchWidgetHost != null) {
-            mSearchWidgetHost.stopListening();
-            mSearchWidgetHost.clearViews();
-            mSearchWidgetHost.deleteHost();
-            mWidgetPlaceholders.clear();
-            mSearchWidgetHost = null;
-        }
-    }
-
-    @Override
-    public void onStateTransitionComplete(LauncherState finalState) {
-        if (finalState != ALL_APPS) {
-            // Clear all search session related objects
-            mUriSliceMap.values().forEach(SliceLifeCycle::destroy);
-            mUriSliceMap.clear();
-
-            clearWidgetHost();
-        }
-    }
-
-    /**
-     * Adds a new observer for the provided uri and returns a callback to cancel this observer
-     */
-    public SafeCloseable addObserver(Uri uri, Observer<Slice> listener,
-            Consumer<Uri> timeoutConsumer) {
-        SliceLifeCycle slc = mUriSliceMap.get(uri);
-        if (slc == null) {
-            slc = new SliceLifeCycle(uri, mLauncher);
-            mUriSliceMap.put(uri, slc);
-        }
-        if (slc.mLastValue != null) {
-            listener.onChanged(slc.mLastValue);
-        }
-
-        // Use a listener wrapper to handle error timeout.
-        Observer<Slice> listenerWrapper = new Observer<Slice>() {
-            final Alarm mErrorTimeout = new Alarm();
-            {
-                mErrorTimeout.setOnAlarmListener(alarm -> {
-                    alarm.cancelAlarm();
-                    timeoutConsumer.accept(uri);
-                });
-                mErrorTimeout.setAlarm(SLICE_TIMEOUT_MS);
-            }
-
-            @Override
-            public void onChanged(Slice slice) {
-                if (slice == null) {
-                    return;
-                }
-
-                if (mErrorTimeout.alarmPending()) {
-                    mErrorTimeout.cancelAlarm();
-                }
-
-                if (mUriSliceMap.get(uri) != null) {
-                    mUriSliceMap.get(uri).mLastValue = slice;
-                }
-
-                listener.onChanged(slice);
-            }
-        };
-
-        slc.addListener(listenerWrapper);
-
-        final SliceLifeCycle sliceLifeCycle = slc;
-        return () -> sliceLifeCycle.removeListener(listenerWrapper);
-    }
-
-    static class SearchWidgetHost extends AppWidgetHost {
-        SearchWidgetHost(Context context) {
-            super(context, SEARCH_APPWIDGET_HOST_ID);
-        }
-
-        @Override
-        protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
-                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;
-
-        Slice mLastValue;
-
-        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) { }
-    }
-}
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 61f2c2a..988794c 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -131,6 +131,7 @@
 
     /**
      * 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 HandlerRunnable updateIconInBackground(final ItemInfoUpdateReceiver caller,
@@ -139,7 +140,7 @@
         if (mPendingIconRequestCount <= 0) {
             MODEL_EXECUTOR.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
         }
-        mPendingIconRequestCount ++;
+        mPendingIconRequestCount++;
 
         HandlerRunnable<ItemInfoWithIcon> request = new HandlerRunnable<>(mWorkerHandler,
                 () -> {
@@ -158,7 +159,7 @@
     }
 
     private void onIconRequestEnd() {
-        mPendingIconRequestCount --;
+        mPendingIconRequestCount--;
         if (mPendingIconRequestCount <= 0) {
             MODEL_EXECUTOR.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
         }
@@ -289,7 +290,8 @@
             @NonNull Supplier<LauncherActivityInfo> activityInfoProvider,
             boolean usePkgIcon, boolean useLowResIcon) {
         CacheEntry entry = cacheLocked(infoInOut.getTargetComponent(), infoInOut.user,
-                activityInfoProvider, mLauncherActivityInfoCachingLogic, usePkgIcon, useLowResIcon);
+                activityInfoProvider, mLauncherActivityInfoCachingLogic, usePkgIcon,
+                useLowResIcon);
         applyCacheEntry(entry, infoInOut);
     }
 
@@ -315,7 +317,8 @@
     }
 
     public void updateSessionCache(PackageUserKey key, PackageInstaller.SessionInfo info) {
-        cachePackageInstallInfo(key.mPackageName, key.mUser, info.getAppIcon(), info.getAppLabel());
+        cachePackageInstallInfo(key.mPackageName, key.mUser, info.getAppIcon(),
+                info.getAppLabel());
     }
 
     @Override