Enable trim memory callbacks to the loader, background task preloading

- Also enable the high-res thumbnail loader

Bug: 73651529

Change-Id: Ic23997f10289ea10cb1f41104e07029c9102c
Signed-off-by: Winson Chung <winsonc@google.com>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 0956048..9b6c053 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -25,6 +25,9 @@
     <dimen name="task_fade_length">20dp</dimen>
     <dimen name="recents_page_spacing">10dp</dimen>
 
+    <!-- The speed in dp/s at which the user needs to be scrolling in recents such that we start
+             loading full resolution screenshots. -->
+    <dimen name="recents_fast_fling_velocity">600dp</dimen>
 
     <dimen name="quickstep_fling_threshold_velocity">500dp</dimen>
     <dimen name="quickstep_fling_min_velocity">250dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index 7bd4366..71cdd10 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -29,6 +29,7 @@
 import com.android.launcher3.graphics.BitmapRenderer;
 import com.android.launcher3.util.TouchController;
 import com.android.quickstep.OverviewInteractionState;
+import com.android.quickstep.RecentsModel;
 import com.android.quickstep.RecentsView;
 import com.android.systemui.shared.recents.view.RecentsTransition;
 
@@ -88,4 +89,18 @@
         RecentsView recents = launcher.getOverviewPanel();
         recents.reset();
     }
+
+    public static void onStart(Launcher launcher) {
+        RecentsModel model = RecentsModel.getInstance(launcher);
+        if (model != null) {
+            model.onStart();
+        }
+    }
+
+    public static void onTrimMemory(Launcher launcher, int level) {
+        RecentsModel model = RecentsModel.getInstance(launcher);
+        if (model != null) {
+            model.onTrimMemory(level);
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 7fe7751..90e857c 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -16,6 +16,8 @@
 package com.android.quickstep;
 
 import android.annotation.TargetApi;
+import android.app.ActivityManager;
+import android.content.ComponentCallbacks2;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
@@ -29,6 +31,7 @@
 import android.util.LruCache;
 import android.util.SparseArray;
 
+import com.android.launcher3.Launcher;
 import com.android.launcher3.MainThreadExecutor;
 import com.android.launcher3.R;
 import com.android.launcher3.util.Preconditions;
@@ -51,7 +54,6 @@
  */
 @TargetApi(Build.VERSION_CODES.O)
 public class RecentsModel extends TaskStackChangeListener {
-
     // We do not need any synchronization for this variable as its only written on UI thread.
     private static RecentsModel INSTANCE;
 
@@ -83,10 +85,16 @@
     private int mTaskChangeId;
     private ISystemUiProxy mSystemUiProxy;
     private boolean mClearAssistCacheOnStackChange = true;
+    private final boolean mPreloadTasksInBackground;
 
     private RecentsModel(Context context) {
         mContext = context;
 
+        ActivityManager activityManager =
+                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        mPreloadTasksInBackground = !activityManager.isLowRamDevice();
+        mMainThreadExecutor = new MainThreadExecutor();
+
         Resources res = context.getResources();
         mRecentsTaskLoader = new RecentsTaskLoader(mContext,
                 res.getInteger(R.integer.config_recentsMaxThumbnailCacheSize),
@@ -100,8 +108,6 @@
             }
         };
         mRecentsTaskLoader.startLoader(mContext);
-
-        mMainThreadExecutor = new MainThreadExecutor();
         ActivityManagerWrapper.getInstance().registerTaskStackListener(this);
 
         mTaskChangeId = 1;
@@ -162,6 +168,31 @@
         }
     }
 
+    @Override
+    public void onTaskStackChangedBackground() {
+        int userId = UserHandle.myUserId();
+        if (!mPreloadTasksInBackground || !checkCurrentUserId(userId, false /* debug */)) {
+            // TODO: Only register this for the current user
+            return;
+        }
+
+        // Preload a fixed number of task icons/thumbnails in the background
+        ActivityManager.RunningTaskInfo runningTaskInfo =
+                ActivityManagerWrapper.getInstance().getRunningTask();
+        RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext);
+        RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
+        launchOpts.runningTaskId = runningTaskInfo != null ? runningTaskInfo.id : -1;
+        launchOpts.numVisibleTasks = 2;
+        launchOpts.numVisibleTaskThumbnails = 2;
+        launchOpts.onlyLoadForCache = true;
+        launchOpts.onlyLoadPausedActivities = true;
+        launchOpts.loadThumbnails = true;
+        PreloadOptions preloadOpts = new PreloadOptions();
+        preloadOpts.loadTitles = false;
+        plan.preloadPlan(preloadOpts, mRecentsTaskLoader, -1, userId);
+        mRecentsTaskLoader.loadTasks(plan, launchOpts);
+    }
+
     public boolean isLoadPlanValid(int resultId) {
         return mTaskChangeId == resultId;
     }
