Add task snapshot for home task

The real home activity usually takes longer time than a
snapshot to complete drawing. Especially when unlocking
to home, the duration becomes more noticeable.

This CL enables snapshot of home task when turning screen
off. And because the snapshot is only used when entering
home from a sleeping state, the snapshot will be removed
once it is used.

Also provide a method for home activity to remove its
snapshot while the content of home activity has significant
change after taking the snapshot.

Bug: 140811348
Test: 1. Set an unlock method that doesn't need to show
         lockscreen when unlocking.
      2. Turn off screen while home is on top.
      3. Unlock device to enter home.
      4. Check the duration of trace "screenTurningOn".

Change-Id: Ic516cdcfd84ca4a85e19798537f9f5a85077392b
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 37136a1..368a1bc 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -405,6 +405,14 @@
     void setDisablePreviewScreenshots(IBinder token, boolean disable);
 
     /**
+     * It should only be called from home activity to remove its outdated snapshot. The home
+     * snapshot is used to speed up entering home from screen off. If the content of home activity
+     * is significantly different from before taking the snapshot, then the home activity can use
+     * this method to avoid inconsistent transition.
+     */
+    void invalidateHomeTaskSnapshot(IBinder homeToken);
+
+    /**
      * Return the user id of last resumed activity.
      */
     int getLastResumedActivityUserId();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 70f8e15..deaafca 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -28,6 +28,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 
 import android.annotation.NonNull;
+import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManager.RecentTaskInfo;
 import android.app.ActivityManager.RunningTaskInfo;
@@ -161,6 +162,23 @@
     }
 
     /**
+     * Removes the outdated snapshot of home task.
+     */
+    public void invalidateHomeTaskSnapshot(final Activity homeActivity) {
+        mBackgroundExecutor.submit(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    ActivityTaskManager.getService().invalidateHomeTaskSnapshot(
+                            homeActivity.getActivityToken());
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to invalidate home snapshot", e);
+                }
+            }
+        });
+    }
+
+    /**
      * @return the activity label, badging if necessary.
      */
     public String getBadgedActivityLabel(ActivityInfo info, int userId) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 8435a82..c05b704 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -157,6 +157,7 @@
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.Trace;
 import android.os.UEventObserver;
 import android.os.UserHandle;
 import android.os.VibrationEffect;
@@ -4603,6 +4604,7 @@
     public void screenTurningOn(final ScreenOnListener screenOnListener) {
         if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...");
 
+        Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn", 0 /* cookie */);
         updateScreenOffSleepToken(false);
         mDefaultDisplayPolicy.screenTurnedOn(screenOnListener);
 
@@ -4665,6 +4667,7 @@
         if (!mDefaultDisplayPolicy.finishScreenTurningOn()) {
             return; // Spurious or not ready yet.
         }
+        Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn", 0 /* cookie */);
 
         final boolean enableScreen;
         final boolean awake = mDefaultDisplayPolicy.isAwake();
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index bc2fa4e..59fb319 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1640,6 +1640,17 @@
                 allowTaskSnapshot, activityCreated, fromRecents, snapshot);
 
         if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
+            if (isActivityTypeHome()) {
+                // The snapshot of home is only used once because it won't be updated while screen
+                // is on (see {@link TaskSnapshotController#screenTurningOff}).
+                mWmService.mTaskSnapshotController.removeSnapshotCache(task.mTaskId);
+                // TODO(b/9684093): Use more general condition to specify the case.
+                if (mDisplayContent.mAppTransition
+                        .getAppTransition() != WindowManager.TRANSIT_KEYGUARD_GOING_AWAY) {
+                    // Only use snapshot of home as starting window when unlocking.
+                    return false;
+                }
+            }
             return createSnapshot(snapshot);
         }
 
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 46c4d87..c405100 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -4572,6 +4572,17 @@
         }
     }
 
+    @Override
+    public void invalidateHomeTaskSnapshot(IBinder token) {
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            if (r == null || !r.isActivityTypeHome()) {
+                return;
+            }
+            mWindowManager.mTaskSnapshotController.removeSnapshotCache(r.getTask().mTaskId);
+        }
+    }
+
     /** Return the user id of the last resumed activity. */
     @Override
     public @UserIdInt
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotCache.java b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
index 5cbab5d..7b0d841 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotCache.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
@@ -109,7 +109,7 @@
         removeRunningEntry(taskId);
     }
 
-    private void removeRunningEntry(int taskId) {
+    void removeRunningEntry(int taskId) {
         final CacheEntry entry = mRunningCache.get(taskId);
         if (entry != null) {
             mAppTaskMap.remove(entry.topApp);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index c1a36c4..12b2845 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -171,22 +171,30 @@
     }
 
     void snapshotTasks(ArraySet<Task> tasks) {
+        snapshotTasks(mTmpTasks, false /* allowSnapshotHome */);
+    }
+
+    private void snapshotTasks(ArraySet<Task> tasks, boolean allowSnapshotHome) {
         for (int i = tasks.size() - 1; i >= 0; i--) {
             final Task task = tasks.valueAt(i);
-            final int mode = getSnapshotMode(task);
             final TaskSnapshot snapshot;
-            switch (mode) {
-                case SNAPSHOT_MODE_NONE:
-                    continue;
-                case SNAPSHOT_MODE_APP_THEME:
-                    snapshot = drawAppThemeSnapshot(task);
-                    break;
-                case SNAPSHOT_MODE_REAL:
-                    snapshot = snapshotTask(task);
-                    break;
-                default:
-                    snapshot = null;
-                    break;
+            final boolean snapshotHome = allowSnapshotHome && task.isActivityTypeHome();
+            if (snapshotHome) {
+                snapshot = snapshotTask(task);
+            } else {
+                switch (getSnapshotMode(task)) {
+                    case SNAPSHOT_MODE_NONE:
+                        continue;
+                    case SNAPSHOT_MODE_APP_THEME:
+                        snapshot = drawAppThemeSnapshot(task);
+                        break;
+                    case SNAPSHOT_MODE_REAL:
+                        snapshot = snapshotTask(task);
+                        break;
+                    default:
+                        snapshot = null;
+                        break;
+                }
             }
             if (snapshot != null) {
                 final GraphicBuffer buffer = snapshot.getSnapshot();
@@ -196,8 +204,11 @@
                             + buffer.getHeight());
                 } else {
                     mCache.putSnapshot(task, snapshot);
-                    mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
-                    task.onSnapshotChanged(snapshot);
+                    // Don't persist or notify the change for the temporal snapshot.
+                    if (!snapshotHome) {
+                        mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
+                        task.onSnapshotChanged(snapshot);
+                    }
                 }
             }
         }
@@ -450,6 +461,10 @@
         mPersister.onTaskRemovedFromRecents(taskId, userId);
     }
 
+    void removeSnapshotCache(int taskId) {
+        mCache.removeRunningEntry(taskId);
+    }
+
     /**
      * See {@link TaskSnapshotPersister#removeObsoleteFiles}
      */
@@ -485,7 +500,9 @@
                             mTmpTasks.add(task);
                         }
                     });
-                    snapshotTasks(mTmpTasks);
+                    // Allow taking snapshot of home when turning screen off to reduce the delay of
+                    // unlocking/waking to home.
+                    snapshotTasks(mTmpTasks, true /* allowSnapshotHome */);
                 }
             } finally {
                 listener.onScreenOff();