summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Massimo Carli <mcarli@google.com> 2024-12-11 11:34:22 +0000
committer Massimo Carli <mcarli@google.com> 2025-02-04 00:38:04 +0000
commita87b90e6d40a6b5fb3f9395caa3b49a3d0df1ee0 (patch)
tree7db426fd572dd466367462acbb0a8059294cc689
parent972c0c3ef52ae4aa16ab4b6d3110f161f7625a87 (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
-rw-r--r--core/java/android/window/WindowContainerTransaction.java58
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java3
-rw-r--r--services/core/java/com/android/server/wm/AppCompatReachabilityPolicy.java15
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java27
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java35
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)