diff options
author | 2025-03-18 20:33:22 -0700 | |
---|---|---|
committer | 2025-03-18 20:33:22 -0700 | |
commit | 1a1890346ac4bbd0b47d82e50f0b5352eea74ebf (patch) | |
tree | 649cb82f3e845bc356b2d52826fe39c160821a20 | |
parent | 857623fa6938a16c847b24a8765c5433d8c397b6 (diff) | |
parent | f4e67a30d5fa3b2cb7793b9d4ca81cff64cc2487 (diff) |
Merge "Delegate back gesture request to Shell." into main
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) { |