diff options
| author | 2023-12-06 22:24:29 +0000 | |
|---|---|---|
| committer | 2023-12-06 22:24:29 +0000 | |
| commit | 22b22b133656b832dfb237bef6ab135285e13e36 (patch) | |
| tree | a6133617dd13f4b106877dadbc631e062794e275 | |
| parent | 554e294a6e8c8d7da685121527eb10aa2b5b0dba (diff) | |
| parent | dbd6004304a79e2ee3f6f7fff0c0bb804c50370c (diff) | |
Merge changes from topic "override_button_perm" into main
* changes:
Allow focused window to override stem primary key.
Add a new permission OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW
8 files changed, 257 insertions, 13 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 378a18c175be..f5b9b171b9a0 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -251,6 +251,7 @@ package android { field public static final String OBSERVE_SENSOR_PRIVACY = "android.permission.OBSERVE_SENSOR_PRIVACY"; field public static final String OPEN_ACCESSIBILITY_DETAILS_SETTINGS = "android.permission.OPEN_ACCESSIBILITY_DETAILS_SETTINGS"; field public static final String OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD = "android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"; + field @FlaggedApi("com.android.input.flags.override_key_behavior_permission_apis") public static final String OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW = "android.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW"; field public static final String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT"; field public static final String PACKET_KEEPALIVE_OFFLOAD = "android.permission.PACKET_KEEPALIVE_OFFLOAD"; field public static final String PEERS_MAC_ADDRESS = "android.permission.PEERS_MAC_ADDRESS"; diff --git a/core/java/com/android/internal/policy/KeyInterceptionInfo.java b/core/java/com/android/internal/policy/KeyInterceptionInfo.java index 964be01952ea..b20f6d225b69 100644 --- a/core/java/com/android/internal/policy/KeyInterceptionInfo.java +++ b/core/java/com/android/internal/policy/KeyInterceptionInfo.java @@ -26,10 +26,12 @@ public class KeyInterceptionInfo { public final int layoutParamsPrivateFlags; // Debug friendly name to help identify the window public final String windowTitle; + public final int windowOwnerUid; - public KeyInterceptionInfo(int type, int flags, String title) { + public KeyInterceptionInfo(int type, int flags, String title, int uid) { layoutParamsType = type; layoutParamsPrivateFlags = flags; windowTitle = title; + windowOwnerUid = uid; } } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index c55b8089242a..dd93586c340b 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -7832,6 +7832,22 @@ <permission android:name="android.permission.PREPARE_FACTORY_RESET" android:protectionLevel="signature|privileged" /> + <!-- @SystemApi Allows focused window to override the default behavior of supported system keys. + The following keycodes are supported: + <p> KEYCODE_STEM_PRIMARY + <p>If an app is granted this permission and has a focused window, it will be allowed to + receive supported key events that are otherwise handled by the system. The app can choose + to consume the key events and trigger its own behavior, in which case the default key + behavior will be skipped. + <p>For example, KEYCODE_STEM_PRIMARY by default opens recent app launcher. If the foreground + fitness app is granted this permission, it can repurpose the KEYCODE_STEM_PRIMARY button + to pause/resume the current fitness session. + <p>Protection level: signature|privileged + @FlaggedApi("com.android.input.flags.override_key_behavior_permission_apis") + @hide --> + <permission android:name="android.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW" + android:protectionLevel="signature|privileged" /> + <!-- Attribution for Geofencing service. --> <attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/> <!-- Attribution for Country Detector. --> diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 30bce2f41cf7..4e5dc1dd76fa 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -17,11 +17,13 @@ package com.android.server.policy; import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; +import static android.Manifest.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW; import static android.Manifest.permission.SYSTEM_ALERT_WINDOW; import static android.Manifest.permission.SYSTEM_APPLICATION_OVERLAY; import static android.app.AppOpsManager.OP_CREATE_ACCESSIBILITY_OVERLAY; import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; import static android.app.AppOpsManager.OP_TOAST_WINDOW; +import static android.content.PermissionChecker.PID_UNKNOWN; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE; @@ -117,6 +119,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.PermissionChecker; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -690,6 +693,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { private final com.android.internal.policy.LogDecelerateInterpolator mLogDecelerateInterpolator = new LogDecelerateInterpolator(100, 0); + private final DeferredKeyActionExecutor mDeferredKeyActionExecutor = + new DeferredKeyActionExecutor(); private volatile int mTopFocusedDisplayId = INVALID_DISPLAY; @@ -698,6 +703,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private KeyCombinationManager mKeyCombinationManager; private SingleKeyGestureDetector mSingleKeyGestureDetector; private GestureLauncherService mGestureLauncherService; + private ButtonOverridePermissionChecker mButtonOverridePermissionChecker; private boolean mLockNowPending = false; @@ -725,6 +731,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private static final int MSG_RINGER_TOGGLE_CHORD = 24; private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 25; private static final int MSG_LOG_KEYBOARD_SYSTEM_EVENT = 26; + private static final int MSG_SET_DEFERRED_KEY_ACTIONS_EXECUTABLE = 27; private class PolicyHandler extends Handler { @@ -792,7 +799,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { mAutofillManagerInternal.onBackKeyPressed(); break; case MSG_SYSTEM_KEY_PRESS: - sendSystemKeyToStatusBar((KeyEvent) msg.obj); + KeyEvent event = (KeyEvent) msg.obj; + sendSystemKeyToStatusBar(event); + event.recycle(); break; case MSG_HANDLE_ALL_APPS: launchAllAppsAction(); @@ -809,6 +818,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { case MSG_LOG_KEYBOARD_SYSTEM_EVENT: handleKeyboardSystemEvent(KeyboardLogEvent.from(msg.arg1), (KeyEvent) msg.obj); break; + case MSG_SET_DEFERRED_KEY_ACTIONS_EXECUTABLE: + final int keyCode = msg.arg1; + final long downTime = (Long) msg.obj; + mDeferredKeyActionExecutor.setActionsExecutable(keyCode, downTime); + break; } } } @@ -2234,6 +2248,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { IActivityManager getActivityManagerService() { return ActivityManager.getService(); } + + ButtonOverridePermissionChecker getButtonOverridePermissionChecker() { + return new ButtonOverridePermissionChecker(); + } } /** {@inheritDoc} */ @@ -2499,6 +2517,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mKeyguardDelegate = injector.getKeyguardServiceDelegate(); initKeyCombinationRules(); initSingleKeyGestureRules(injector.getLooper()); + mButtonOverridePermissionChecker = injector.getButtonOverridePermissionChecker(); mSideFpsEventHandler = new SideFpsEventHandler(mContext, mHandler, mPowerManager); } @@ -2768,17 +2787,33 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mShouldEarlyShortPressOnStemPrimary) { return; } - stemPrimaryPress(1 /*count*/); + // Short-press should be triggered only if app doesn't handle it. + mDeferredKeyActionExecutor.queueKeyAction( + KeyEvent.KEYCODE_STEM_PRIMARY, downTime, () -> stemPrimaryPress(1 /*count*/)); } @Override void onLongPress(long eventTime) { - stemPrimaryLongPress(eventTime); + // Long-press should be triggered only if app doesn't handle it. + mDeferredKeyActionExecutor.queueKeyAction( + KeyEvent.KEYCODE_STEM_PRIMARY, + eventTime, + () -> stemPrimaryLongPress(eventTime)); } @Override void onMultiPress(long downTime, int count, int unusedDisplayId) { - stemPrimaryPress(count); + // Triple-press stem to toggle accessibility gesture should always be triggered + // regardless of if app handles it. + if (count == 3 + && mTriplePressOnStemPrimaryBehavior + == TRIPLE_PRESS_PRIMARY_TOGGLE_ACCESSIBILITY) { + stemPrimaryPress(count); + } else { + // Other multi-press gestures should be triggered only if app doesn't handle it. + mDeferredKeyActionExecutor.queueKeyAction( + KeyEvent.KEYCODE_STEM_PRIMARY, downTime, () -> stemPrimaryPress(count)); + } } @Override @@ -2792,7 +2827,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { mBackgroundRecentTaskInfoOnStemPrimarySingleKeyUp = mActivityTaskManagerInternal.getMostRecentTaskFromBackground(); if (mShouldEarlyShortPressOnStemPrimary) { - stemPrimaryPress(1 /*pressCount*/); + // Key-up gesture should be triggered only if app doesn't handle it. + mDeferredKeyActionExecutor.queueKeyAction( + KeyEvent.KEYCODE_STEM_PRIMARY, eventTime, () -> stemPrimaryPress(1)); } } } @@ -3750,6 +3787,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { return true; } break; + case KeyEvent.KEYCODE_STEM_PRIMARY: + if (prepareToSendSystemKeyToApplication(focusedToken, event)) { + // Send to app. + return false; + } else { + // Intercepted. + sendSystemKeyToStatusBarAsync(event); + return true; + } } if (isValidGlobalKey(keyCode) && mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) { @@ -3760,6 +3806,60 @@ public class PhoneWindowManager implements WindowManagerPolicy { return (metaState & KeyEvent.META_META_ON) != 0; } + /** + * In this function, we check whether a system key should be sent to the application. We also + * detect the key gesture on this key, even if the key will be sent to the app. The gesture + * action, if any, will not be executed immediately. It will be queued and execute only after + * the application tells us that it didn't handle this key. + * + * @return true if this key should be sent to the application. This also means that the target + * application has the necessary permissions to receive this key. Return false otherwise. + */ + private boolean prepareToSendSystemKeyToApplication(IBinder focusedToken, KeyEvent event) { + final int keyCode = event.getKeyCode(); + if (!event.isSystem()) { + Log.wtf( + TAG, + "Illegal keycode provided to prepareToSendSystemKeyToApplication: " + + KeyEvent.keyCodeToString(keyCode)); + return false; + } + final boolean isDown = event.getAction() == KeyEvent.ACTION_DOWN; + if (isDown && event.getRepeatCount() == 0) { + // This happens at the initial DOWN event. Check focused window permission now. + final KeyInterceptionInfo info = + mWindowManagerInternal.getKeyInterceptionInfoFromToken(focusedToken); + if (info != null + && mButtonOverridePermissionChecker.canAppOverrideSystemKey( + mContext, info.windowOwnerUid)) { + // Focused window has the permission. Pass the event to it. + return true; + } else { + // Focused window doesn't have the permission. Intercept the event. + // If the initial DOWN event is intercepted, follow-up events will be intercepted + // too. So we know the gesture won't be handled by app, and can handle the gesture + // in system. + setDeferredKeyActionsExecutableAsync(keyCode, event.getDownTime()); + return false; + } + } else { + // This happens after the initial DOWN event. We will just reuse the initial decision. + // I.e., if the initial DOWN event was dispatched, follow-up events should be + // dispatched. Otherwise, follow-up events should be consumed. + final Set<Integer> consumedKeys = mConsumedKeysForDevice.get(event.getDeviceId()); + final boolean wasConsumed = consumedKeys != null && consumedKeys.contains(keyCode); + return !wasConsumed; + } + } + + private void setDeferredKeyActionsExecutableAsync(int keyCode, long downTime) { + Message msg = Message.obtain(mHandler, MSG_SET_DEFERRED_KEY_ACTIONS_EXECUTABLE); + msg.arg1 = keyCode; + msg.obj = downTime; + msg.setAsynchronous(true); + msg.sendToTarget(); + } + @SuppressLint("MissingPermission") private void injectBackGesture(long downtime) { // Create and inject down event @@ -3977,11 +4077,34 @@ public class PhoneWindowManager implements WindowManagerPolicy { mContext.closeSystemDialogs(); } return true; + case KeyEvent.KEYCODE_STEM_PRIMARY: + handleUnhandledSystemKey(event); + sendSystemKeyToStatusBarAsync(event); + return true; } return false; } + /** + * Called when a system key was sent to application and was unhandled. We will execute any + * queued actions associated with this key code at this point. + */ + private void handleUnhandledSystemKey(KeyEvent event) { + if (!event.isSystem()) { + Log.wtf( + TAG, + "Illegal keycode provided to handleUnhandledSystemKey: " + + KeyEvent.keyCodeToString(event.getKeyCode())); + return; + } + if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { + // If the initial DOWN event is unhandled by app, follow-up events will also be + // unhandled by app. So we can handle the key event in system. + setDeferredKeyActionsExecutableAsync(event.getKeyCode(), event.getDownTime()); + } + } + private void sendSwitchKeyboardLayout(@NonNull KeyEvent event, int direction) { mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, event.getDeviceId(), direction).sendToTarget(); @@ -4904,9 +5027,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { case KeyEvent.KEYCODE_MACRO_4: result &= ~ACTION_PASS_TO_USER; break; - case KeyEvent.KEYCODE_STEM_PRIMARY: - sendSystemKeyToStatusBarAsync(event); - break; } if (useHapticFeedback) { @@ -5016,7 +5136,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { * Notify the StatusBar that a system key was pressed without blocking the current thread. */ private void sendSystemKeyToStatusBarAsync(KeyEvent keyEvent) { - Message message = mHandler.obtainMessage(MSG_SYSTEM_KEY_PRESS, keyEvent); + // Make a copy because the event may be recycled. + Message message = mHandler.obtainMessage(MSG_SYSTEM_KEY_PRESS, KeyEvent.obtain(keyEvent)); message.setAsynchronous(true); mHandler.sendMessage(message); } @@ -6468,6 +6589,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mGlobalKeyManager.dump(prefix, pw); mKeyCombinationManager.dump(prefix, pw); mSingleKeyGestureDetector.dump(prefix, pw); + mDeferredKeyActionExecutor.dump(prefix, pw); if (mWakeGestureListener != null) { mWakeGestureListener.dump(pw, prefix); @@ -6793,4 +6915,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { + " name."); } } + + /** A helper class to check button override permission. */ + static class ButtonOverridePermissionChecker { + boolean canAppOverrideSystemKey(Context context, int uid) { + return PermissionChecker.checkPermissionForDataDelivery( + context, + OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW, + PID_UNKNOWN, + uid, + null, + null, + null) + == PERMISSION_GRANTED; + } + } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index e1f1f662c5aa..b890a9e9bd04 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -5622,9 +5622,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (mKeyInterceptionInfo == null || mKeyInterceptionInfo.layoutParamsPrivateFlags != getAttrs().privateFlags || mKeyInterceptionInfo.layoutParamsType != getAttrs().type - || mKeyInterceptionInfo.windowTitle != getWindowTag()) { + || mKeyInterceptionInfo.windowTitle != getWindowTag() + || mKeyInterceptionInfo.windowOwnerUid != getOwningUid()) { mKeyInterceptionInfo = new KeyInterceptionInfo(getAttrs().type, getAttrs().privateFlags, - getWindowTag().toString()); + getWindowTag().toString(), getOwningUid()); } return mKeyInterceptionInfo; } diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java index ab35da69da7c..9cdec2588501 100644 --- a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java +++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java @@ -64,6 +64,7 @@ class ShortcutKeyTestBase { @Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule(); TestPhoneWindowManager mPhoneWindowManager; + DispatchedKeyHandler mDispatchedKeyHandler = event -> false; final Context mContext = spy(getInstrumentation().getTargetContext()); /** Modifier key to meta state */ @@ -102,6 +103,10 @@ class ShortcutKeyTestBase { mPhoneWindowManager = new TestPhoneWindowManager(mContext, supportSettingsUpdate); } + protected final void setDispatchedKeyHandler(DispatchedKeyHandler keyHandler) { + mDispatchedKeyHandler = keyHandler; + } + @After public void tearDown() { if (mPhoneWindowManager != null) { @@ -174,9 +179,20 @@ class ShortcutKeyTestBase { int actions = mPhoneWindowManager.interceptKeyBeforeQueueing(keyEvent); if ((actions & ACTION_PASS_TO_USER) != 0) { if (0 == mPhoneWindowManager.interceptKeyBeforeDispatching(keyEvent)) { - mPhoneWindowManager.dispatchUnhandledKey(keyEvent); + if (!mDispatchedKeyHandler.onKeyDispatched(keyEvent)) { + mPhoneWindowManager.dispatchUnhandledKey(keyEvent); + } } } mPhoneWindowManager.dispatchAllPendingEvents(); } + + interface DispatchedKeyHandler { + /** + * Called when a key event is dispatched to app. + * + * @return true if the event is consumed by app. + */ + boolean onKeyDispatched(KeyEvent event); + } } diff --git a/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java index 912e1d3df945..f7ad2a8f5243 100644 --- a/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java @@ -97,6 +97,35 @@ public class StemKeyGestureTests extends ShortcutKeyTestBase { } @Test + public void stemSingleKey_appHasOverridePermission_consumedByApp_notOpenAllApp() { + overrideBehavior(STEM_PRIMARY_BUTTON_SHORT_PRESS, SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS); + setUpPhoneWindowManager(/* supportSettingsUpdate= */ true); + mPhoneWindowManager.overrideStartActivity(); + mPhoneWindowManager.setKeyguardServiceDelegateIsShowing(false); + mPhoneWindowManager.overrideIsUserSetupComplete(true); + mPhoneWindowManager.overrideFocusedWindowButtonOverridePermission(true); + setDispatchedKeyHandler(keyEvent -> true); + + sendKey(KEYCODE_STEM_PRIMARY); + + mPhoneWindowManager.assertNotOpenAllAppView(); + } + + @Test + public void stemSingleKey_appHasOverridePermission_notConsumedByApp_openAllApp() { + overrideBehavior(STEM_PRIMARY_BUTTON_SHORT_PRESS, SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS); + setUpPhoneWindowManager(/* supportSettingsUpdate= */ true); + mPhoneWindowManager.overrideStartActivity(); + mPhoneWindowManager.setKeyguardServiceDelegateIsShowing(false); + mPhoneWindowManager.overrideIsUserSetupComplete(true); + mPhoneWindowManager.overrideFocusedWindowButtonOverridePermission(true); + + sendKey(KEYCODE_STEM_PRIMARY); + + mPhoneWindowManager.assertOpenAllAppView(); + } + + @Test public void stemLongKey_triggerSearchServiceToLaunchAssist() { overrideBehavior( STEM_PRIMARY_BUTTON_LONG_PRESS, @@ -165,6 +194,30 @@ public class StemKeyGestureTests extends ShortcutKeyTestBase { mPhoneWindowManager.assertSwitchToRecent(referenceId); } + @Test + public void stemDoubleKey_earlyShortPress_firstPressConsumedByApp_switchToMostRecent() + throws RemoteException { + overrideBehavior(STEM_PRIMARY_BUTTON_DOUBLE_PRESS, SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS); + setUpPhoneWindowManager(/* supportSettingsUpdate= */ true); + mPhoneWindowManager.overrideShouldEarlyShortPressOnStemPrimary(true); + mPhoneWindowManager.setKeyguardServiceDelegateIsShowing(false); + mPhoneWindowManager.overrideIsUserSetupComplete(true); + mPhoneWindowManager.overrideFocusedWindowButtonOverridePermission(true); + RecentTaskInfo recentTaskInfo = new RecentTaskInfo(); + int referenceId = 666; + recentTaskInfo.persistentId = referenceId; + doReturn(recentTaskInfo).when( + mPhoneWindowManager.mActivityTaskManagerInternal).getMostRecentTaskFromBackground(); + + setDispatchedKeyHandler(keyEvent -> true); + sendKey(KEYCODE_STEM_PRIMARY); + setDispatchedKeyHandler(keyEvent -> false); + sendKey(KEYCODE_STEM_PRIMARY); + + mPhoneWindowManager.assertNotOpenAllAppView(); + mPhoneWindowManager.assertSwitchToRecent(referenceId); + } + private void overrideBehavior(String key, int expectedBehavior) { Settings.Global.putLong(mContext.getContentResolver(), key, expectedBehavior); } 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 43c47458d19f..d057226836a3 100644 --- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java +++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java @@ -90,6 +90,7 @@ import android.view.autofill.AutofillManagerInternal; import com.android.dx.mockito.inline.extended.StaticMockitoSession; import com.android.internal.accessibility.AccessibilityShortcutController; +import com.android.internal.policy.KeyInterceptionInfo; import com.android.internal.util.FrameworkStatsLog; import com.android.server.GestureLauncherService; import com.android.server.LocalServices; @@ -162,6 +163,9 @@ class TestPhoneWindowManager { @Mock private KeyguardServiceDelegate mKeyguardServiceDelegate; + @Mock + private PhoneWindowManager.ButtonOverridePermissionChecker mButtonOverridePermissionChecker; + private StaticMockitoSession mMockitoSession; private OffsettableClock mClock = new OffsettableClock(); private TestLooper mTestLooper = new TestLooper(() -> mClock.now()); @@ -189,6 +193,10 @@ class TestPhoneWindowManager { IActivityManager getActivityManagerService() { return mActivityManagerService; } + + PhoneWindowManager.ButtonOverridePermissionChecker getButtonOverridePermissionChecker() { + return mButtonOverridePermissionChecker; + } } TestPhoneWindowManager(Context context, boolean supportSettingsUpdate) { @@ -304,6 +312,11 @@ class TestPhoneWindowManager { doReturn(false).when(mPhoneWindowManager).keyguardOn(); doNothing().when(mContext).startActivityAsUser(any(), any()); doNothing().when(mContext).startActivityAsUser(any(), any(), any()); + + KeyInterceptionInfo interceptionInfo = new KeyInterceptionInfo(0, 0, null, 0); + doReturn(interceptionInfo) + .when(mWindowManagerInternal).getKeyInterceptionInfoFromToken(any()); + Mockito.reset(mContext); } @@ -525,6 +538,11 @@ class TestPhoneWindowManager { mPhoneWindowManager.mPrimaryShortPressTargetActivity = component; } + void overrideFocusedWindowButtonOverridePermission(boolean granted) { + doReturn(granted) + .when(mButtonOverridePermissionChecker).canAppOverrideSystemKey(any(), anyInt()); + } + /** * Below functions will check the policy behavior could be invoked. */ |