Loading services/core/java/com/android/server/policy/PhoneWindowManager.java +26 −9 Original line number Diff line number Diff line Loading @@ -32,7 +32,6 @@ import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.O; import static android.os.IInputConstants.INVALID_INPUT_DEVICE_ID; import static android.provider.Settings.Secure.VOLUME_HUSH_OFF; import static android.view.contentprotection.flags.Flags.createAccessibilityOverlayAppOpEnabled; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.Display.STATE_OFF; Loading Loading @@ -69,6 +68,7 @@ import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_OTHER; import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN; import static android.view.WindowManagerGlobal.ADD_OKAY; import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED; import static android.view.contentprotection.flags.Flags.createAccessibilityOverlayAppOpEnabled; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_KEYCHORD_DELAY; import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_WEAR_TRIPLE_PRESS_GESTURE; Loading Loading @@ -101,6 +101,7 @@ import android.app.ActivityManager.RecentTaskInfo; import android.app.ActivityManagerInternal; import android.app.ActivityTaskManager; import android.app.AppOpsManager; import android.app.IActivityManager; import android.app.IUiModeManager; import android.app.NotificationManager; import android.app.ProgressDialog; Loading Loading @@ -427,6 +428,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowManagerInternal mWindowManagerInternal; PowerManager mPowerManager; ActivityManagerInternal mActivityManagerInternal; IActivityManager mActivityManagerService; ActivityTaskManagerInternal mActivityTaskManagerInternal; AutofillManagerInternal mAutofillManagerInternal; InputManager mInputManager; Loading Loading @@ -549,7 +551,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mLidNavigationAccessibility; int mShortPressOnPowerBehavior; private boolean mShouldEarlyShortPressOnPower; private boolean mShouldEarlyShortPressOnStemPrimary; boolean mShouldEarlyShortPressOnStemPrimary; int mLongPressOnPowerBehavior; long mLongPressOnPowerAssistantTimeoutMs; int mVeryLongPressOnPowerBehavior; Loading Loading @@ -578,6 +580,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private int mDoublePressOnStemPrimaryBehavior; private int mTriplePressOnStemPrimaryBehavior; private int mLongPressOnStemPrimaryBehavior; private RecentTaskInfo mBackgroundRecentTaskInfoOnStemPrimarySingleKeyUp; private boolean mHandleVolumeKeysInWM; Loading Loading @@ -1563,7 +1566,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { ? false : mKeyguardDelegate.isShowing(); if (!keyguardActive) { switchRecentTask(); performStemPrimaryDoublePressSwitchToRecentTask(); } break; } Loading Loading @@ -1672,11 +1675,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** * Load most recent task (expect current task) and bring it to the front. */ private void switchRecentTask() { RecentTaskInfo targetTask = mActivityTaskManagerInternal.getMostRecentTaskFromBackground(); void performStemPrimaryDoublePressSwitchToRecentTask() { RecentTaskInfo targetTask = mBackgroundRecentTaskInfoOnStemPrimarySingleKeyUp; if (targetTask == null) { if (DEBUG_INPUT) { Slog.w(TAG, "No recent task available! Show watch face."); Slog.w(TAG, "No recent task available! Show wallpaper."); } goHome(); return; Loading @@ -1695,7 +1698,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { + targetTask.baseIntent); } try { ActivityManager.getService().startActivityFromRecents(targetTask.persistentId, null); mActivityManagerService.startActivityFromRecents(targetTask.persistentId, null); } catch (RemoteException | IllegalArgumentException e) { Slog.e(TAG, "Failed to start task " + targetTask.persistentId + " from recents", e); } Loading Loading @@ -2219,6 +2222,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }); } IActivityManager getActivityManagerService() { return ActivityManager.getService(); } } /** {@inheritDoc} */ Loading @@ -2233,6 +2240,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mWindowManagerFuncs = injector.getWindowManagerFuncs(); mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mActivityManagerService = injector.getActivityManagerService(); mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class); mInputManager = mContext.getSystemService(InputManager.class); mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); Loading Loading @@ -2767,11 +2775,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override void onKeyUp(long eventTime, int count) { if (mShouldEarlyShortPressOnStemPrimary && count == 1) { if (count == 1) { // Save info about the most recent task on the first press of the stem key. This // may be used later to switch to the most recent app using double press gesture. // It is possible that we may navigate away from this task before the double // press is detected, as a result of the first press, so we save the current // most recent task before that happens. mBackgroundRecentTaskInfoOnStemPrimarySingleKeyUp = mActivityTaskManagerInternal.getMostRecentTaskFromBackground(); if (mShouldEarlyShortPressOnStemPrimary) { stemPrimaryPress(1 /*pressCount*/); } } } } private void initSingleKeyGestureRules(Looper looper) { mSingleKeyGestureDetector = SingleKeyGestureDetector.get(mContext, looper); Loading services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java +44 −0 Original line number Diff line number Diff line Loading @@ -16,15 +16,19 @@ package com.android.server.policy; import static android.provider.Settings.Global.STEM_PRIMARY_BUTTON_DOUBLE_PRESS; import static android.provider.Settings.Global.STEM_PRIMARY_BUTTON_LONG_PRESS; import static android.provider.Settings.Global.STEM_PRIMARY_BUTTON_SHORT_PRESS; import static android.view.KeyEvent.KEYCODE_STEM_PRIMARY; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_PRIMARY_LAUNCH_VOICE_ASSISTANT; import static com.android.server.policy.PhoneWindowManager.SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS; import static com.android.server.policy.PhoneWindowManager.SHORT_PRESS_PRIMARY_LAUNCH_TARGET_ACTIVITY; import android.app.ActivityManager.RecentTaskInfo; import android.content.ComponentName; import android.os.RemoteException; import android.provider.Settings; import org.junit.Test; Loading Loading @@ -120,6 +124,46 @@ public class StemKeyGestureTests extends ShortcutKeyTestBase { mPhoneWindowManager.assertStatusBarStartAssist(); } @Test public void stemDoubleKey_EarlyShortPress_AllAppsThenSwitchToMostRecent() 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); RecentTaskInfo recentTaskInfo = new RecentTaskInfo(); int referenceId = 666; recentTaskInfo.persistentId = referenceId; doReturn(recentTaskInfo).when( mPhoneWindowManager.mActivityTaskManagerInternal).getMostRecentTaskFromBackground(); sendKey(KEYCODE_STEM_PRIMARY); sendKey(KEYCODE_STEM_PRIMARY); mPhoneWindowManager.assertOpenAllAppView(); mPhoneWindowManager.assertSwitchToRecent(referenceId); } @Test public void stemDoubleKey_NoEarlyShortPress_SwitchToMostRecent() throws RemoteException { overrideBehavior(STEM_PRIMARY_BUTTON_DOUBLE_PRESS, SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS); setUpPhoneWindowManager(/* supportSettingsUpdate= */ true); mPhoneWindowManager.overrideShouldEarlyShortPressOnStemPrimary(false); mPhoneWindowManager.setKeyguardServiceDelegateIsShowing(false); mPhoneWindowManager.overrideIsUserSetupComplete(true); RecentTaskInfo recentTaskInfo = new RecentTaskInfo(); int referenceId = 666; recentTaskInfo.persistentId = referenceId; doReturn(recentTaskInfo).when( mPhoneWindowManager.mActivityTaskManagerInternal).getMostRecentTaskFromBackground(); sendKey(KEYCODE_STEM_PRIMARY); sendKey(KEYCODE_STEM_PRIMARY); mPhoneWindowManager.assertNotOpenAllAppView(); mPhoneWindowManager.assertSwitchToRecent(referenceId); } private void overrideBehavior(String key, int expectedBehavior) { Settings.Global.putLong(mContext.getContentResolver(), key, expectedBehavior); Loading services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java +18 −1 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ import static org.mockito.Mockito.withSettings; import android.app.ActivityManagerInternal; import android.app.AppOpsManager; import android.app.IActivityManager; import android.app.NotificationManager; import android.app.SearchManager; import android.content.ComponentName; Loading Loading @@ -126,7 +127,8 @@ class TestPhoneWindowManager { @Mock private WindowManagerInternal mWindowManagerInternal; @Mock private ActivityManagerInternal mActivityManagerInternal; @Mock private ActivityTaskManagerInternal mActivityTaskManagerInternal; @Mock ActivityTaskManagerInternal mActivityTaskManagerInternal; @Mock IActivityManager mActivityManagerService; @Mock private InputManagerInternal mInputManagerInternal; @Mock private InputManager mInputManager; @Mock private SensorPrivacyManager mSensorPrivacyManager; Loading Loading @@ -181,6 +183,10 @@ class TestPhoneWindowManager { KeyguardServiceDelegate getKeyguardServiceDelegate() { return mKeyguardServiceDelegate; } IActivityManager getActivityManagerService() { return mActivityManagerService; } } TestPhoneWindowManager(Context context, boolean supportSettingsUpdate) { Loading Loading @@ -347,6 +353,10 @@ class TestPhoneWindowManager { mPhoneWindowManager.mShortPressOnPowerBehavior = behavior; } void overrideShouldEarlyShortPressOnStemPrimary(boolean shouldEarlyShortPress) { mPhoneWindowManager.mShouldEarlyShortPressOnStemPrimary = shouldEarlyShortPress; } // Override assist perform function. void overrideLongPressOnPower(int behavior) { mPhoneWindowManager.mLongPressOnPowerBehavior = behavior; Loading Loading @@ -667,4 +677,11 @@ class TestPhoneWindowManager { vendorId, productId, logEvent.getIntValue(), new int[]{expectedKey}, expectedModifierState), description(errorMsg)); } void assertSwitchToRecent(int persistentId) throws RemoteException { mTestLooper.dispatchAll(); verify(mActivityManagerService, timeout(TEST_SINGLE_KEY_DELAY_MILLIS)).startActivityFromRecents(eq(persistentId), isNull()); } } Loading
services/core/java/com/android/server/policy/PhoneWindowManager.java +26 −9 Original line number Diff line number Diff line Loading @@ -32,7 +32,6 @@ import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.O; import static android.os.IInputConstants.INVALID_INPUT_DEVICE_ID; import static android.provider.Settings.Secure.VOLUME_HUSH_OFF; import static android.view.contentprotection.flags.Flags.createAccessibilityOverlayAppOpEnabled; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.Display.STATE_OFF; Loading Loading @@ -69,6 +68,7 @@ import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_OTHER; import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN; import static android.view.WindowManagerGlobal.ADD_OKAY; import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED; import static android.view.contentprotection.flags.Flags.createAccessibilityOverlayAppOpEnabled; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_KEYCHORD_DELAY; import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_WEAR_TRIPLE_PRESS_GESTURE; Loading Loading @@ -101,6 +101,7 @@ import android.app.ActivityManager.RecentTaskInfo; import android.app.ActivityManagerInternal; import android.app.ActivityTaskManager; import android.app.AppOpsManager; import android.app.IActivityManager; import android.app.IUiModeManager; import android.app.NotificationManager; import android.app.ProgressDialog; Loading Loading @@ -427,6 +428,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowManagerInternal mWindowManagerInternal; PowerManager mPowerManager; ActivityManagerInternal mActivityManagerInternal; IActivityManager mActivityManagerService; ActivityTaskManagerInternal mActivityTaskManagerInternal; AutofillManagerInternal mAutofillManagerInternal; InputManager mInputManager; Loading Loading @@ -549,7 +551,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mLidNavigationAccessibility; int mShortPressOnPowerBehavior; private boolean mShouldEarlyShortPressOnPower; private boolean mShouldEarlyShortPressOnStemPrimary; boolean mShouldEarlyShortPressOnStemPrimary; int mLongPressOnPowerBehavior; long mLongPressOnPowerAssistantTimeoutMs; int mVeryLongPressOnPowerBehavior; Loading Loading @@ -578,6 +580,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private int mDoublePressOnStemPrimaryBehavior; private int mTriplePressOnStemPrimaryBehavior; private int mLongPressOnStemPrimaryBehavior; private RecentTaskInfo mBackgroundRecentTaskInfoOnStemPrimarySingleKeyUp; private boolean mHandleVolumeKeysInWM; Loading Loading @@ -1563,7 +1566,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { ? false : mKeyguardDelegate.isShowing(); if (!keyguardActive) { switchRecentTask(); performStemPrimaryDoublePressSwitchToRecentTask(); } break; } Loading Loading @@ -1672,11 +1675,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** * Load most recent task (expect current task) and bring it to the front. */ private void switchRecentTask() { RecentTaskInfo targetTask = mActivityTaskManagerInternal.getMostRecentTaskFromBackground(); void performStemPrimaryDoublePressSwitchToRecentTask() { RecentTaskInfo targetTask = mBackgroundRecentTaskInfoOnStemPrimarySingleKeyUp; if (targetTask == null) { if (DEBUG_INPUT) { Slog.w(TAG, "No recent task available! Show watch face."); Slog.w(TAG, "No recent task available! Show wallpaper."); } goHome(); return; Loading @@ -1695,7 +1698,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { + targetTask.baseIntent); } try { ActivityManager.getService().startActivityFromRecents(targetTask.persistentId, null); mActivityManagerService.startActivityFromRecents(targetTask.persistentId, null); } catch (RemoteException | IllegalArgumentException e) { Slog.e(TAG, "Failed to start task " + targetTask.persistentId + " from recents", e); } Loading Loading @@ -2219,6 +2222,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }); } IActivityManager getActivityManagerService() { return ActivityManager.getService(); } } /** {@inheritDoc} */ Loading @@ -2233,6 +2240,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mWindowManagerFuncs = injector.getWindowManagerFuncs(); mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mActivityManagerService = injector.getActivityManagerService(); mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class); mInputManager = mContext.getSystemService(InputManager.class); mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); Loading Loading @@ -2767,11 +2775,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override void onKeyUp(long eventTime, int count) { if (mShouldEarlyShortPressOnStemPrimary && count == 1) { if (count == 1) { // Save info about the most recent task on the first press of the stem key. This // may be used later to switch to the most recent app using double press gesture. // It is possible that we may navigate away from this task before the double // press is detected, as a result of the first press, so we save the current // most recent task before that happens. mBackgroundRecentTaskInfoOnStemPrimarySingleKeyUp = mActivityTaskManagerInternal.getMostRecentTaskFromBackground(); if (mShouldEarlyShortPressOnStemPrimary) { stemPrimaryPress(1 /*pressCount*/); } } } } private void initSingleKeyGestureRules(Looper looper) { mSingleKeyGestureDetector = SingleKeyGestureDetector.get(mContext, looper); Loading
services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java +44 −0 Original line number Diff line number Diff line Loading @@ -16,15 +16,19 @@ package com.android.server.policy; import static android.provider.Settings.Global.STEM_PRIMARY_BUTTON_DOUBLE_PRESS; import static android.provider.Settings.Global.STEM_PRIMARY_BUTTON_LONG_PRESS; import static android.provider.Settings.Global.STEM_PRIMARY_BUTTON_SHORT_PRESS; import static android.view.KeyEvent.KEYCODE_STEM_PRIMARY; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_PRIMARY_LAUNCH_VOICE_ASSISTANT; import static com.android.server.policy.PhoneWindowManager.SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS; import static com.android.server.policy.PhoneWindowManager.SHORT_PRESS_PRIMARY_LAUNCH_TARGET_ACTIVITY; import android.app.ActivityManager.RecentTaskInfo; import android.content.ComponentName; import android.os.RemoteException; import android.provider.Settings; import org.junit.Test; Loading Loading @@ -120,6 +124,46 @@ public class StemKeyGestureTests extends ShortcutKeyTestBase { mPhoneWindowManager.assertStatusBarStartAssist(); } @Test public void stemDoubleKey_EarlyShortPress_AllAppsThenSwitchToMostRecent() 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); RecentTaskInfo recentTaskInfo = new RecentTaskInfo(); int referenceId = 666; recentTaskInfo.persistentId = referenceId; doReturn(recentTaskInfo).when( mPhoneWindowManager.mActivityTaskManagerInternal).getMostRecentTaskFromBackground(); sendKey(KEYCODE_STEM_PRIMARY); sendKey(KEYCODE_STEM_PRIMARY); mPhoneWindowManager.assertOpenAllAppView(); mPhoneWindowManager.assertSwitchToRecent(referenceId); } @Test public void stemDoubleKey_NoEarlyShortPress_SwitchToMostRecent() throws RemoteException { overrideBehavior(STEM_PRIMARY_BUTTON_DOUBLE_PRESS, SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS); setUpPhoneWindowManager(/* supportSettingsUpdate= */ true); mPhoneWindowManager.overrideShouldEarlyShortPressOnStemPrimary(false); mPhoneWindowManager.setKeyguardServiceDelegateIsShowing(false); mPhoneWindowManager.overrideIsUserSetupComplete(true); RecentTaskInfo recentTaskInfo = new RecentTaskInfo(); int referenceId = 666; recentTaskInfo.persistentId = referenceId; doReturn(recentTaskInfo).when( mPhoneWindowManager.mActivityTaskManagerInternal).getMostRecentTaskFromBackground(); sendKey(KEYCODE_STEM_PRIMARY); sendKey(KEYCODE_STEM_PRIMARY); mPhoneWindowManager.assertNotOpenAllAppView(); mPhoneWindowManager.assertSwitchToRecent(referenceId); } private void overrideBehavior(String key, int expectedBehavior) { Settings.Global.putLong(mContext.getContentResolver(), key, expectedBehavior); Loading
services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java +18 −1 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ import static org.mockito.Mockito.withSettings; import android.app.ActivityManagerInternal; import android.app.AppOpsManager; import android.app.IActivityManager; import android.app.NotificationManager; import android.app.SearchManager; import android.content.ComponentName; Loading Loading @@ -126,7 +127,8 @@ class TestPhoneWindowManager { @Mock private WindowManagerInternal mWindowManagerInternal; @Mock private ActivityManagerInternal mActivityManagerInternal; @Mock private ActivityTaskManagerInternal mActivityTaskManagerInternal; @Mock ActivityTaskManagerInternal mActivityTaskManagerInternal; @Mock IActivityManager mActivityManagerService; @Mock private InputManagerInternal mInputManagerInternal; @Mock private InputManager mInputManager; @Mock private SensorPrivacyManager mSensorPrivacyManager; Loading Loading @@ -181,6 +183,10 @@ class TestPhoneWindowManager { KeyguardServiceDelegate getKeyguardServiceDelegate() { return mKeyguardServiceDelegate; } IActivityManager getActivityManagerService() { return mActivityManagerService; } } TestPhoneWindowManager(Context context, boolean supportSettingsUpdate) { Loading Loading @@ -347,6 +353,10 @@ class TestPhoneWindowManager { mPhoneWindowManager.mShortPressOnPowerBehavior = behavior; } void overrideShouldEarlyShortPressOnStemPrimary(boolean shouldEarlyShortPress) { mPhoneWindowManager.mShouldEarlyShortPressOnStemPrimary = shouldEarlyShortPress; } // Override assist perform function. void overrideLongPressOnPower(int behavior) { mPhoneWindowManager.mLongPressOnPowerBehavior = behavior; Loading Loading @@ -667,4 +677,11 @@ class TestPhoneWindowManager { vendorId, productId, logEvent.getIntValue(), new int[]{expectedKey}, expectedModifierState), description(errorMsg)); } void assertSwitchToRecent(int persistentId) throws RemoteException { mTestLooper.dispatchAll(); verify(mActivityManagerService, timeout(TEST_SINGLE_KEY_DELAY_MILLIS)).startActivityFromRecents(eq(persistentId), isNull()); } }