diff options
7 files changed, 156 insertions, 3 deletions
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java index c81184fb2383..1f3841ad8b58 100644 --- a/core/java/android/window/TransitionInfo.java +++ b/core/java/android/window/TransitionInfo.java @@ -110,8 +110,11 @@ public final class TransitionInfo implements Parcelable { /** The container is an input-method window. */ public static final int FLAG_IS_INPUT_METHOD = 1 << 8; + /** The container is ActivityEmbedding embedded. */ + public static final int FLAG_IS_EMBEDDED = 1 << 9; + /** The first unused bit. This can be used by remotes to attach custom flags to this change. */ - public static final int FLAG_FIRST_CUSTOM = 1 << 9; + public static final int FLAG_FIRST_CUSTOM = 1 << 10; /** @hide */ @IntDef(prefix = { "FLAG_" }, value = { @@ -125,6 +128,7 @@ public final class TransitionInfo implements Parcelable { FLAG_OCCLUDES_KEYGUARD, FLAG_DISPLAY_HAS_ALERT_WINDOWS, FLAG_IS_INPUT_METHOD, + FLAG_IS_EMBEDDED, FLAG_FIRST_CUSTOM }) public @interface ChangeFlags {} @@ -325,6 +329,9 @@ public final class TransitionInfo implements Parcelable { if ((flags & FLAG_DISPLAY_HAS_ALERT_WINDOWS) != 0) { sb.append((sb.length() == 0 ? "" : "|") + "DISPLAY_HAS_ALERT_WINDOWS"); } + if ((flags & FLAG_IS_EMBEDDED) != 0) { + sb.append((sb.length() == 0 ? "" : "|") + "IS_EMBEDDED"); + } if ((flags & FLAG_FIRST_CUSTOM) != 0) { sb.append((sb.length() == 0 ? "" : "|") + "FIRST_CUSTOM"); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java index 5a94a0d6f6a5..6694e441084b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java @@ -26,6 +26,7 @@ import android.util.Pair; import androidx.annotation.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; +import com.android.wm.shell.activityembedding.ActivityEmbeddingController; import com.android.wm.shell.bubbles.BubbleController; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; @@ -72,6 +73,7 @@ public class ShellInitImpl { private final Transitions mTransitions; private final StartingWindowController mStartingWindow; private final Optional<RecentTasksController> mRecentTasks; + private final Optional<ActivityEmbeddingController> mActivityEmbeddingOptional; private final InitImpl mImpl = new InitImpl(); // An ordered list of init callbacks to be made once shell is first started @@ -93,6 +95,7 @@ public class ShellInitImpl { Optional<UnfoldTransitionHandler> unfoldTransitionHandler, Optional<FreeformTaskListener<?>> freeformTaskListenerOptional, Optional<RecentTasksController> recentTasks, + Optional<ActivityEmbeddingController> activityEmbeddingOptional, Transitions transitions, StartingWindowController startingWindow, ShellExecutor mainExecutor) { @@ -110,6 +113,7 @@ public class ShellInitImpl { mUnfoldTransitionHandler = unfoldTransitionHandler; mFreeformTaskListenerOptional = freeformTaskListenerOptional; mRecentTasks = recentTasks; + mActivityEmbeddingOptional = activityEmbeddingOptional; mTransitions = transitions; mMainExecutor = mainExecutor; mStartingWindow = startingWindow; @@ -139,6 +143,7 @@ public class ShellInitImpl { if (Transitions.ENABLE_SHELL_TRANSITIONS) { mTransitions.register(mShellTaskOrganizer); + mActivityEmbeddingOptional.ifPresent(ActivityEmbeddingController::init); mUnfoldTransitionHandler.ifPresent(UnfoldTransitionHandler::init); if (mSplitScreenOptional.isPresent() && mPipTouchHandlerOptional.isPresent()) { final DefaultMixedHandler mixedHandler = new DefaultMixedHandler(mTransitions, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java new file mode 100644 index 000000000000..82b0270698e4 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2022 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.wm.shell.activityembedding; + +import static android.window.TransitionInfo.FLAG_IS_EMBEDDED; + +import android.content.Context; +import android.os.IBinder; +import android.view.SurfaceControl; +import android.window.TransitionInfo; +import android.window.TransitionRequestInfo; +import android.window.WindowContainerTransaction; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.wm.shell.transition.Transitions; + +/** + * Responsible for handling ActivityEmbedding related transitions. + */ +public class ActivityEmbeddingController implements Transitions.TransitionHandler { + + private final Context mContext; + private final Transitions mTransitions; + + public ActivityEmbeddingController(Context context, Transitions transitions) { + mContext = context; + mTransitions = transitions; + } + + /** Registers to handle transitions. */ + public void init() { + mTransitions.addHandler(this); + } + + @Override + public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction startTransaction, + @NonNull SurfaceControl.Transaction finishTransaction, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + // TODO(b/207070762) Handle AE animation as a part of other transitions. + // Only handle the transition if all containers are embedded. + for (TransitionInfo.Change change : info.getChanges()) { + if (!isEmbedded(change)) { + return false; + } + } + + // TODO(b/207070762) Implement AE animation. + startTransaction.apply(); + finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */); + return true; + } + + @Nullable + @Override + public WindowContainerTransaction handleRequest(@NonNull IBinder transition, + @NonNull TransitionRequestInfo request) { + return null; + } + + private static boolean isEmbedded(@NonNull TransitionInfo.Change change) { + return (change.getFlags() & FLAG_IS_EMBEDDED) != 0; + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index 2ea111b113d8..d5ef7de10332 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -38,6 +38,7 @@ import com.android.wm.shell.TaskViewFactory; import com.android.wm.shell.TaskViewFactoryController; import com.android.wm.shell.TaskViewTransitions; import com.android.wm.shell.WindowManagerShellWrapper; +import com.android.wm.shell.activityembedding.ActivityEmbeddingController; import com.android.wm.shell.back.BackAnimation; import com.android.wm.shell.back.BackAnimationController; import com.android.wm.shell.bubbles.BubbleController; @@ -621,6 +622,18 @@ public abstract class WMShellBaseModule { taskViewTransitions); } + + // + // ActivityEmbedding + // + + @WMSingleton + @Provides + static Optional<ActivityEmbeddingController> provideActivityEmbeddingController( + Context context, Transitions transitions) { + return Optional.of(new ActivityEmbeddingController(context, transitions)); + } + // // Misc // @@ -647,6 +660,7 @@ public abstract class WMShellBaseModule { Optional<UnfoldTransitionHandler> unfoldTransitionHandler, Optional<FreeformTaskListener<?>> freeformTaskListener, Optional<RecentTasksController> recentTasksOptional, + Optional<ActivityEmbeddingController> activityEmbeddingOptional, Transitions transitions, StartingWindowController startingWindow, @ShellMainThread ShellExecutor mainExecutor) { @@ -664,6 +678,7 @@ public abstract class WMShellBaseModule { unfoldTransitionHandler, freeformTaskListener, recentTasksOptional, + activityEmbeddingOptional, transitions, startingWindow, mainExecutor); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellInitImplTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellInitImplTest.java index 1effc97a0de3..ace8d365c7af 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellInitImplTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellInitImplTest.java @@ -24,6 +24,7 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; +import com.android.wm.shell.activityembedding.ActivityEmbeddingController; import com.android.wm.shell.bubbles.BubbleController; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; @@ -69,6 +70,7 @@ public class ShellInitImplTest extends ShellTestCase { @Mock private Optional<UnfoldTransitionHandler> mUnfoldTransitionHandler; @Mock private Optional<FreeformTaskListener<?>> mFreeformTaskListenerOptional; @Mock private Optional<RecentTasksController> mRecentTasks; + @Mock private Optional<ActivityEmbeddingController> mActivityEmbeddingController; @Mock private Transitions mTransitions; @Mock private StartingWindowController mStartingWindow; @Mock private ShellExecutor mMainExecutor; @@ -82,8 +84,8 @@ public class ShellInitImplTest extends ShellTestCase { mDisplayInsetsController, mDragAndDropController, mShellTaskOrganizer, mKidsModeTaskOrganizer, mBubblesOptional, mSplitScreenOptional, mPipTouchHandlerOptional, mFullscreenTaskListener, mUnfoldAnimationController, - mUnfoldTransitionHandler, mFreeformTaskListenerOptional, mRecentTasks, mTransitions, - mStartingWindow, mMainExecutor); + mUnfoldTransitionHandler, mFreeformTaskListenerOptional, mRecentTasks, + mActivityEmbeddingController, mTransitions, mStartingWindow, mMainExecutor); } @Test diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index c455ac1dd370..5ad5a55bf6db 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -46,6 +46,7 @@ import static android.view.WindowManager.TransitionType; import static android.view.WindowManager.transitTypeToString; import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS; import static android.window.TransitionInfo.FLAG_IS_DISPLAY; +import static android.window.TransitionInfo.FLAG_IS_EMBEDDED; import static android.window.TransitionInfo.FLAG_IS_INPUT_METHOD; import static android.window.TransitionInfo.FLAG_IS_VOICE_INTERACTION; import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; @@ -1761,6 +1762,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe if (occludesKeyguard(wc)) { flags |= FLAG_OCCLUDES_KEYGUARD; } + if (wc.isEmbedded()) { + flags |= FLAG_IS_EMBEDDED; + } return flags; } } diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index e1fbf96b2e71..c323e02ad149 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -30,6 +30,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; +import static android.window.TransitionInfo.FLAG_IS_EMBEDDED; import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER; import static android.window.TransitionInfo.FLAG_TRANSLUCENT; @@ -61,8 +62,10 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.view.SurfaceControl; import android.window.IDisplayAreaOrganizer; +import android.window.ITaskFragmentOrganizer; import android.window.ITaskOrganizer; import android.window.ITransitionPlayer; +import android.window.TaskFragmentOrganizer; import android.window.TransitionInfo; import androidx.test.filters.SmallTest; @@ -1005,6 +1008,43 @@ public class TransitionTests extends WindowTestsBase { assertTrue(openTransition.allReady()); } + @Test + public void testIsEmbeddedChange() { + final Transition transition = createTestTransition(TRANSIT_OPEN); + final ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges; + final ArraySet<WindowContainer> participants = transition.mParticipants; + + final Task task = createTask(mDisplayContent); + final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); + mAtm.mTaskFragmentOrganizerController.registerOrganizer( + ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder())); + final TaskFragment embeddedTf = new TaskFragmentBuilder(mAtm) + .setParentTask(task) + .createActivityCount(2) + .setOrganizer(organizer) + .build(); + final ActivityRecord closingActivity = embeddedTf.getBottomMostActivity(); + final ActivityRecord openingActivity = embeddedTf.getTopMostActivity(); + // Start states. + changes.put(embeddedTf, new Transition.ChangeInfo(true /* vis */, false /* exChg */)); + changes.put(closingActivity, new Transition.ChangeInfo(true /* vis */, false /* exChg */)); + changes.put(openingActivity, new Transition.ChangeInfo(false /* vis */, true /* exChg */)); + // End states. + closingActivity.mVisibleRequested = false; + openingActivity.mVisibleRequested = true; + + participants.add(closingActivity); + participants.add(openingActivity); + final ArrayList<WindowContainer> targets = Transition.calculateTargets( + participants, changes); + final TransitionInfo info = Transition.calculateTransitionInfo( + transition.mType, 0 /* flags */, targets, changes, mMockT); + + assertEquals(2, info.getChanges().size()); + assertTrue((info.getChanges().get(0).getFlags() & FLAG_IS_EMBEDDED) != 0); + assertTrue((info.getChanges().get(1).getFlags() & FLAG_IS_EMBEDDED) != 0); + } + private static void makeTaskOrganized(Task... tasks) { final ITaskOrganizer organizer = mock(ITaskOrganizer.class); for (Task t : tasks) { |