Loading core/java/android/window/WindowContainerTransaction.java +57 −1 Original line number Diff line number Diff line Loading @@ -1129,6 +1129,19 @@ public final class WindowContainerTransaction implements Parcelable { return this; } /** * 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 Loading Loading @@ -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, Loading Loading @@ -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 { Loading @@ -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; Loading Loading @@ -1664,6 +1683,9 @@ public final class WindowContainerTransaction implements Parcelable { @Nullable private Bundle mLaunchOptions; @Nullable private Bundle mAppCompatOptions; @Nullable private Intent mActivityIntent; Loading Loading @@ -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, Loading Loading @@ -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; Loading @@ -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); Loading Loading @@ -1965,6 +2003,11 @@ public final class WindowContainerTransaction implements Parcelable { return mLaunchOptions; } @Nullable public Bundle getAppCompatOptions() { return mAppCompatOptions; } @Nullable public Intent getActivityIntent() { return mActivityIntent; Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -2244,6 +2291,9 @@ public final class WindowContainerTransaction implements Parcelable { @Nullable private Bundle mLaunchOptions; @Nullable private Bundle mAppCompatOptions; @Nullable private Intent mActivityIntent; Loading Loading @@ -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; Loading Loading @@ -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; Loading libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +3 −0 Original line number Diff line number Diff line Loading @@ -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; Loading services/core/java/com/android/server/wm/AppCompatReachabilityPolicy.java +11 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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(); Loading services/core/java/com/android/server/wm/WindowOrganizerController.java +27 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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()); Loading services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java +35 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) Loading Loading
core/java/android/window/WindowContainerTransaction.java +57 −1 Original line number Diff line number Diff line Loading @@ -1129,6 +1129,19 @@ public final class WindowContainerTransaction implements Parcelable { return this; } /** * 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 Loading Loading @@ -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, Loading Loading @@ -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 { Loading @@ -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; Loading Loading @@ -1664,6 +1683,9 @@ public final class WindowContainerTransaction implements Parcelable { @Nullable private Bundle mLaunchOptions; @Nullable private Bundle mAppCompatOptions; @Nullable private Intent mActivityIntent; Loading Loading @@ -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, Loading Loading @@ -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; Loading @@ -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); Loading Loading @@ -1965,6 +2003,11 @@ public final class WindowContainerTransaction implements Parcelable { return mLaunchOptions; } @Nullable public Bundle getAppCompatOptions() { return mAppCompatOptions; } @Nullable public Intent getActivityIntent() { return mActivityIntent; Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -2244,6 +2291,9 @@ public final class WindowContainerTransaction implements Parcelable { @Nullable private Bundle mLaunchOptions; @Nullable private Bundle mAppCompatOptions; @Nullable private Intent mActivityIntent; Loading Loading @@ -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; Loading Loading @@ -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; Loading
libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +3 −0 Original line number Diff line number Diff line Loading @@ -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; Loading
services/core/java/com/android/server/wm/AppCompatReachabilityPolicy.java +11 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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(); Loading
services/core/java/com/android/server/wm/WindowOrganizerController.java +27 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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()); Loading
services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java +35 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) Loading