Loading services/core/java/com/android/server/wm/BackNavigationController.java +12 −21 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import android.graphics.Point; import android.graphics.Rect; import android.hardware.HardwareBuffer; Loading @@ -41,7 +40,6 @@ import android.window.BackAnimationAdapter; import android.window.BackNavigationInfo; import android.window.IBackAnimationFinishedCallback; import android.window.OnBackInvokedCallbackInfo; import android.window.ScreenCapture; import android.window.TaskSnapshot; import android.window.WindowContainerToken; Loading Loading @@ -269,10 +267,11 @@ class BackNavigationController { removedWindowContainer, BackNavigationInfo.typeToString(backType)); // For now, we only animate when going home and cross task. // For now, we only animate when going home, cross task or cross-activity. boolean prepareAnimation = (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME || backType == BackNavigationInfo.TYPE_CROSS_TASK) || backType == BackNavigationInfo.TYPE_CROSS_TASK || backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) && adapter != null; // Only prepare animation if no leash has been created (no animation is running). Loading Loading @@ -336,6 +335,7 @@ class BackNavigationController { RemoteAnimationTarget behindAppTarget = null; if (needsScreenshot(backType)) { HardwareBuffer screenshotBuffer = null; Task backTargetTask = prevTask; switch(backType) { case BackNavigationInfo.TYPE_CROSS_TASK: int prevTaskId = prevTask != null ? prevTask.mTaskId : 0; Loading @@ -343,14 +343,10 @@ class BackNavigationController { screenshotBuffer = getTaskSnapshot(prevTaskId, prevUserId); break; case BackNavigationInfo.TYPE_CROSS_ACTIVITY: //TODO(207481538) Remove once the infrastructure to support per-activity // screenshot is implemented. For now we simply have the mBackScreenshots hash // map that dumbly saves the screenshots. if (prevActivity != null && prevActivity.mActivityComponent != null) { screenshotBuffer = getActivitySnapshot(currentTask, prevActivity.mActivityComponent); if (prevActivity != null && prevActivity.mActivityComponent != null) { screenshotBuffer = getActivitySnapshot(currentTask, prevActivity); } backTargetTask = currentTask; break; } Loading @@ -369,8 +365,9 @@ class BackNavigationController { // leash needs to be added before to be in the synchronized block. startedTransaction.setLayer(topAppTarget.leash, 1); behindAppTarget = createRemoteAnimationTargetLocked( prevTask, screenshotSurface, MODE_OPENING); behindAppTarget = createRemoteAnimationTargetLocked( backTargetTask, screenshotSurface, MODE_OPENING); // reset leash after animation finished. leashes.add(screenshotSurface); Loading Loading @@ -543,14 +540,8 @@ class BackNavigationController { mShowWallpaper = false; } private HardwareBuffer getActivitySnapshot(@NonNull Task task, ComponentName activityComponent) { // Check if we have a screenshot of the previous activity, indexed by its // component name. ScreenCapture.ScreenshotHardwareBuffer backBuffer = task.mBackScreenshots .get(activityComponent.flattenToString()); return backBuffer != null ? backBuffer.getHardwareBuffer() : null; private HardwareBuffer getActivitySnapshot(@NonNull Task task, ActivityRecord r) { return task.getSnapshotForActivityRecord(r); } private HardwareBuffer getTaskSnapshot(int taskId, int userId) { Loading services/core/java/com/android/server/wm/TaskFragment.java +14 −1 Original line number Diff line number Diff line Loading @@ -79,6 +79,7 @@ import android.app.servertransaction.ResumeActivityItem; import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; import android.hardware.HardwareBuffer; import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; Loading Loading @@ -1859,7 +1860,6 @@ class TaskFragment extends WindowContainer<WindowContainer> { super.addChild(child, index); if (isAddingActivity && task != null) { // TODO(b/207481538): temporary per-activity screenshoting if (r != null && BackNavigationController.isScreenshotEnabled()) { ProtoLog.v(WM_DEBUG_BACK_PREVIEW, "Screenshotting Activity %s", Loading Loading @@ -2528,6 +2528,19 @@ class TaskFragment extends WindowContainer<WindowContainer> { return !mCreatedByOrganizer || mIsRemovalRequested; } @Nullable HardwareBuffer getSnapshotForActivityRecord(@Nullable ActivityRecord r) { if (!BackNavigationController.isScreenshotEnabled()) { return null; } if (r != null && r.mActivityComponent != null) { ScreenCapture.ScreenshotHardwareBuffer backBuffer = mBackScreenshots.get(r.mActivityComponent.flattenToString()); return backBuffer != null ? backBuffer.getHardwareBuffer() : null; } return null; } @Override void removeChild(WindowContainer child) { removeChild(child, true /* removeSelfIfPossible */); Loading services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java +38 −8 Original line number Diff line number Diff line Loading @@ -115,18 +115,14 @@ public class BackNavigationControllerTests extends WindowTestsBase { @Test public void backTypeCrossActivityWhenBackToPreviousActivity() { Task task = createTopTaskWithActivity(); WindowState window = createAppWindow(task, FIRST_APPLICATION_WINDOW, "window"); addToWindowMap(window, true); IOnBackInvokedCallback callback = createOnBackInvokedCallback(); window.setOnBackInvokedCallbackInfo( new OnBackInvokedCallbackInfo(callback, OnBackInvokedDispatcher.PRIORITY_SYSTEM)); CrossActivityTestCase testCase = createTopTaskWithTwoActivities(); IOnBackInvokedCallback callback = withSystemCallback(testCase.task); BackNavigationInfo backNavigationInfo = startBackNavigation(); assertWithMessage("BackNavigationInfo").that(backNavigationInfo).isNotNull(); assertThat(backNavigationInfo.getOnBackInvokedCallback()).isEqualTo(callback); assertThat(typeToString(backNavigationInfo.getType())) .isEqualTo(typeToString(BackNavigationInfo.TYPE_CROSS_ACTIVITY)); assertWithMessage("Activity callback").that( backNavigationInfo.getOnBackInvokedCallback()).isEqualTo(callback); } @Test Loading Loading @@ -302,6 +298,34 @@ public class BackNavigationControllerTests extends WindowTestsBase { return task; } @NonNull private CrossActivityTestCase createTopTaskWithTwoActivities() { Task task = createTask(mDefaultDisplay); ActivityRecord record1 = createActivityRecord(task); ActivityRecord record2 = createActivityRecord(task); // enable OnBackInvokedCallbacks record2.info.applicationInfo.privateFlagsExt |= PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK; WindowState window1 = createWindow(null, FIRST_APPLICATION_WINDOW, record1, "window1"); WindowState window2 = createWindow(null, FIRST_APPLICATION_WINDOW, record2, "window2"); when(task.mSurfaceControl.isValid()).thenReturn(true); when(record1.mSurfaceControl.isValid()).thenReturn(true); when(record2.mSurfaceControl.isValid()).thenReturn(true); Mockito.doNothing().when(task).reparentSurfaceControl(any(), any()); Mockito.doNothing().when(record1).reparentSurfaceControl(any(), any()); Mockito.doNothing().when(record2).reparentSurfaceControl(any(), any()); mAtm.setFocusedTask(task.mTaskId, record1); mAtm.setFocusedTask(task.mTaskId, record2); addToWindowMap(window1, true); addToWindowMap(window2, true); CrossActivityTestCase testCase = new CrossActivityTestCase(); testCase.task = task; testCase.recordBack = record1; testCase.recordFront = record2; return testCase; } private void addToWindowMap(WindowState window, boolean focus) { mWm.mWindowMap.put(window.mClient.asBinder(), window); if (focus) { Loading @@ -310,4 +334,10 @@ public class BackNavigationControllerTests extends WindowTestsBase { doReturn(window).when(mWm).getFocusedWindowLocked(); } } private class CrossActivityTestCase { public Task task; public ActivityRecord recordBack; public ActivityRecord recordFront; } } Loading
services/core/java/com/android/server/wm/BackNavigationController.java +12 −21 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import android.graphics.Point; import android.graphics.Rect; import android.hardware.HardwareBuffer; Loading @@ -41,7 +40,6 @@ import android.window.BackAnimationAdapter; import android.window.BackNavigationInfo; import android.window.IBackAnimationFinishedCallback; import android.window.OnBackInvokedCallbackInfo; import android.window.ScreenCapture; import android.window.TaskSnapshot; import android.window.WindowContainerToken; Loading Loading @@ -269,10 +267,11 @@ class BackNavigationController { removedWindowContainer, BackNavigationInfo.typeToString(backType)); // For now, we only animate when going home and cross task. // For now, we only animate when going home, cross task or cross-activity. boolean prepareAnimation = (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME || backType == BackNavigationInfo.TYPE_CROSS_TASK) || backType == BackNavigationInfo.TYPE_CROSS_TASK || backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) && adapter != null; // Only prepare animation if no leash has been created (no animation is running). Loading Loading @@ -336,6 +335,7 @@ class BackNavigationController { RemoteAnimationTarget behindAppTarget = null; if (needsScreenshot(backType)) { HardwareBuffer screenshotBuffer = null; Task backTargetTask = prevTask; switch(backType) { case BackNavigationInfo.TYPE_CROSS_TASK: int prevTaskId = prevTask != null ? prevTask.mTaskId : 0; Loading @@ -343,14 +343,10 @@ class BackNavigationController { screenshotBuffer = getTaskSnapshot(prevTaskId, prevUserId); break; case BackNavigationInfo.TYPE_CROSS_ACTIVITY: //TODO(207481538) Remove once the infrastructure to support per-activity // screenshot is implemented. For now we simply have the mBackScreenshots hash // map that dumbly saves the screenshots. if (prevActivity != null && prevActivity.mActivityComponent != null) { screenshotBuffer = getActivitySnapshot(currentTask, prevActivity.mActivityComponent); if (prevActivity != null && prevActivity.mActivityComponent != null) { screenshotBuffer = getActivitySnapshot(currentTask, prevActivity); } backTargetTask = currentTask; break; } Loading @@ -369,8 +365,9 @@ class BackNavigationController { // leash needs to be added before to be in the synchronized block. startedTransaction.setLayer(topAppTarget.leash, 1); behindAppTarget = createRemoteAnimationTargetLocked( prevTask, screenshotSurface, MODE_OPENING); behindAppTarget = createRemoteAnimationTargetLocked( backTargetTask, screenshotSurface, MODE_OPENING); // reset leash after animation finished. leashes.add(screenshotSurface); Loading Loading @@ -543,14 +540,8 @@ class BackNavigationController { mShowWallpaper = false; } private HardwareBuffer getActivitySnapshot(@NonNull Task task, ComponentName activityComponent) { // Check if we have a screenshot of the previous activity, indexed by its // component name. ScreenCapture.ScreenshotHardwareBuffer backBuffer = task.mBackScreenshots .get(activityComponent.flattenToString()); return backBuffer != null ? backBuffer.getHardwareBuffer() : null; private HardwareBuffer getActivitySnapshot(@NonNull Task task, ActivityRecord r) { return task.getSnapshotForActivityRecord(r); } private HardwareBuffer getTaskSnapshot(int taskId, int userId) { Loading
services/core/java/com/android/server/wm/TaskFragment.java +14 −1 Original line number Diff line number Diff line Loading @@ -79,6 +79,7 @@ import android.app.servertransaction.ResumeActivityItem; import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; import android.hardware.HardwareBuffer; import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; Loading Loading @@ -1859,7 +1860,6 @@ class TaskFragment extends WindowContainer<WindowContainer> { super.addChild(child, index); if (isAddingActivity && task != null) { // TODO(b/207481538): temporary per-activity screenshoting if (r != null && BackNavigationController.isScreenshotEnabled()) { ProtoLog.v(WM_DEBUG_BACK_PREVIEW, "Screenshotting Activity %s", Loading Loading @@ -2528,6 +2528,19 @@ class TaskFragment extends WindowContainer<WindowContainer> { return !mCreatedByOrganizer || mIsRemovalRequested; } @Nullable HardwareBuffer getSnapshotForActivityRecord(@Nullable ActivityRecord r) { if (!BackNavigationController.isScreenshotEnabled()) { return null; } if (r != null && r.mActivityComponent != null) { ScreenCapture.ScreenshotHardwareBuffer backBuffer = mBackScreenshots.get(r.mActivityComponent.flattenToString()); return backBuffer != null ? backBuffer.getHardwareBuffer() : null; } return null; } @Override void removeChild(WindowContainer child) { removeChild(child, true /* removeSelfIfPossible */); Loading
services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java +38 −8 Original line number Diff line number Diff line Loading @@ -115,18 +115,14 @@ public class BackNavigationControllerTests extends WindowTestsBase { @Test public void backTypeCrossActivityWhenBackToPreviousActivity() { Task task = createTopTaskWithActivity(); WindowState window = createAppWindow(task, FIRST_APPLICATION_WINDOW, "window"); addToWindowMap(window, true); IOnBackInvokedCallback callback = createOnBackInvokedCallback(); window.setOnBackInvokedCallbackInfo( new OnBackInvokedCallbackInfo(callback, OnBackInvokedDispatcher.PRIORITY_SYSTEM)); CrossActivityTestCase testCase = createTopTaskWithTwoActivities(); IOnBackInvokedCallback callback = withSystemCallback(testCase.task); BackNavigationInfo backNavigationInfo = startBackNavigation(); assertWithMessage("BackNavigationInfo").that(backNavigationInfo).isNotNull(); assertThat(backNavigationInfo.getOnBackInvokedCallback()).isEqualTo(callback); assertThat(typeToString(backNavigationInfo.getType())) .isEqualTo(typeToString(BackNavigationInfo.TYPE_CROSS_ACTIVITY)); assertWithMessage("Activity callback").that( backNavigationInfo.getOnBackInvokedCallback()).isEqualTo(callback); } @Test Loading Loading @@ -302,6 +298,34 @@ public class BackNavigationControllerTests extends WindowTestsBase { return task; } @NonNull private CrossActivityTestCase createTopTaskWithTwoActivities() { Task task = createTask(mDefaultDisplay); ActivityRecord record1 = createActivityRecord(task); ActivityRecord record2 = createActivityRecord(task); // enable OnBackInvokedCallbacks record2.info.applicationInfo.privateFlagsExt |= PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK; WindowState window1 = createWindow(null, FIRST_APPLICATION_WINDOW, record1, "window1"); WindowState window2 = createWindow(null, FIRST_APPLICATION_WINDOW, record2, "window2"); when(task.mSurfaceControl.isValid()).thenReturn(true); when(record1.mSurfaceControl.isValid()).thenReturn(true); when(record2.mSurfaceControl.isValid()).thenReturn(true); Mockito.doNothing().when(task).reparentSurfaceControl(any(), any()); Mockito.doNothing().when(record1).reparentSurfaceControl(any(), any()); Mockito.doNothing().when(record2).reparentSurfaceControl(any(), any()); mAtm.setFocusedTask(task.mTaskId, record1); mAtm.setFocusedTask(task.mTaskId, record2); addToWindowMap(window1, true); addToWindowMap(window2, true); CrossActivityTestCase testCase = new CrossActivityTestCase(); testCase.task = task; testCase.recordBack = record1; testCase.recordFront = record2; return testCase; } private void addToWindowMap(WindowState window, boolean focus) { mWm.mWindowMap.put(window.mClient.asBinder(), window); if (focus) { Loading @@ -310,4 +334,10 @@ public class BackNavigationControllerTests extends WindowTestsBase { doReturn(window).when(mWm).getFocusedWindowLocked(); } } private class CrossActivityTestCase { public Task task; public ActivityRecord recordBack; public ActivityRecord recordFront; } }