diff options
| author | 2024-12-11 11:34:22 +0000 | |
|---|---|---|
| committer | 2025-02-04 00:38:04 +0000 | |
| commit | a87b90e6d40a6b5fb3f9395caa3b49a3d0df1ee0 (patch) | |
| tree | 7db426fd572dd466367462acbb0a8059294cc689 | |
| parent | 972c0c3ef52ae4aa16ab4b6d3110f161f7625a87 (diff) | |
[21/n] Create Infrastructure for reachability
Create methods to create and start a
WindowContainerTransaction to hadle reachability
animations.
Flag: com.android.window.flags.app_compat_refactoring
Bug: 377874638
Bug: 377875801
Test: atest WmTests:WindowContainerTransactionTests
Change-Id: Iff8a8428207b713d2869ea24fdeb89ec6ea3d3cc
5 files changed, 133 insertions, 5 deletions
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index 68b5a261f507..1156503cf8e8 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -1130,6 +1130,19 @@ public final class WindowContainerTransaction implements Parcelable { } /** + * Adds a hierarchy op for app compat reachability. + * + * @param container The token for the container Task + * @param taskId The id of the current task + * @hide + */ + public WindowContainerTransaction setReachabilityOffset( + @NonNull WindowContainerToken container, int taskId, int x, int y) { + mHierarchyOps.add(HierarchyOp.createForReachability(container.asBinder(), taskId, x, y)); + return this; + } + + /** * Merges another WCT into this one. * @param transfer When true, this will transfer everything from other potentially leaving * other in an unusable state. When false, other is left alone, but @@ -1590,6 +1603,7 @@ public final class WindowContainerTransaction implements Parcelable { public static final int HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE = 22; public static final int HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT = 23; public static final int HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK = 24; + public static final int HIERARCHY_OP_TYPE_APP_COMPAT_REACHABILITY = 25; @IntDef(prefix = {"HIERARCHY_OP_TYPE_"}, value = { HIERARCHY_OP_TYPE_REPARENT, @@ -1617,6 +1631,7 @@ public final class WindowContainerTransaction implements Parcelable { HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE, HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT, HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK, + HIERARCHY_OP_TYPE_APP_COMPAT_REACHABILITY, }) @Retention(RetentionPolicy.SOURCE) public @interface HierarchyOpType { @@ -1630,6 +1645,10 @@ public final class WindowContainerTransaction implements Parcelable { public static final String LAUNCH_KEY_SHORTCUT_CALLING_PACKAGE = "android:transaction.hop.shortcut_calling_package"; + // The following keys are used to define the reachability direction after a double tap. + public static final String REACHABILITY_EVENT_X = "android:transaction.reachability_x"; + public static final String REACHABILITY_EVENT_Y = "android:transaction.reachability_y"; + @HierarchyOpType private final int mType; @@ -1665,6 +1684,9 @@ public final class WindowContainerTransaction implements Parcelable { private Bundle mLaunchOptions; @Nullable + private Bundle mAppCompatOptions; + + @Nullable private Intent mActivityIntent; /** Used as options for {@link #addTaskFragmentOperation}. */ @@ -1833,7 +1855,21 @@ public final class WindowContainerTransaction implements Parcelable { .build(); } - /** Creates a hierarchy op for setting a task non-trimmable by recents. */ + /** Create a hierarchy op for app compat reachability. */ + @NonNull + public static HierarchyOp createForReachability(IBinder container, int taskId, int x, + int y) { + final Bundle appCompatOptions = new Bundle(); + appCompatOptions.putInt(LAUNCH_KEY_TASK_ID, taskId); + appCompatOptions.putInt(REACHABILITY_EVENT_X, x); + appCompatOptions.putInt(REACHABILITY_EVENT_Y, y); + return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_APP_COMPAT_REACHABILITY) + .setAppCompatOptions(appCompatOptions) + .setContainer(container) + .build(); + } + + /** Create a hierarchy op for setting a task non-trimmable by recents. */ @NonNull @FlaggedApi(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) public static HierarchyOp createForSetTaskTrimmableFromRecents(@NonNull IBinder container, @@ -1863,6 +1899,7 @@ public final class WindowContainerTransaction implements Parcelable { mWindowingModes = copy.mWindowingModes; mActivityTypes = copy.mActivityTypes; mLaunchOptions = copy.mLaunchOptions; + mAppCompatOptions = copy.mAppCompatOptions; mActivityIntent = copy.mActivityIntent; mTaskFragmentOperation = copy.mTaskFragmentOperation; mKeyguardState = copy.mKeyguardState; @@ -1889,6 +1926,7 @@ public final class WindowContainerTransaction implements Parcelable { mWindowingModes = in.createIntArray(); mActivityTypes = in.createIntArray(); mLaunchOptions = in.readBundle(); + mAppCompatOptions = in.readBundle(getClass().getClassLoader()); mActivityIntent = in.readTypedObject(Intent.CREATOR); mTaskFragmentOperation = in.readTypedObject(TaskFragmentOperation.CREATOR); mKeyguardState = in.readTypedObject(KeyguardState.CREATOR); @@ -1966,6 +2004,11 @@ public final class WindowContainerTransaction implements Parcelable { } @Nullable + public Bundle getAppCompatOptions() { + return mAppCompatOptions; + } + + @Nullable public Intent getActivityIntent() { return mActivityIntent; } @@ -2100,6 +2143,9 @@ public final class WindowContainerTransaction implements Parcelable { case HIERARCHY_OP_TYPE_LAUNCH_TASK: sb.append(mLaunchOptions); break; + case HIERARCHY_OP_TYPE_APP_COMPAT_REACHABILITY: + sb.append(mAppCompatOptions); + break; case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: sb.append("container=").append(mContainer).append(" clearRoot=").append(mToTop); break; @@ -2182,6 +2228,7 @@ public final class WindowContainerTransaction implements Parcelable { dest.writeIntArray(mWindowingModes); dest.writeIntArray(mActivityTypes); dest.writeBundle(mLaunchOptions); + dest.writeBundle(mAppCompatOptions); dest.writeTypedObject(mActivityIntent, flags); dest.writeTypedObject(mTaskFragmentOperation, flags); dest.writeTypedObject(mKeyguardState, flags); @@ -2245,6 +2292,9 @@ public final class WindowContainerTransaction implements Parcelable { private Bundle mLaunchOptions; @Nullable + private Bundle mAppCompatOptions; + + @Nullable private Intent mActivityIntent; @Nullable @@ -2328,6 +2378,11 @@ public final class WindowContainerTransaction implements Parcelable { return this; } + Builder setAppCompatOptions(@Nullable Bundle appCompatOptions) { + mAppCompatOptions = appCompatOptions; + return this; + } + Builder setActivityIntent(@Nullable Intent activityIntent) { mActivityIntent = activityIntent; return this; @@ -2407,6 +2462,7 @@ public final class WindowContainerTransaction implements Parcelable { hierarchyOp.mToTop = mToTop; hierarchyOp.mReparentTopOnly = mReparentTopOnly; hierarchyOp.mLaunchOptions = mLaunchOptions; + hierarchyOp.mAppCompatOptions = mAppCompatOptions; hierarchyOp.mActivityIntent = mActivityIntent; hierarchyOp.mPendingIntent = mPendingIntent; hierarchyOp.mAlwaysOnTop = mAlwaysOnTop; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index b83b7e2f07a3..527291be9888 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -193,6 +193,9 @@ public class Transitions implements RemoteCallable<Transitions>, /** Transition to end the recents transition */ public static final int TRANSIT_END_RECENTS_TRANSITION = TRANSIT_FIRST_CUSTOM + 22; + /** Transition type for app compat reachability. */ + public static final int TRANSIT_MOVE_LETTERBOX_REACHABILITY = TRANSIT_FIRST_CUSTOM + 23; + /** Transition type for desktop mode transitions. */ public static final int TRANSIT_DESKTOP_MODE_TYPES = WindowManager.TRANSIT_FIRST_CUSTOM + 100; diff --git a/services/core/java/com/android/server/wm/AppCompatReachabilityPolicy.java b/services/core/java/com/android/server/wm/AppCompatReachabilityPolicy.java index a7c52bd1fc38..b47786675fc9 100644 --- a/services/core/java/com/android/server/wm/AppCompatReachabilityPolicy.java +++ b/services/core/java/com/android/server/wm/AppCompatReachabilityPolicy.java @@ -32,6 +32,7 @@ import android.annotation.Nullable; import android.graphics.Rect; import com.android.internal.annotations.VisibleForTesting; +import com.android.window.flags.Flags; import java.io.PrintWriter; import java.util.function.Supplier; @@ -97,8 +98,11 @@ class AppCompatReachabilityPolicy { private void handleHorizontalDoubleTap(int x) { final AppCompatReachabilityOverrides reachabilityOverrides = mActivityRecord.mAppCompatController.getReachabilityOverrides(); - if (!reachabilityOverrides.isHorizontalReachabilityEnabled() - || mActivityRecord.isInTransition()) { + // We don't return early when the Shell letterbox implementation is enabled because + // double tap is always sent via transitions. + final boolean isInTransition = !Flags.appCompatRefactoring() + && mActivityRecord.isInTransition(); + if (!reachabilityOverrides.isHorizontalReachabilityEnabled() || isInTransition) { return; } final Rect letterboxInnerFrame = getLetterboxInnerFrame(); @@ -143,8 +147,11 @@ class AppCompatReachabilityPolicy { private void handleVerticalDoubleTap(int y) { final AppCompatReachabilityOverrides reachabilityOverrides = mActivityRecord.mAppCompatController.getReachabilityOverrides(); - if (!reachabilityOverrides.isVerticalReachabilityEnabled() - || mActivityRecord.isInTransition()) { + // We don't return early when the Shell letterbox implementation is enabled because + // double tap is always sent via transitions. + final boolean isInTransition = !Flags.appCompatRefactoring() + && mActivityRecord.isInTransition(); + if (!reachabilityOverrides.isVerticalReachabilityEnabled() || isInTransition) { return; } final Rect letterboxInnerFrame = getLetterboxInnerFrame(); diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 060f2e803ec9..8afd60fb4802 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -52,6 +52,7 @@ import static android.window.WindowContainerTransaction.Change.CHANGE_FOCUSABLE; import static android.window.WindowContainerTransaction.Change.CHANGE_FORCE_TRANSLUCENT; import static android.window.WindowContainerTransaction.Change.CHANGE_HIDDEN; import static android.window.WindowContainerTransaction.Change.CHANGE_RELATIVE_BOUNDS; +import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_APP_COMPAT_REACHABILITY; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER; @@ -77,6 +78,8 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_SHORTCUT; +import static android.window.WindowContainerTransaction.HierarchyOp.REACHABILITY_EVENT_X; +import static android.window.WindowContainerTransaction.HierarchyOp.REACHABILITY_EVENT_Y; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_WINDOW_ORGANIZER; import static com.android.server.wm.ActivityRecord.State.PAUSING; @@ -1196,6 +1199,30 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub caller.mPid, caller.mUid, taskId, safeOptions)); break; } + case HIERARCHY_OP_TYPE_APP_COMPAT_REACHABILITY: { + int doubleTapX = hop.getAppCompatOptions().getInt(REACHABILITY_EVENT_X); + int doubleTapY = hop.getAppCompatOptions().getInt(REACHABILITY_EVENT_Y); + final WindowContainer<?> wc = WindowContainer.fromBinder(hop.getContainer()); + if (wc == null) { + break; + } + final Task currentTask = wc.asTask(); + if (chain.mTransition != null) { + chain.mTransition.collect(wc); + } + if (currentTask != null) { + final ActivityRecord top = currentTask.topRunningActivity(); + if (top != null) { + if (chain.mTransition != null) { + chain.mTransition.collect(top); + } + top.mAppCompatController.getReachabilityPolicy().handleDoubleTap(doubleTapX, + doubleTapY); + } + } + effects |= TRANSACT_EFFECTS_CLIENT_CONFIG; + break; + } case HIERARCHY_OP_TYPE_REORDER: case HIERARCHY_OP_TYPE_REPARENT: { final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java index 369600c3f8d7..dcb68620e361 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java @@ -18,20 +18,30 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_APP_COMPAT_REACHABILITY; +import static android.window.WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID; +import static android.window.WindowContainerTransaction.HierarchyOp.REACHABILITY_EVENT_X; +import static android.window.WindowContainerTransaction.HierarchyOp.REACHABILITY_EVENT_Y; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.times; import android.content.Intent; +import android.os.Binder; +import android.os.Bundle; import android.platform.test.annotations.Presubmit; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; +import android.window.WindowContainerTransaction.HierarchyOp; import androidx.annotation.NonNull; import androidx.test.filters.SmallTest; @@ -223,6 +233,31 @@ public class WindowContainerTransactionTests extends WindowTestsBase { < tda.mChildren.indexOf(desktopOrganizer.mTasks.get(2).getRootTask())); } + @Test + public void testAppCompat_setReachabilityOffsets() { + final Task task = createTask(/* taskId */ 37); + final WindowContainerToken containerToken = task.getTaskInfo().token; + spyOn(containerToken); + final Binder asBinder = new Binder(); + doReturn(asBinder).when(containerToken).asBinder(); + final WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.setReachabilityOffset(containerToken, /* taskId */ task.mTaskId, 10, 20); + + final List<HierarchyOp> hierarchyOps = wct.getHierarchyOps().stream() + .filter(op -> op.getType() == HIERARCHY_OP_TYPE_APP_COMPAT_REACHABILITY) + .toList(); + + assertEquals(1, hierarchyOps.size()); + final HierarchyOp appCompatOp = hierarchyOps.getFirst(); + assertNotNull(appCompatOp); + final Bundle appCompatOptions = appCompatOp.getAppCompatOptions(); + + assertEquals(task.mTaskId, appCompatOptions.getInt(LAUNCH_KEY_TASK_ID)); + assertEquals(10, appCompatOptions.getInt(REACHABILITY_EVENT_X)); + assertEquals(20, appCompatOptions.getInt(REACHABILITY_EVENT_Y)); + assertSame(asBinder, appCompatOp.getContainer()); + } + private Task createTask(int taskId) { return new Task.Builder(mAtm) .setTaskId(taskId) |