summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Wei Sheng Shih <wilsonshih@google.com> 2025-03-18 20:33:22 -0700
committer Android (Google) Code Review <android-gerrit@google.com> 2025-03-18 20:33:22 -0700
commit1a1890346ac4bbd0b47d82e50f0b5352eea74ebf (patch)
tree649cb82f3e845bc356b2d52826fe39c160821a20
parent857623fa6938a16c847b24a8765c5433d8c397b6 (diff)
parentf4e67a30d5fa3b2cb7793b9d4ca81cff64cc2487 (diff)
Merge "Delegate back gesture request to Shell." into main
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl5
-rw-r--r--core/java/android/window/flags/windowing_frontend.aconfig11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java27
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java17
-rw-r--r--services/core/java/com/android/server/wm/BackNavigationController.java30
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java29
9 files changed, 126 insertions, 7 deletions
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 01b2953362b5..6c6709bb2b47 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -369,6 +369,11 @@ interface IActivityTaskManager {
in RemoteCallback navigationObserver, in BackAnimationAdapter adaptor);
/**
+ * Registers a callback to be invoked when the system server requests a back gesture.
+ */
+ void registerBackGestureDelegate(in RemoteCallback monitor);
+
+ /**
* registers a callback to be invoked when a background activity launch is aborted.
*
* @param observer callback to be registered.
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 8dd0457248a4..b19ab4527f06 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -524,4 +524,15 @@ flag {
metadata {
purpose: PURPOSE_BUGFIX
}
+}
+
+flag {
+ name: "delegate_back_gesture_to_shell"
+ namespace: "windowing_frontend"
+ description: "Delegate back gesture event to back animation controller."
+ bug: "394599430"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 81cf031994a2..746632f67725 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -286,6 +286,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
this::createExternalInterface, this);
mShellCommandHandler.addDumpCallback(this::dump, this);
mShellController.addConfigurationChangeListener(this);
+ registerBackGestureDelegate();
}
public BackAnimation getBackAnimationImpl() {
@@ -1144,6 +1145,32 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
mBackAnimationAdapter = new BackAnimationAdapter(runner);
}
+ private void registerBackGestureDelegate() {
+ if (!Flags.delegateBackGestureToShell()) {
+ return;
+ }
+ final RemoteCallback requestBackMonitor = new RemoteCallback(
+ new RemoteCallback.OnResultListener() {
+ @Override
+ public void onResult(@Nullable Bundle result) {
+ mShellExecutor.execute(() -> {
+ if (mBackGestureStarted) {
+ Log.w(TAG, "Back gesture is running, ignore request");
+ return;
+ }
+ onMotionEvent(0, 0, KeyEvent.ACTION_DOWN, EDGE_NONE);
+ setTriggerBack(true);
+ onMotionEvent(0, 0, KeyEvent.ACTION_UP, EDGE_NONE);
+ });
+ }
+ });
+ try {
+ mActivityTaskManager.registerBackGestureDelegate(requestBackMonitor);
+ } catch (RemoteException remoteException) {
+ Log.w(TAG, "Failed register back gesture request ", remoteException);
+ }
+ }
+
/**
* Description of current BackAnimationController state.
*/
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index e9f522d08328..8cf0481b1dc3 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4633,6 +4633,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@SuppressLint("MissingPermission")
private void injectBackGesture(long downtime) {
+ if (mActivityTaskManagerInternal.requestBackGesture()) {
+ return;
+ }
// Create and inject down event
KeyEvent downEvent = new KeyEvent(downtime, downtime, KeyEvent.ACTION_DOWN,
KeyEvent.KEYCODE_BACK, 0 /* repeat */, 0 /* metaState */,
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 21b730e13585..7123a7c1160f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -803,4 +803,10 @@ public abstract class ActivityTaskManagerInternal {
/** Returns whether assist data is allowed. */
public abstract boolean isAssistDataAllowed();
+
+ /**
+ * Delegate back gesture request from shell.
+ * Returns true if the back gesture request was successful, false otherwise.
+ */
+ public abstract boolean requestBackGesture();
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 46d24b0d3201..a0c38dd82037 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1892,6 +1892,18 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
+ @Override
+ public void registerBackGestureDelegate(RemoteCallback requestObserver) {
+ mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
+ "registerBackGestureDelegate()");
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ mBackNavigationController.registerBackGestureDelegate(requestObserver);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
/**
* Public API to check if the client is allowed to start an activity on specified display.
*
@@ -7571,6 +7583,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public boolean isAssistDataAllowed() {
return ActivityTaskManagerService.this.isAssistDataAllowed();
}
+
+ @Override
+ public boolean requestBackGesture() {
+ return mBackNavigationController.requestBackGesture();
+ }
}
/** Cache the return value for {@link #isPip2ExperimentEnabled()} */
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index dfe323c43abb..819e4abaa9d3 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -85,6 +85,7 @@ class BackNavigationController {
private boolean mShowWallpaper;
private Runnable mPendingAnimation;
private final NavigationMonitor mNavigationMonitor = new NavigationMonitor();
+ private RemoteCallback mGestureRequest;
private AnimationHandler mAnimationHandler;
@@ -113,6 +114,35 @@ class BackNavigationController {
mNavigationMonitor.onEmbeddedWindowGestureTransferred(host);
}
+ void registerBackGestureDelegate(@NonNull RemoteCallback requestObserver) {
+ if (!sPredictBackEnable) {
+ return;
+ }
+ synchronized (mWindowManagerService.mGlobalLock) {
+ mGestureRequest = requestObserver;
+ try {
+ requestObserver.getInterface().asBinder().linkToDeath(() -> {
+ synchronized (mWindowManagerService.mGlobalLock) {
+ mGestureRequest = null;
+ }
+ }, 0 /* flags */);
+ } catch (RemoteException r) {
+ Slog.e(TAG, "Failed to link to death");
+ mGestureRequest = null;
+ }
+ }
+ }
+
+ boolean requestBackGesture() {
+ synchronized (mWindowManagerService.mGlobalLock) {
+ if (mGestureRequest == null) {
+ return false;
+ }
+ mGestureRequest.sendResult(null);
+ return true;
+ }
+ }
+
/**
* Set up the necessary leashes and build a {@link BackNavigationInfo} instance for an upcoming
* back gesture animation.
diff --git a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
index 0495e967c0e3..5ab00361d3c0 100644
--- a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
@@ -491,6 +491,11 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase {
@Test
public void testKeyGestureBack() {
+ mPhoneWindowManager.overrideDelegateBackGestureRemote(true);
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_BACK);
+ mPhoneWindowManager.assertBackEventInjected();
+
+ mPhoneWindowManager.overrideDelegateBackGestureRemote(false);
sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_BACK);
mPhoneWindowManager.assertBackEventInjected();
}
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index 7b6d361c55d4..7059c41898f3 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -202,6 +202,7 @@ class TestPhoneWindowManager {
private boolean mIsTalkBackEnabled;
private boolean mIsTalkBackShortcutGestureEnabled;
+ private boolean mDelegateBackGestureRemote;
private boolean mIsVoiceAccessEnabled;
private Intent mBrowserIntent;
@@ -580,6 +581,12 @@ class TestPhoneWindowManager {
setPhoneCallIsInProgress();
}
+ void overrideDelegateBackGestureRemote(boolean isDelegating) {
+ mDelegateBackGestureRemote = isDelegating;
+ doReturn(mDelegateBackGestureRemote).when(mActivityTaskManagerInternal)
+ .requestBackGesture();
+ }
+
void prepareBrightnessDecrease(float currentBrightness) {
doReturn(0.0f).when(mPowerManager).getBrightnessConstraint(
DEFAULT_DISPLAY, PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM);
@@ -661,13 +668,21 @@ class TestPhoneWindowManager {
}
void assertBackEventInjected() {
- ArgumentCaptor<InputEvent> intentCaptor = ArgumentCaptor.forClass(InputEvent.class);
- verify(mInputManager, times(2)).injectInputEvent(intentCaptor.capture(), anyInt());
- List<InputEvent> inputEvents = intentCaptor.getAllValues();
- Assert.assertEquals(KeyEvent.KEYCODE_BACK, ((KeyEvent) inputEvents.get(0)).getKeyCode());
- Assert.assertEquals(KeyEvent.KEYCODE_BACK, ((KeyEvent) inputEvents.get(1)).getKeyCode());
- // Reset verifier for next call.
- Mockito.clearInvocations(mContext);
+ if (mDelegateBackGestureRemote) {
+ Mockito.verify(mActivityTaskManagerInternal).requestBackGesture();
+ ArgumentCaptor<InputEvent> intentCaptor = ArgumentCaptor.forClass(InputEvent.class);
+ verify(mInputManager, never()).injectInputEvent(intentCaptor.capture(), anyInt());
+ } else {
+ ArgumentCaptor<InputEvent> intentCaptor = ArgumentCaptor.forClass(InputEvent.class);
+ verify(mInputManager, times(2)).injectInputEvent(intentCaptor.capture(), anyInt());
+ List<InputEvent> inputEvents = intentCaptor.getAllValues();
+ Assert.assertEquals(KeyEvent.KEYCODE_BACK,
+ ((KeyEvent) inputEvents.get(0)).getKeyCode());
+ Assert.assertEquals(KeyEvent.KEYCODE_BACK,
+ ((KeyEvent) inputEvents.get(1)).getKeyCode());
+ // Reset verifier for next call.
+ Mockito.clearInvocations(mContext);
+ }
}
void overrideSearchKeyBehavior(int behavior) {