Merge "Port IME tasksnapshot over to shell transitions" into sc-v2-dev am: 4097e44f2a

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15819924

Change-Id: I1ee4e3f23de9ee715f3171caa634863ccfe3eb08
This commit is contained in:
Evan Rosky
2021-10-08 18:49:44 +00:00
committed by Automerger Merge Worker
7 changed files with 154 additions and 44 deletions

View File

@@ -4890,8 +4890,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* @param visible {@code true} if this {@link ActivityRecord} should become visible, otherwise
* this should become invisible.
* @param performLayout if {@code true}, perform surface placement after committing visibility.
* @param fromTransition {@code true} if this is part of finishing a transition.
*/
void commitVisibility(boolean visible, boolean performLayout) {
void commitVisibility(boolean visible, boolean performLayout, boolean fromTransition) {
// Reset the state of mVisibleSetFromTransferredStartingWindow since visibility is actually
// been set by the app now.
mVisibleSetFromTransferredStartingWindow = false;
@@ -4941,7 +4942,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
mUseTransferredAnimation = false;
postApplyAnimation(visible);
postApplyAnimation(visible, fromTransition);
}
void commitVisibility(boolean visible, boolean performLayout) {
commitVisibility(visible, performLayout, false /* fromTransition */);
}
/**
@@ -4952,8 +4957,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
*
* @param visible {@code true} if this {@link ActivityRecord} has become visible, otherwise
* this has become invisible.
* @param fromTransition {@code true} if this call is part of finishing a transition. This is
* needed because the shell transition is no-longer active by the time
* commitVisibility is called.
*/
private void postApplyAnimation(boolean visible) {
private void postApplyAnimation(boolean visible, boolean fromTransition) {
final boolean usingShellTransitions = mTransitionController.isShellTransitionsEnabled();
final boolean delayed = isAnimating(TRANSITION | PARENTS | CHILDREN,
ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION
@@ -4994,7 +5002,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final DisplayContent displayContent = getDisplayContent();
if (!displayContent.mClosingApps.contains(this)
&& !displayContent.mOpeningApps.contains(this)) {
&& !displayContent.mOpeningApps.contains(this)
&& !fromTransition) {
// Take the screenshot before possibly hiding the WSA, otherwise the screenshot
// will not be taken.
mWmService.mTaskSnapshotController.notifyAppVisibilityChanged(this, visible);

View File

@@ -991,6 +991,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
synchronized (mGlobalLock) {
mWindowManager = wm;
mRootWindowContainer = wm.mRoot;
mWindowOrganizerController.setWindowManager(wm);
mTempConfig.setToDefaults();
mTempConfig.setLocales(LocaleList.getDefault());
mConfigurationSeq = mTempConfig.seq = 1;

View File

@@ -178,43 +178,46 @@ class TaskSnapshotController {
snapshotTasks(tasks, false /* allowSnapshotHome */);
}
void recordTaskSnapshot(Task task, boolean allowSnapshotHome) {
final TaskSnapshot snapshot;
final boolean snapshotHome = allowSnapshotHome && task.isActivityTypeHome();
if (snapshotHome) {
snapshot = snapshotTask(task);
} else {
switch (getSnapshotMode(task)) {
case SNAPSHOT_MODE_NONE:
return;
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 HardwareBuffer buffer = snapshot.getHardwareBuffer();
if (buffer.getWidth() == 0 || buffer.getHeight() == 0) {
buffer.close();
Slog.e(TAG, "Invalid task snapshot dimensions " + buffer.getWidth() + "x"
+ buffer.getHeight());
} else {
mCache.putSnapshot(task, snapshot);
// Don't persist or notify the change for the temporal snapshot.
if (!snapshotHome) {
mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
task.onSnapshotChanged(snapshot);
}
}
}
}
private void snapshotTasks(ArraySet<Task> tasks, boolean allowSnapshotHome) {
for (int i = tasks.size() - 1; i >= 0; i--) {
final Task task = tasks.valueAt(i);
final TaskSnapshot snapshot;
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 HardwareBuffer buffer = snapshot.getHardwareBuffer();
if (buffer.getWidth() == 0 || buffer.getHeight() == 0) {
buffer.close();
Slog.e(TAG, "Invalid task snapshot dimensions " + buffer.getWidth() + "x"
+ buffer.getHeight());
} else {
mCache.putSnapshot(task, snapshot);
// Don't persist or notify the change for the temporal snapshot.
if (!snapshotHome) {
mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
task.onSnapshotChanged(snapshot);
}
}
}
recordTaskSnapshot(tasks.valueAt(i), allowSnapshotHome);
}
}

View File

@@ -415,7 +415,16 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
if (commitVisibility) {
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
" Commit activity becoming invisible: %s", ar);
ar.commitVisibility(false /* visible */, false /* performLayout */);
final Task task = ar.getTask();
if (task != null && !task.isVisibleRequested()
&& mTransientLaunches != null) {
// If transition is transient, then snapshots are taken at end of
// transition.
mController.mTaskSnapshotController.recordTaskSnapshot(
task, false /* allowSnapshotHome */);
}
ar.commitVisibility(false /* visible */, false /* performLayout */,
true /* fromTransition */);
activitiesWentInvisible = true;
}
}
@@ -558,6 +567,19 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
mVisibleAtTransitionEndTokens.add(wc.asWindowToken());
}
// Take task snapshots before the animation so that we can capture IME before it gets
// transferred. If transition is transient, IME won't be moved during the transition and
// the tasks are still live, so we take the snapshot at the end of the transition instead.
if (mTransientLaunches == null) {
for (int i = mParticipants.size() - 1; i >= 0; --i) {
final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord();
if (ar == null || ar.isVisibleRequested() || ar.getTask() == null
|| ar.getTask().isVisibleRequested()) continue;
mController.mTaskSnapshotController.recordTaskSnapshot(
ar.getTask(), false /* allowSnapshotHome */);
}
}
mStartTransaction = transaction;
mFinishTransaction = mController.mAtm.mWindowManager.mTransactionFactory.get();
buildFinishTransaction(mFinishTransaction, info.getRootLeash());

View File

@@ -59,6 +59,7 @@ class TransitionController {
private ITransitionPlayer mTransitionPlayer;
final ActivityTaskManagerService mAtm;
final TaskSnapshotController mTaskSnapshotController;
private final ArrayList<WindowManagerInternal.AppTransitionListener> mLegacyListeners =
new ArrayList<>();
@@ -79,9 +80,11 @@ class TransitionController {
// TODO(b/188595497): remove when not needed.
final StatusBarManagerInternal mStatusBar;
TransitionController(ActivityTaskManagerService atm) {
TransitionController(ActivityTaskManagerService atm,
TaskSnapshotController taskSnapshotController) {
mAtm = atm;
mStatusBar = LocalServices.getService(StatusBarManagerInternal.class);
mTaskSnapshotController = taskSnapshotController;
mTransitionPlayerDeath = () -> {
synchronized (mAtm.mGlobalLock) {
// Clean-up/finish any playing transitions.

View File

@@ -117,7 +117,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final DisplayAreaOrganizerController mDisplayAreaOrganizerController;
final TaskFragmentOrganizerController mTaskFragmentOrganizerController;
final TransitionController mTransitionController;
TransitionController mTransitionController;
/**
* A Map which manages the relationship between
* {@link TaskFragmentCreationParams#getFragmentToken()} and {@link TaskFragment}
@@ -131,7 +131,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
mTaskOrganizerController = new TaskOrganizerController(mService);
mDisplayAreaOrganizerController = new DisplayAreaOrganizerController(mService);
mTaskFragmentOrganizerController = new TaskFragmentOrganizerController(atm);
mTransitionController = new TransitionController(atm);
}
void setWindowManager(WindowManagerService wms) {
mTransitionController = new TransitionController(mService, wms.mTaskSnapshotController);
}
TransitionController getTransitionController() {

View File

@@ -34,8 +34,11 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
@@ -448,7 +451,8 @@ public class TransitionTests extends WindowTestsBase {
@Test
public void testIntermediateVisibility() {
final TransitionController controller = new TransitionController(mAtm);
final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class);
final TransitionController controller = new TransitionController(mAtm, snapshotController);
final ITransitionPlayer player = new ITransitionPlayer.Default();
controller.registerTransitionPlayer(player);
ITaskOrganizer mockOrg = mock(ITaskOrganizer.class);
@@ -511,6 +515,71 @@ public class TransitionTests extends WindowTestsBase {
assertTrue(activity2.isVisible());
}
@Test
public void testTransientLaunch() {
final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class);
final TransitionController controller = new TransitionController(mAtm, snapshotController);
final ITransitionPlayer player = new ITransitionPlayer.Default();
controller.registerTransitionPlayer(player);
ITaskOrganizer mockOrg = mock(ITaskOrganizer.class);
final Transition openTransition = controller.createTransition(TRANSIT_OPEN);
// Start out with task2 visible and set up a transition that closes task2 and opens task1
final Task task1 = createTask(mDisplayContent);
task1.mTaskOrganizer = mockOrg;
final ActivityRecord activity1 = createActivityRecord(task1);
activity1.mVisibleRequested = false;
activity1.setVisible(false);
final Task task2 = createTask(mDisplayContent);
task2.mTaskOrganizer = mockOrg;
final ActivityRecord activity2 = createActivityRecord(task2);
activity2.mVisibleRequested = true;
activity2.setVisible(true);
openTransition.collectExistenceChange(task1);
openTransition.collectExistenceChange(activity1);
openTransition.collectExistenceChange(task2);
openTransition.collectExistenceChange(activity2);
activity1.mVisibleRequested = true;
activity1.setVisible(true);
activity2.mVisibleRequested = false;
// Using abort to force-finish the sync (since we can't wait for drawing in unit test).
// We didn't call abort on the transition itself, so it will still run onTransactionReady
// normally.
mWm.mSyncEngine.abort(openTransition.getSyncId());
verify(snapshotController, times(1)).recordTaskSnapshot(eq(task2), eq(false));
openTransition.finishTransition();
// We are now going to simulate closing task1 to return back to (open) task2.
final Transition closeTransition = controller.createTransition(TRANSIT_CLOSE);
closeTransition.collectExistenceChange(task1);
closeTransition.collectExistenceChange(activity1);
closeTransition.collectExistenceChange(task2);
closeTransition.collectExistenceChange(activity2);
closeTransition.setTransientLaunch(activity2);
activity1.mVisibleRequested = false;
activity2.mVisibleRequested = true;
// Using abort to force-finish the sync (since we obviously can't wait for drawing).
// We didn't call abort on the actual transition, so it will still run onTransactionReady
// normally.
mWm.mSyncEngine.abort(closeTransition.getSyncId());
// Make sure we haven't called recordSnapshot (since we are transient, it shouldn't be
// called until finish).
verify(snapshotController, times(0)).recordTaskSnapshot(eq(task1), eq(false));
closeTransition.finishTransition();
verify(snapshotController, times(1)).recordTaskSnapshot(eq(task1), eq(false));
}
/** Fill the change map with all the parents of top. Change maps are usually fully populated */
private static void fillChangeMap(ArrayMap<WindowContainer, Transition.ChangeInfo> changes,
WindowContainer top) {