Add a listener when task snapshots change
Since we start recents before we take the snapshot, we need to add
a mechanism to inform recents about task snapshots changes.
We add a new method to TaskStackChangedListener,
onTaskSnapshotChanged, which gets called whenever a task snapshot
changes. Then, SystemUI registers such a listener and updates the
task thumbnail view for the specific task.
Test: Open app, press recents, make sure thumbnail is up-to-date
Bug: 31339431
Change-Id: I01e81b9cd11886da734da671c68d5732aa51009f
diff --git a/services/core/java/com/android/server/am/TaskChangeNotificationController.java b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
index cb20eac..d035fa9 100644
--- a/services/core/java/com/android/server/am/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
@@ -16,6 +16,8 @@
package com.android.server.am;
+import android.app.ActivityManager;
+import android.app.ActivityManager.TaskSnapshot;
import android.app.ITaskStackListener;
import android.app.ActivityManager.TaskDescription;
import android.content.ComponentName;
@@ -43,6 +45,7 @@
static final int NOTIFY_ACTIVITY_REQUESTED_ORIENTATION_CHANGED_LISTENERS = 12;
static final int NOTIFY_TASK_REMOVAL_STARTED_LISTENERS = 13;
static final int NOTIFY_TASK_PROFILE_LOCKED_LISTENERS_MSG = 14;
+ static final int NOTIFY_TASK_SNAPSHOT_CHANGED_LISTENERS_MSG = 15;
// Delay in notifying task stack change listeners (in millis)
static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
@@ -113,6 +116,10 @@
l.onTaskProfileLocked(m.arg1, m.arg2);
};
+ private final TaskStackConsumer mNotifyTaskSnapshotChanged = (l, m) -> {
+ l.onTaskSnapshotChanged(m.arg1, (TaskSnapshot) m.obj);
+ };
+
@FunctionalInterface
public interface TaskStackConsumer {
void accept(ITaskStackListener t, Message m) throws RemoteException;
@@ -170,7 +177,9 @@
break;
case NOTIFY_TASK_PROFILE_LOCKED_LISTENERS_MSG:
forAllRemoteListeners(mNotifyTaskProfileLocked, msg);
-
+ break;
+ case NOTIFY_TASK_SNAPSHOT_CHANGED_LISTENERS_MSG:
+ forAllRemoteListeners(mNotifyTaskSnapshotChanged, msg);
break;
}
}
@@ -348,4 +357,14 @@
forAllLocalListeners(mNotifyTaskProfileLocked, msg);
msg.sendToTarget();
}
+
+ /**
+ * Notify listeners that the snapshot of a task has changed.
+ */
+ void notifyTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) {
+ final Message msg = mHandler.obtainMessage(NOTIFY_TASK_SNAPSHOT_CHANGED_LISTENERS_MSG,
+ taskId, 0, snapshot);
+ forAllLocalListeners(mNotifyTaskSnapshotChanged, msg);
+ msg.sendToTarget();
+ }
}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 9e22c50..c3f657e 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -52,6 +52,8 @@
import com.android.internal.util.XmlUtils;
import com.android.server.wm.TaskWindowContainerController;
+import com.android.server.wm.TaskWindowContainerListener;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -103,7 +105,7 @@
import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
-final class TaskRecord extends ConfigurationContainer {
+final class TaskRecord extends ConfigurationContainer implements TaskWindowContainerListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
@@ -410,8 +412,8 @@
final Rect bounds = updateOverrideConfigurationFromLaunchBounds();
final Configuration overrideConfig = getOverrideConfiguration();
- mWindowContainerController = new TaskWindowContainerController(taskId, getStackId(), userId,
- bounds, overrideConfig, mResizeMode, isHomeTask(), isOnTopLauncher(), onTop,
+ mWindowContainerController = new TaskWindowContainerController(taskId, this, getStackId(),
+ userId, bounds, overrideConfig, mResizeMode, isHomeTask(), isOnTopLauncher(), onTop,
showForAllUsers);
}
@@ -427,6 +429,11 @@
mWindowContainerController = null;
}
+ @Override
+ public void onSnapshotChanged(TaskSnapshot snapshot) {
+ mService.mTaskChangeNotificationController.notifyTaskSnapshotChanged(taskId, snapshot);
+ }
+
void setResizeMode(int resizeMode) {
if (mResizeMode == resizeMode) {
return;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index b1b7542..f3196b1 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -639,6 +639,10 @@
return mFillsParent || !StackId.isTaskResizeAllowed(mStack.mStackId);
}
+ TaskWindowContainerController getController() {
+ return (TaskWindowContainerController) super.getController();
+ }
+
@Override
public String toString() {
return "{taskId=" + mTaskId + " appTokens=" + mChildren + " mdr=" + mDeferRemoval + "}";
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index efa72a6..bce2099 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -17,17 +17,10 @@
package com.android.server.wm;
import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS;
-import static android.graphics.Bitmap.Config.ARGB_8888;
-import static android.graphics.GraphicBuffer.USAGE_HW_TEXTURE;
-import static android.graphics.GraphicBuffer.USAGE_SW_READ_NEVER;
-import static android.graphics.GraphicBuffer.USAGE_SW_WRITE_NEVER;
-import static android.graphics.PixelFormat.RGBA_8888;
import android.annotation.Nullable;
import android.app.ActivityManager.StackId;
import android.app.ActivityManager.TaskSnapshot;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.GraphicBuffer;
import android.util.ArraySet;
import android.view.WindowManagerPolicy.StartingSurface;
@@ -76,6 +69,9 @@
final TaskSnapshot snapshot = snapshotTask(task);
if (snapshot != null) {
mCache.putSnapshot(task, snapshot);
+ if (task.getController() != null) {
+ task.getController().reportSnapshotChanged(snapshot);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerController.java b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
index 0e4d048..75b3f3e 100644
--- a/services/core/java/com/android/server/wm/TaskWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
@@ -18,8 +18,10 @@
import android.app.ActivityManager.TaskSnapshot;
import android.content.res.Configuration;
-import android.graphics.GraphicBuffer;
import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.util.EventLog;
import android.util.Slog;
@@ -37,14 +39,28 @@
* Test class: {@link TaskWindowContainerControllerTests}
*/
public class TaskWindowContainerController
- extends WindowContainerController<Task, WindowContainerListener> {
+ extends WindowContainerController<Task, TaskWindowContainerListener> {
+
+ private static final int REPORT_SNAPSHOT_CHANGED = 0;
private final int mTaskId;
- public TaskWindowContainerController(int taskId, int stackId, int userId, Rect bounds,
- Configuration overrideConfig, int resizeMode, boolean homeTask, boolean isOnTopLauncher,
- boolean toTop, boolean showForAllUsers) {
- super(null, WindowManagerService.getInstance());
+ private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case REPORT_SNAPSHOT_CHANGED:
+ mListener.onSnapshotChanged((TaskSnapshot) msg.obj);
+ break;
+ }
+ }
+ };
+
+ public TaskWindowContainerController(int taskId, TaskWindowContainerListener listener,
+ int stackId, int userId, Rect bounds, Configuration overrideConfig, int resizeMode,
+ boolean homeTask, boolean isOnTopLauncher, boolean toTop, boolean showForAllUsers) {
+ super(listener, WindowManagerService.getInstance());
mTaskId = taskId;
synchronized(mWindowMap) {
@@ -253,6 +269,10 @@
}
}
+ void reportSnapshotChanged(TaskSnapshot snapshot) {
+ mHandler.obtainMessage(REPORT_SNAPSHOT_CHANGED, snapshot).sendToTarget();
+ }
+
@Override
public String toString() {
return "{TaskWindowContainerController taskId=" + mTaskId + "}";
diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerListener.java b/services/core/java/com/android/server/wm/TaskWindowContainerListener.java
new file mode 100644
index 0000000..61b202d
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskWindowContainerListener.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 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.server.wm;
+
+import android.app.ActivityManager.TaskSnapshot;
+
+/**
+ * Interface used by the creator of the controller to listen to changes with the container.
+ */
+public interface TaskWindowContainerListener extends WindowContainerListener {
+
+ /**
+ * Called when the snapshot of this task has changed.
+ */
+ void onSnapshotChanged(TaskSnapshot snapshot);
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b04ff42..9d945f0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -235,6 +235,8 @@
import java.util.HashMap;
import java.util.List;
+import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
+import static android.Manifest.permission.READ_FRAME_BUFFER;
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
@@ -3854,7 +3856,7 @@
@Override
public Bitmap screenshotWallpaper() {
- if (!checkCallingPermission(Manifest.permission.READ_FRAME_BUFFER,
+ if (!checkCallingPermission(READ_FRAME_BUFFER,
"screenshotWallpaper()")) {
throw new SecurityException("Requires READ_FRAME_BUFFER permission");
}
@@ -3876,7 +3878,7 @@
*/
@Override
public boolean requestAssistScreenshot(final IAssistScreenshotReceiver receiver) {
- if (!checkCallingPermission(Manifest.permission.READ_FRAME_BUFFER,
+ if (!checkCallingPermission(READ_FRAME_BUFFER,
"requestAssistScreenshot()")) {
throw new SecurityException("Requires READ_FRAME_BUFFER permission");
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 466bd67..25f2c6e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -19,6 +19,8 @@
import org.junit.Assert;
import org.junit.Before;
+import android.app.ActivityManager;
+import android.app.ActivityManager.TaskSnapshot;
import android.content.Context;
import android.os.IBinder;
import android.support.test.InstrumentationRegistry;
@@ -208,7 +210,7 @@
class TestTaskWindowContainerController extends TaskWindowContainerController {
TestTaskWindowContainerController(int stackId) {
- super(sNextTaskId++, stackId, 0 /* userId */, null /* bounds */,
+ super(sNextTaskId++, snapshot -> {}, stackId, 0 /* userId */, null /* bounds */,
EMPTY /* overrideConfig*/, RESIZE_MODE_UNRESIZEABLE, false /* homeTask*/,
false /* isOnTopLauncher */, true /* toTop*/, true /* showForAllUsers */);
}