@@ -178,6 +209,19 @@
         return mSystemUiProxy;
     }
 
+    public void onStart() {
+        mRecentsTaskLoader.startLoader(mContext);
+        mRecentsTaskLoader.getHighResThumbnailLoader().setVisible(true);
+    }
+
+    public void onTrimMemory(int level) {
+        if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
+            // We already stop the loader in UI_HIDDEN, so stop the high res loader as well
+            mRecentsTaskLoader.getHighResThumbnailLoader().setVisible(false);
+        }
+        mRecentsTaskLoader.onTrimMemory(level);
+    }
+
     @WorkerThread
     public void preloadAssistData(int taskId, Bundle data) {
         mMainThreadExecutor.execute(() -> {
diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java
index 991852a..42677c1 100644
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/RecentsView.java
@@ -26,6 +26,7 @@
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
@@ -85,6 +86,8 @@
     private LayoutTransition mLayoutTransition;
     private Runnable mNextPageSwitchRunnable;
 
+    private float mFastFlingVelocity;
+
     /**
      * TODO: Call reloadIdNeeded in onTaskStackChanged.
      */
@@ -199,7 +202,9 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
+        Resources res = getResources();
         mFirstTaskIndex = getPageCount();
+        mFastFlingVelocity = res.getDimensionPixelSize(R.dimen.recents_fast_fling_velocity);
     }
 
     @Override
@@ -327,8 +332,10 @@
         }
         while (getChildCount() > requiredChildCount) {
             final TaskView taskView = (TaskView) getChildAt(getChildCount() - 1);
+            final Task task = taskView.getTask();
             removeView(taskView);
-            loader.unloadTaskData(taskView.getTask());
+            loader.unloadTaskData(task);
+            loader.getHighResThumbnailLoader().onTaskInvisible(task);
         }
         setLayoutTransition(mLayoutTransition);
 
@@ -439,11 +446,21 @@
     @Override
     protected boolean computeScrollHelper() {
         boolean scrolling = super.computeScrollHelper();
+        boolean isFlingingFast = false;
         updateCurveProperties();
         if (scrolling || (mTouchState == TOUCH_STATE_SCROLLING)) {
+            if (scrolling) {
+                // Check if we are flinging quickly to disable high res thumbnail loading
+                isFlingingFast = mScroller.getCurrVelocity() > mFastFlingVelocity;
+            }
+
             // After scrolling, update the visible task's data
             loadVisibleTaskData();
         }
+
+        // Update the high res thumbnail loader
+        RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
+        loader.getHighResThumbnailLoader().setFlingingFast(isFlingingFast);
         return scrolling;
     }
 
@@ -488,10 +505,12 @@
             if (visible) {
                 if (!mPrevVisibleTasks.get(i)) {
                     loader.loadTaskData(task);
+                    loader.getHighResThumbnailLoader().onTaskVisible(task);
                 }
             } else {
                 if (mPrevVisibleTasks.get(i)) {
                     loader.unloadTaskData(task);
+                    loader.getHighResThumbnailLoader().onTaskInvisible(task);
                 }
             }
             mPrevVisibleTasks.put(i, visible);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 5ac53a8..38b0140 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -829,6 +829,7 @@
             mScrimAnimator.start();
         }
         mShouldFadeInScrim = false;
+        UiFactory.onStart(this);
     }
 
     @Override
@@ -2171,6 +2172,7 @@
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.onTrimMemory(level);
         }
+        UiFactory.onTrimMemory(this, level);
     }
 
     @Override
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index ca8039c..6ec209a 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -552,7 +552,6 @@
                 // Notify the user when the page changes
                 announceForAccessibility(getCurrentPageDescription());
             }
-            return true;
         }
         return false;
     }
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
index 64a29ea..a16ae48 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
@@ -64,4 +64,8 @@
     public static void resetOverview(Launcher launcher) { }
 
     public static void onLauncherStateOrFocusChanged(Launcher launcher) { }
+
+    public static void onStart(Launcher launcher) { }
+
+    public static void onTrimMemory(Launcher launcher, int level) { }
 }