diff options
| author | 2021-09-20 10:13:36 +0000 | |
|---|---|---|
| committer | 2021-09-20 10:13:36 +0000 | |
| commit | f061f27f16cf194a57f6e98dd347bdac90344077 (patch) | |
| tree | a381b4897fb26803801aad0f19047e2651e2cf86 | |
| parent | a8ecb944346561d363cb4e56314c75d76febbd39 (diff) | |
| parent | 494ce0751d7111e39949685be3e4a518a80ba564 (diff) | |
Merge "Include activity reparent in transition" into sc-v2-dev
5 files changed, 100 insertions, 12 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 946fa44d1f1c..dfb2f8ff8bc9 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1389,6 +1389,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return parent != null ? parent.asTaskFragment() : null; } + /** Whether we should prepare a transition for this {@link ActivityRecord} parent change. */ + private boolean shouldStartChangeTransition( + @Nullable TaskFragment newParent, @Nullable TaskFragment oldParent) { + if (mWmService.mDisableTransitionAnimation + || mDisplayContent == null || newParent == null || oldParent == null + || getSurfaceControl() == null || !isVisible() || !isVisibleRequested()) { + return false; + } + + // Transition change for the activity moving into a TaskFragment of different bounds. + return newParent.isOrganizedTaskFragment() + && !newParent.getBounds().equals(oldParent.getBounds()); + } + @Override void onParentChanged(ConfigurationContainer rawNewParent, ConfigurationContainer rawOldParent) { final TaskFragment oldParent = (TaskFragment) rawOldParent; @@ -1397,6 +1411,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final Task newTask = newParent != null ? newParent.getTask() : null; this.task = newTask; + if (shouldStartChangeTransition(newParent, oldParent)) { + initializeChangeTransition(getBounds()); + } + super.onParentChanged(newParent, oldParent); if (isPersistable()) { @@ -2607,6 +2625,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return parent != null ? parent.getOrganizedTaskFragment() : null; } + @Override boolean isEmbedded() { final TaskFragment parent = getTaskFragment(); return parent != null && parent.isEmbedded(); diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 7a42351c33c1..c0b69794966b 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -237,6 +237,8 @@ public class AppTransitionController { // Check if there is any override if (!overrideWithTaskFragmentRemoteAnimation(transit, activityTypes)) { + // Unfreeze the windows that were previously frozen for TaskFragment animation. + unfreezeEmbeddedChangingWindows(); overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes); } @@ -341,6 +343,9 @@ public class AppTransitionController { switch (changingType) { case TYPE_TASK: return TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE; + case TYPE_ACTIVITY: + // ActivityRecord is put in a change transition only when it is reparented + // to an organized TaskFragment. See ActivityRecord#shouldStartChangeTransition. case TYPE_TASK_FRAGMENT: return TRANSIT_OLD_TASK_FRAGMENT_CHANGE; default: @@ -511,6 +516,16 @@ public class AppTransitionController { : null; } + private void unfreezeEmbeddedChangingWindows() { + final ArraySet<WindowContainer> changingContainers = mDisplayContent.mChangingContainers; + for (int i = changingContainers.size() - 1; i >= 0; i--) { + final WindowContainer wc = changingContainers.valueAt(i); + if (wc.isEmbedded()) { + wc.mSurfaceFreezer.unfreeze(wc.getSyncTransaction()); + } + } + } + /** * Overrides the pending transition with the remote animation defined by the * {@link ITaskFragmentOrganizer} if all windows in the transition are children of diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index c8b8b0dd5a1d..584f7bf5e5b1 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -33,7 +33,6 @@ import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static android.os.UserHandle.USER_NULL; import static android.view.Display.INVALID_DISPLAY; -import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND; import static android.view.WindowManager.TRANSIT_NONE; @@ -465,7 +464,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { return this; } - /** Returns {@code true} if this is a container for embedded activities or tasks. */ + @Override boolean isEmbedded() { if (mIsEmbedded) { return true; @@ -2073,15 +2072,6 @@ class TaskFragment extends WindowContainer<WindowContainer> { return !startBounds.equals(getBounds()); } - /** - * Initializes a change transition. See {@link SurfaceFreezer} for more information. - */ - void initializeChangeTransition(Rect startBounds) { - mDisplayContent.prepareAppTransition(TRANSIT_CHANGE); - mDisplayContent.mChangingContainers.add(this); - mSurfaceFreezer.freeze(getSyncTransaction(), startBounds); - } - @Override void setSurfaceControl(SurfaceControl sc) { super.setSurfaceControl(sc); @@ -2163,6 +2153,11 @@ class TaskFragment extends WindowContainer<WindowContainer> { return mTaskFragmentOrganizer != null; } + /** Whether this is an organized {@link TaskFragment} and not a {@link Task}. */ + final boolean isOrganizedTaskFragment() { + return mTaskFragmentOrganizer != null; + } + /** Clear {@link #mLastPausedActivity} for all {@link TaskFragment} children */ void clearLastPausedActivity() { forAllTaskFragments(taskFragment -> taskFragment.mLastPausedActivity = null); diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index cdfa5aa84a95..0862d9bedde0 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -30,6 +30,7 @@ import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.os.UserHandle.USER_NULL; import static android.view.SurfaceControl.Transaction; import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE; +import static android.view.WindowManager.TRANSIT_CHANGE; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; @@ -2578,13 +2579,34 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< mSurfaceFreezer.unfreeze(getPendingTransaction()); } + /** + * Initializes a change transition. See {@link SurfaceFreezer} for more information. + * + * For now, this will only be called for the following cases: + * 1. {@link Task} is changing windowing mode between fullscreen and freeform. + * 2. {@link TaskFragment} is organized and is changing window bounds. + * 3. {@link ActivityRecord} is reparented into an organized {@link TaskFragment}. + * + * This shouldn't be called on other {@link WindowContainer} unless there is a valid use case. + */ + void initializeChangeTransition(Rect startBounds) { + mDisplayContent.prepareAppTransition(TRANSIT_CHANGE); + mDisplayContent.mChangingContainers.add(this); + mSurfaceFreezer.freeze(getSyncTransaction(), startBounds); + } + ArraySet<WindowContainer> getAnimationSources() { return mSurfaceAnimationSources; } @Override public SurfaceControl getFreezeSnapshotTarget() { - return null; + // Only allow freezing if this window is in a TRANSIT_CHANGE + if (!mDisplayContent.mAppTransition.containsTransitRequest(TRANSIT_CHANGE) + || !mDisplayContent.mChangingContainers.contains(this)) { + return null; + } + return getSurfaceControl(); } @Override @@ -3189,6 +3211,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< return false; } + /** @return {@code true} if this is a container for embedded activities or tasks. */ + boolean isEmbedded() { + return false; + } + /** * @return {@code true} if this container's surface should be shown when it is created. */ diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java index a0a3ce73265c..405d714256ab 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -43,6 +43,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import android.graphics.Rect; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; @@ -54,6 +55,8 @@ import android.view.IRemoteAnimationRunner; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; import android.view.WindowManager; +import android.window.ITaskFragmentOrganizer; +import android.window.TaskFragmentOrganizer; import androidx.test.filters.SmallTest; @@ -391,6 +394,35 @@ public class AppTransitionTests extends WindowTestsBase { mDc.mAppTransition.getAnimationStyleResId(attrs)); } + @Test + public void testActivityRecordReparentToTaskFragment() { + final ActivityRecord activity = createActivityRecord(mDc); + activity.setVisibility(true); + final Task task = activity.getTask(); + + // Add a TaskFragment of half of the Task size. + final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); + final ITaskFragmentOrganizer iOrganizer = + ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()); + mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer); + final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) + .setParentTask(task) + .setOrganizer(organizer) + .build(); + final Rect taskBounds = new Rect(); + task.getBounds(taskBounds); + taskFragment.setBounds(0, 0, taskBounds.right / 2, taskBounds.bottom); + + assertTrue(mDc.mChangingContainers.isEmpty()); + assertFalse(mDc.mAppTransition.isTransitionSet()); + + // Schedule app transition when reparent activity to a TaskFragment of different size. + activity.reparent(taskFragment, POSITION_TOP); + + assertTrue(mDc.mChangingContainers.contains(activity)); + assertTrue(mDc.mAppTransition.containsTransitRequest(TRANSIT_CHANGE)); + } + private class TestRemoteAnimationRunner implements IRemoteAnimationRunner { boolean mCancelled = false; @Override |