Loading services/core/java/com/android/server/policy/PhoneWindowManager.java +21 −54 Original line number Diff line number Diff line Loading @@ -185,7 +185,6 @@ import android.view.autofill.AutofillManagerInternal; import com.android.internal.R; import com.android.internal.accessibility.AccessibilityShortcutController; import com.android.internal.accessibility.util.AccessibilityUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.AssistUtils; import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.internal.logging.MetricsLogger; Loading Loading @@ -1545,6 +1544,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { } void showGlobalActionsInternal() { if (mGlobalActions == null) { mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs); } final boolean keyguardShowing = isKeyguardShowingAndNotOccluded(); mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned()); // since it took two seconds of long press to bring this up, Loading Loading @@ -1867,45 +1869,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { mDefaultDisplayPolicy = mDefaultDisplayRotation.getDisplayPolicy(); } /** Point of injection for test dependencies. */ @VisibleForTesting static class Injector { private final Context mContext; private final WindowManagerFuncs mWindowManagerFuncs; Injector(Context context, WindowManagerFuncs funcs) { mContext = context; mWindowManagerFuncs = funcs; } Context getContext() { return mContext; } WindowManagerFuncs getWindowManagerFuncs() { return mWindowManagerFuncs; } AccessibilityShortcutController getAccessibilityShortcutController( Context context, Handler handler, int initialUserId) { return new AccessibilityShortcutController(context, handler, initialUserId); } GlobalActions getGlobalActions() { return new GlobalActions(mContext, mWindowManagerFuncs); } } /** {@inheritDoc} */ @Override public void init(Context context, WindowManagerFuncs funcs) { init(new Injector(context, funcs)); } @VisibleForTesting void init(Injector injector) { mContext = injector.getContext(); mWindowManagerFuncs = injector.getWindowManagerFuncs(); public void init(Context context, WindowManagerFuncs windowManagerFuncs) { mContext = context; mWindowManagerFuncs = windowManagerFuncs; mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class); Loading @@ -1920,9 +1888,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHasFeatureLeanback = mPackageManager.hasSystemFeature(FEATURE_LEANBACK); mHasFeatureAuto = mPackageManager.hasSystemFeature(FEATURE_AUTOMOTIVE); mHasFeatureHdmiCec = mPackageManager.hasSystemFeature(FEATURE_HDMI_CEC); mAccessibilityShortcutController = injector.getAccessibilityShortcutController( mContext, new Handler(), mCurrentUserId); mGlobalActions = injector.getGlobalActions(); mAccessibilityShortcutController = new AccessibilityShortcutController(mContext, new Handler(), mCurrentUserId); mLogger = new MetricsLogger(); mScreenOffSleepTokenAcquirer = mActivityTaskManagerInternal Loading @@ -1937,7 +1904,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { res.getBoolean(com.android.internal.R.bool.config_wakeOnBackKeyPress); // Init display burn-in protection boolean burnInProtectionEnabled = mContext.getResources().getBoolean( boolean burnInProtectionEnabled = context.getResources().getBoolean( com.android.internal.R.bool.config_enableBurnInProtection); // Allow a system property to override this. Used by developer settings. boolean burnInProtectionDevMode = Loading @@ -1955,7 +1922,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { maxVertical = -4; maxRadius = (isRoundWindow()) ? 6 : -1; } else { Resources resources = mContext.getResources(); Resources resources = context.getResources(); minHorizontal = resources.getInteger( com.android.internal.R.integer.config_burnInProtectionMinHorizontalOffset); maxHorizontal = resources.getInteger( Loading @@ -1968,21 +1935,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.integer.config_burnInProtectionMaxRadius); } mBurnInProtectionHelper = new BurnInProtectionHelper( mContext, minHorizontal, maxHorizontal, minVertical, maxVertical, maxRadius); context, minHorizontal, maxHorizontal, minVertical, maxVertical, maxRadius); } mHandler = new PolicyHandler(); mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler); mSettingsObserver = new SettingsObserver(mHandler); mSettingsObserver.observe(); mModifierShortcutManager = new ModifierShortcutManager(mContext); mUiMode = mContext.getResources().getInteger( mModifierShortcutManager = new ModifierShortcutManager(context); mUiMode = context.getResources().getInteger( com.android.internal.R.integer.config_defaultUiModeType); mHomeIntent = new Intent(Intent.ACTION_MAIN, null); mHomeIntent.addCategory(Intent.CATEGORY_HOME); mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); mEnableCarDockHomeCapture = mContext.getResources().getBoolean( mEnableCarDockHomeCapture = context.getResources().getBoolean( com.android.internal.R.bool.config_enableCarDockHomeLaunch); mCarDockIntent = new Intent(Intent.ACTION_MAIN, null); mCarDockIntent.addCategory(Intent.CATEGORY_CAR_DOCK); Loading @@ -1997,7 +1964,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mVrHeadsetHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mBroadcastWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PhoneWindowManager.mBroadcastWakeLock"); mPowerKeyWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, Loading Loading @@ -2069,9 +2036,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { readConfigurationDependentBehaviors(); mDisplayFoldController = DisplayFoldController.create(mContext, DEFAULT_DISPLAY); mDisplayFoldController = DisplayFoldController.create(context, DEFAULT_DISPLAY); mAccessibilityManager = (AccessibilityManager) mContext.getSystemService( mAccessibilityManager = (AccessibilityManager) context.getSystemService( Context.ACCESSIBILITY_SERVICE); // register for dock events Loading @@ -2081,7 +2048,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { filter.addAction(UiModeManager.ACTION_ENTER_DESK_MODE); filter.addAction(UiModeManager.ACTION_EXIT_DESK_MODE); filter.addAction(Intent.ACTION_DOCK_EVENT); Intent intent = mContext.registerReceiver(mDockReceiver, filter); Intent intent = context.registerReceiver(mDockReceiver, filter); if (intent != null) { // Retrieve current sticky dock event broadcast. mDefaultDisplayPolicy.setDockMode(intent.getIntExtra(Intent.EXTRA_DOCK_STATE, Loading @@ -2092,13 +2059,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { filter = new IntentFilter(); filter.addAction(Intent.ACTION_DREAMING_STARTED); filter.addAction(Intent.ACTION_DREAMING_STOPPED); mContext.registerReceiver(mDreamReceiver, filter); context.registerReceiver(mDreamReceiver, filter); // register for multiuser-relevant broadcasts filter = new IntentFilter(Intent.ACTION_USER_SWITCHED); mContext.registerReceiver(mMultiuserReceiver, filter); context.registerReceiver(mMultiuserReceiver, filter); mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE); mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(), com.android.internal.R.array.config_safeModeEnabledVibePattern); Loading services/tests/wmtests/src/com/android/server/policy/CombinationKeyTests.javadeleted 100644 → 0 +0 −78 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.policy; import static android.view.KeyEvent.KEYCODE_POWER; import static android.view.KeyEvent.KEYCODE_VOLUME_DOWN; import static android.view.KeyEvent.KEYCODE_VOLUME_UP; import static com.android.server.policy.PhoneWindowManager.POWER_VOLUME_UP_BEHAVIOR_GLOBAL_ACTIONS; import static com.android.server.policy.PhoneWindowManager.POWER_VOLUME_UP_BEHAVIOR_MUTE; import android.view.ViewConfiguration; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; /** * Test class for combination key shortcuts. * * Build/Install/Run: * atest WmTests:CombinationKeyTests */ @MediumTest @RunWith(AndroidJUnit4.class) public class CombinationKeyTests extends ShortcutKeyTestBase { private static final long A11Y_KEY_HOLD_MILLIS = 3500; /** * Power-VolDown to take screenshot. */ @Test public void testPowerVolumeDown() { sendKeyCombination(new int[]{KEYCODE_POWER, KEYCODE_VOLUME_DOWN}, ViewConfiguration.get(mContext).getScreenshotChordKeyTimeout()); mPhoneWindowManager.assertTakeScreenshotCalled(); } /** * Power-VolUp to show global actions or mute audio. (Phone default behavior) */ @Test public void testPowerVolumeUp() { // Show global actions. mPhoneWindowManager.overridePowerVolumeUp(POWER_VOLUME_UP_BEHAVIOR_GLOBAL_ACTIONS); sendKeyCombination(new int[]{KEYCODE_POWER, KEYCODE_VOLUME_UP}, 0); mPhoneWindowManager.assertShowGlobalActionsCalled(); // Mute audio (hold over 100ms). mPhoneWindowManager.overridePowerVolumeUp(POWER_VOLUME_UP_BEHAVIOR_MUTE); sendKeyCombination(new int[]{KEYCODE_POWER, KEYCODE_VOLUME_UP}, 100); mPhoneWindowManager.assertVolumeMute(); } /** * VolDown-VolUp and hold 3 secs to enable accessibility service. */ @Test public void testVolumeDownVolumeUp() { sendKeyCombination(new int[]{KEYCODE_VOLUME_DOWN, KEYCODE_VOLUME_UP}, A11Y_KEY_HOLD_MILLIS); mPhoneWindowManager.assertAccessibilityKeychordCalled(); } } services/tests/wmtests/src/com/android/server/policy/KeyCombinationManagerTests.java→services/tests/wmtests/src/com/android/server/policy/KeyCombinationTests.java +3 −3 Original line number Diff line number Diff line Loading @@ -43,11 +43,11 @@ import java.util.concurrent.TimeUnit; * Test class for {@link KeyCombinationManager}. * * Build/Install/Run: * atest KeyCombinationManagerTests * atest KeyCombinationTests */ @SmallTest public class KeyCombinationManagerTests { public class KeyCombinationTests { private KeyCombinationManager mKeyCombinationManager; private final CountDownLatch mAction1Triggered = new CountDownLatch(1); Loading services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.javadeleted 100644 → 0 +0 −84 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.policy; import static android.view.KeyEvent.KEYCODE_POWER; import static android.view.KeyEvent.KEYCODE_VOLUME_UP; import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_ASSISTANT; import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_GLOBAL_ACTIONS; import android.view.Display; import org.junit.Test; /** * Test class for power key gesture. * * Build/Install/Run: * atest WmTests:PowerKeyGestureTests */ public class PowerKeyGestureTests extends ShortcutKeyTestBase { /** * Power single press to turn screen on/off. */ @Test public void testPowerSinglePress() { sendKey(KEYCODE_POWER); mPhoneWindowManager.assertPowerSleep(); // turn screen on when begin from non-interactive. mPhoneWindowManager.overrideDisplayState(Display.STATE_OFF); sendKey(KEYCODE_POWER); mPhoneWindowManager.assertPowerWakeUp(); mPhoneWindowManager.assertNoPowerSleep(); } /** * Power double press to trigger camera. */ @Test public void testPowerDoublePress() { sendKey(KEYCODE_POWER); sendKey(KEYCODE_POWER); mPhoneWindowManager.assertCameraLaunch(); } /** * Power long press to show assistant or global actions. */ @Test public void testPowerLongPress() { // Show assistant. mPhoneWindowManager.overrideLongPressOnPower(LONG_PRESS_POWER_ASSISTANT); sendKey(KEYCODE_POWER, true); mPhoneWindowManager.assertAssistLaunch(); // Show global actions. mPhoneWindowManager.overrideLongPressOnPower(LONG_PRESS_POWER_GLOBAL_ACTIONS); sendKey(KEYCODE_POWER, true); mPhoneWindowManager.assertShowGlobalActionsCalled(); } /** * Ignore power press if combination key already triggered. */ @Test public void testIgnoreSinglePressWhenCombinationKeyTriggered() { sendKeyCombination(new int[]{KEYCODE_POWER, KEYCODE_VOLUME_UP}, 0); mPhoneWindowManager.assertNoPowerSleep(); } } services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.javadeleted 100644 → 0 +0 −169 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.policy; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.KeyEvent.KEYCODE_ALT_LEFT; import static android.view.KeyEvent.KEYCODE_ALT_RIGHT; import static android.view.KeyEvent.KEYCODE_CTRL_LEFT; import static android.view.KeyEvent.KEYCODE_CTRL_RIGHT; import static android.view.KeyEvent.KEYCODE_META_LEFT; import static android.view.KeyEvent.KEYCODE_META_RIGHT; import static android.view.KeyEvent.KEYCODE_SHIFT_LEFT; import static android.view.KeyEvent.KEYCODE_SHIFT_RIGHT; import static android.view.KeyEvent.META_ALT_LEFT_ON; import static android.view.KeyEvent.META_ALT_ON; import static android.view.KeyEvent.META_ALT_RIGHT_ON; import static android.view.KeyEvent.META_CTRL_LEFT_ON; import static android.view.KeyEvent.META_CTRL_ON; import static android.view.KeyEvent.META_CTRL_RIGHT_ON; import static android.view.KeyEvent.META_META_LEFT_ON; import static android.view.KeyEvent.META_META_ON; import static android.view.KeyEvent.META_META_RIGHT_ON; import static android.view.KeyEvent.META_SHIFT_LEFT_ON; import static android.view.KeyEvent.META_SHIFT_ON; import static android.view.KeyEvent.META_SHIFT_RIGHT_ON; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static com.android.server.policy.WindowManagerPolicy.ACTION_PASS_TO_USER; import static java.util.Collections.unmodifiableMap; import android.content.Context; import android.os.Looper; import android.os.SystemClock; import android.util.ArrayMap; import android.view.InputDevice; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.ViewConfiguration; import org.junit.After; import org.junit.Before; import java.util.Map; class ShortcutKeyTestBase { TestPhoneWindowManager mPhoneWindowManager; final Context mContext = getInstrumentation().getTargetContext(); /** Modifier key to meta state */ private static final Map<Integer, Integer> MODIFIER; static { final Map<Integer, Integer> map = new ArrayMap<>(); map.put(KEYCODE_CTRL_LEFT, META_CTRL_LEFT_ON | META_CTRL_ON); map.put(KEYCODE_CTRL_RIGHT, META_CTRL_RIGHT_ON | META_CTRL_ON); map.put(KEYCODE_ALT_LEFT, META_ALT_LEFT_ON | META_ALT_ON); map.put(KEYCODE_ALT_RIGHT, META_ALT_RIGHT_ON | META_ALT_ON); map.put(KEYCODE_SHIFT_LEFT, META_SHIFT_LEFT_ON | META_SHIFT_ON); map.put(KEYCODE_SHIFT_RIGHT, META_SHIFT_RIGHT_ON | META_SHIFT_ON); map.put(KEYCODE_META_LEFT, META_META_LEFT_ON | META_META_ON); map.put(KEYCODE_META_RIGHT, META_META_RIGHT_ON | META_META_ON); MODIFIER = unmodifiableMap(map); } @Before public void setUp() { if (Looper.myLooper() == null) { Looper.prepare(); } mPhoneWindowManager = new TestPhoneWindowManager(mContext); } @After public void tearDown() { mPhoneWindowManager.tearDown(); } void sendKeyCombination(int[] keyCodes, long duration) { final long downTime = SystemClock.uptimeMillis(); final int count = keyCodes.length; final KeyEvent[] events = new KeyEvent[count]; int metaState = 0; for (int i = 0; i < count; i++) { final int keyCode = keyCodes[i]; final KeyEvent event = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0 /*repeat*/, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/, InputDevice.SOURCE_KEYBOARD); event.setDisplayId(DEFAULT_DISPLAY); events[i] = event; // The order is important here, metaState could be updated and applied to the next key. metaState |= MODIFIER.getOrDefault(keyCode, 0); } for (KeyEvent event: events) { interceptKey(event); } try { Thread.sleep(duration); } catch (InterruptedException e) { throw new RuntimeException(e); } for (KeyEvent event: events) { final long eventTime = SystemClock.uptimeMillis(); final int keyCode = event.getKeyCode(); final KeyEvent upEvent = new KeyEvent(downTime, eventTime, KeyEvent.ACTION_UP, keyCode, 0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/, InputDevice.SOURCE_KEYBOARD); interceptKey(upEvent); metaState &= ~MODIFIER.getOrDefault(keyCode, 0); } } void sendKey(int keyCode) { sendKey(keyCode, false); } void sendKey(int keyCode, boolean longPress) { final long downTime = SystemClock.uptimeMillis(); final KeyEvent event = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0 /*repeat*/, 0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/, InputDevice.SOURCE_KEYBOARD); event.setDisplayId(DEFAULT_DISPLAY); interceptKey(event); if (longPress) { final long nextDownTime = downTime + ViewConfiguration.getLongPressTimeout(); final KeyEvent nextDownevent = new KeyEvent(downTime, nextDownTime, KeyEvent.ACTION_DOWN, keyCode, 1 /*repeat*/, 0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, KeyEvent.FLAG_LONG_PRESS /*flags*/, InputDevice.SOURCE_KEYBOARD); interceptKey(nextDownevent); } final long eventTime = longPress ? SystemClock.uptimeMillis() + ViewConfiguration.getLongPressTimeout() : SystemClock.uptimeMillis(); final KeyEvent upEvent = new KeyEvent(downTime, eventTime, KeyEvent.ACTION_UP, keyCode, 0 /*repeat*/, 0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/, InputDevice.SOURCE_KEYBOARD); interceptKey(upEvent); } private void interceptKey(KeyEvent keyEvent) { int actions = mPhoneWindowManager.interceptKeyBeforeQueueing(keyEvent); if ((actions & ACTION_PASS_TO_USER) != 0) { if (0 == mPhoneWindowManager.interceptKeyBeforeDispatching(keyEvent)) { mPhoneWindowManager.dispatchUnhandledKey(keyEvent); } } } } Loading
services/core/java/com/android/server/policy/PhoneWindowManager.java +21 −54 Original line number Diff line number Diff line Loading @@ -185,7 +185,6 @@ import android.view.autofill.AutofillManagerInternal; import com.android.internal.R; import com.android.internal.accessibility.AccessibilityShortcutController; import com.android.internal.accessibility.util.AccessibilityUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.AssistUtils; import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.internal.logging.MetricsLogger; Loading Loading @@ -1545,6 +1544,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { } void showGlobalActionsInternal() { if (mGlobalActions == null) { mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs); } final boolean keyguardShowing = isKeyguardShowingAndNotOccluded(); mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned()); // since it took two seconds of long press to bring this up, Loading Loading @@ -1867,45 +1869,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { mDefaultDisplayPolicy = mDefaultDisplayRotation.getDisplayPolicy(); } /** Point of injection for test dependencies. */ @VisibleForTesting static class Injector { private final Context mContext; private final WindowManagerFuncs mWindowManagerFuncs; Injector(Context context, WindowManagerFuncs funcs) { mContext = context; mWindowManagerFuncs = funcs; } Context getContext() { return mContext; } WindowManagerFuncs getWindowManagerFuncs() { return mWindowManagerFuncs; } AccessibilityShortcutController getAccessibilityShortcutController( Context context, Handler handler, int initialUserId) { return new AccessibilityShortcutController(context, handler, initialUserId); } GlobalActions getGlobalActions() { return new GlobalActions(mContext, mWindowManagerFuncs); } } /** {@inheritDoc} */ @Override public void init(Context context, WindowManagerFuncs funcs) { init(new Injector(context, funcs)); } @VisibleForTesting void init(Injector injector) { mContext = injector.getContext(); mWindowManagerFuncs = injector.getWindowManagerFuncs(); public void init(Context context, WindowManagerFuncs windowManagerFuncs) { mContext = context; mWindowManagerFuncs = windowManagerFuncs; mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class); Loading @@ -1920,9 +1888,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHasFeatureLeanback = mPackageManager.hasSystemFeature(FEATURE_LEANBACK); mHasFeatureAuto = mPackageManager.hasSystemFeature(FEATURE_AUTOMOTIVE); mHasFeatureHdmiCec = mPackageManager.hasSystemFeature(FEATURE_HDMI_CEC); mAccessibilityShortcutController = injector.getAccessibilityShortcutController( mContext, new Handler(), mCurrentUserId); mGlobalActions = injector.getGlobalActions(); mAccessibilityShortcutController = new AccessibilityShortcutController(mContext, new Handler(), mCurrentUserId); mLogger = new MetricsLogger(); mScreenOffSleepTokenAcquirer = mActivityTaskManagerInternal Loading @@ -1937,7 +1904,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { res.getBoolean(com.android.internal.R.bool.config_wakeOnBackKeyPress); // Init display burn-in protection boolean burnInProtectionEnabled = mContext.getResources().getBoolean( boolean burnInProtectionEnabled = context.getResources().getBoolean( com.android.internal.R.bool.config_enableBurnInProtection); // Allow a system property to override this. Used by developer settings. boolean burnInProtectionDevMode = Loading @@ -1955,7 +1922,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { maxVertical = -4; maxRadius = (isRoundWindow()) ? 6 : -1; } else { Resources resources = mContext.getResources(); Resources resources = context.getResources(); minHorizontal = resources.getInteger( com.android.internal.R.integer.config_burnInProtectionMinHorizontalOffset); maxHorizontal = resources.getInteger( Loading @@ -1968,21 +1935,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.integer.config_burnInProtectionMaxRadius); } mBurnInProtectionHelper = new BurnInProtectionHelper( mContext, minHorizontal, maxHorizontal, minVertical, maxVertical, maxRadius); context, minHorizontal, maxHorizontal, minVertical, maxVertical, maxRadius); } mHandler = new PolicyHandler(); mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler); mSettingsObserver = new SettingsObserver(mHandler); mSettingsObserver.observe(); mModifierShortcutManager = new ModifierShortcutManager(mContext); mUiMode = mContext.getResources().getInteger( mModifierShortcutManager = new ModifierShortcutManager(context); mUiMode = context.getResources().getInteger( com.android.internal.R.integer.config_defaultUiModeType); mHomeIntent = new Intent(Intent.ACTION_MAIN, null); mHomeIntent.addCategory(Intent.CATEGORY_HOME); mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); mEnableCarDockHomeCapture = mContext.getResources().getBoolean( mEnableCarDockHomeCapture = context.getResources().getBoolean( com.android.internal.R.bool.config_enableCarDockHomeLaunch); mCarDockIntent = new Intent(Intent.ACTION_MAIN, null); mCarDockIntent.addCategory(Intent.CATEGORY_CAR_DOCK); Loading @@ -1997,7 +1964,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mVrHeadsetHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mBroadcastWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PhoneWindowManager.mBroadcastWakeLock"); mPowerKeyWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, Loading Loading @@ -2069,9 +2036,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { readConfigurationDependentBehaviors(); mDisplayFoldController = DisplayFoldController.create(mContext, DEFAULT_DISPLAY); mDisplayFoldController = DisplayFoldController.create(context, DEFAULT_DISPLAY); mAccessibilityManager = (AccessibilityManager) mContext.getSystemService( mAccessibilityManager = (AccessibilityManager) context.getSystemService( Context.ACCESSIBILITY_SERVICE); // register for dock events Loading @@ -2081,7 +2048,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { filter.addAction(UiModeManager.ACTION_ENTER_DESK_MODE); filter.addAction(UiModeManager.ACTION_EXIT_DESK_MODE); filter.addAction(Intent.ACTION_DOCK_EVENT); Intent intent = mContext.registerReceiver(mDockReceiver, filter); Intent intent = context.registerReceiver(mDockReceiver, filter); if (intent != null) { // Retrieve current sticky dock event broadcast. mDefaultDisplayPolicy.setDockMode(intent.getIntExtra(Intent.EXTRA_DOCK_STATE, Loading @@ -2092,13 +2059,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { filter = new IntentFilter(); filter.addAction(Intent.ACTION_DREAMING_STARTED); filter.addAction(Intent.ACTION_DREAMING_STOPPED); mContext.registerReceiver(mDreamReceiver, filter); context.registerReceiver(mDreamReceiver, filter); // register for multiuser-relevant broadcasts filter = new IntentFilter(Intent.ACTION_USER_SWITCHED); mContext.registerReceiver(mMultiuserReceiver, filter); context.registerReceiver(mMultiuserReceiver, filter); mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE); mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(), com.android.internal.R.array.config_safeModeEnabledVibePattern); Loading
services/tests/wmtests/src/com/android/server/policy/CombinationKeyTests.javadeleted 100644 → 0 +0 −78 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.policy; import static android.view.KeyEvent.KEYCODE_POWER; import static android.view.KeyEvent.KEYCODE_VOLUME_DOWN; import static android.view.KeyEvent.KEYCODE_VOLUME_UP; import static com.android.server.policy.PhoneWindowManager.POWER_VOLUME_UP_BEHAVIOR_GLOBAL_ACTIONS; import static com.android.server.policy.PhoneWindowManager.POWER_VOLUME_UP_BEHAVIOR_MUTE; import android.view.ViewConfiguration; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; /** * Test class for combination key shortcuts. * * Build/Install/Run: * atest WmTests:CombinationKeyTests */ @MediumTest @RunWith(AndroidJUnit4.class) public class CombinationKeyTests extends ShortcutKeyTestBase { private static final long A11Y_KEY_HOLD_MILLIS = 3500; /** * Power-VolDown to take screenshot. */ @Test public void testPowerVolumeDown() { sendKeyCombination(new int[]{KEYCODE_POWER, KEYCODE_VOLUME_DOWN}, ViewConfiguration.get(mContext).getScreenshotChordKeyTimeout()); mPhoneWindowManager.assertTakeScreenshotCalled(); } /** * Power-VolUp to show global actions or mute audio. (Phone default behavior) */ @Test public void testPowerVolumeUp() { // Show global actions. mPhoneWindowManager.overridePowerVolumeUp(POWER_VOLUME_UP_BEHAVIOR_GLOBAL_ACTIONS); sendKeyCombination(new int[]{KEYCODE_POWER, KEYCODE_VOLUME_UP}, 0); mPhoneWindowManager.assertShowGlobalActionsCalled(); // Mute audio (hold over 100ms). mPhoneWindowManager.overridePowerVolumeUp(POWER_VOLUME_UP_BEHAVIOR_MUTE); sendKeyCombination(new int[]{KEYCODE_POWER, KEYCODE_VOLUME_UP}, 100); mPhoneWindowManager.assertVolumeMute(); } /** * VolDown-VolUp and hold 3 secs to enable accessibility service. */ @Test public void testVolumeDownVolumeUp() { sendKeyCombination(new int[]{KEYCODE_VOLUME_DOWN, KEYCODE_VOLUME_UP}, A11Y_KEY_HOLD_MILLIS); mPhoneWindowManager.assertAccessibilityKeychordCalled(); } }
services/tests/wmtests/src/com/android/server/policy/KeyCombinationManagerTests.java→services/tests/wmtests/src/com/android/server/policy/KeyCombinationTests.java +3 −3 Original line number Diff line number Diff line Loading @@ -43,11 +43,11 @@ import java.util.concurrent.TimeUnit; * Test class for {@link KeyCombinationManager}. * * Build/Install/Run: * atest KeyCombinationManagerTests * atest KeyCombinationTests */ @SmallTest public class KeyCombinationManagerTests { public class KeyCombinationTests { private KeyCombinationManager mKeyCombinationManager; private final CountDownLatch mAction1Triggered = new CountDownLatch(1); Loading
services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.javadeleted 100644 → 0 +0 −84 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.policy; import static android.view.KeyEvent.KEYCODE_POWER; import static android.view.KeyEvent.KEYCODE_VOLUME_UP; import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_ASSISTANT; import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_GLOBAL_ACTIONS; import android.view.Display; import org.junit.Test; /** * Test class for power key gesture. * * Build/Install/Run: * atest WmTests:PowerKeyGestureTests */ public class PowerKeyGestureTests extends ShortcutKeyTestBase { /** * Power single press to turn screen on/off. */ @Test public void testPowerSinglePress() { sendKey(KEYCODE_POWER); mPhoneWindowManager.assertPowerSleep(); // turn screen on when begin from non-interactive. mPhoneWindowManager.overrideDisplayState(Display.STATE_OFF); sendKey(KEYCODE_POWER); mPhoneWindowManager.assertPowerWakeUp(); mPhoneWindowManager.assertNoPowerSleep(); } /** * Power double press to trigger camera. */ @Test public void testPowerDoublePress() { sendKey(KEYCODE_POWER); sendKey(KEYCODE_POWER); mPhoneWindowManager.assertCameraLaunch(); } /** * Power long press to show assistant or global actions. */ @Test public void testPowerLongPress() { // Show assistant. mPhoneWindowManager.overrideLongPressOnPower(LONG_PRESS_POWER_ASSISTANT); sendKey(KEYCODE_POWER, true); mPhoneWindowManager.assertAssistLaunch(); // Show global actions. mPhoneWindowManager.overrideLongPressOnPower(LONG_PRESS_POWER_GLOBAL_ACTIONS); sendKey(KEYCODE_POWER, true); mPhoneWindowManager.assertShowGlobalActionsCalled(); } /** * Ignore power press if combination key already triggered. */ @Test public void testIgnoreSinglePressWhenCombinationKeyTriggered() { sendKeyCombination(new int[]{KEYCODE_POWER, KEYCODE_VOLUME_UP}, 0); mPhoneWindowManager.assertNoPowerSleep(); } }
services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.javadeleted 100644 → 0 +0 −169 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.policy; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.KeyEvent.KEYCODE_ALT_LEFT; import static android.view.KeyEvent.KEYCODE_ALT_RIGHT; import static android.view.KeyEvent.KEYCODE_CTRL_LEFT; import static android.view.KeyEvent.KEYCODE_CTRL_RIGHT; import static android.view.KeyEvent.KEYCODE_META_LEFT; import static android.view.KeyEvent.KEYCODE_META_RIGHT; import static android.view.KeyEvent.KEYCODE_SHIFT_LEFT; import static android.view.KeyEvent.KEYCODE_SHIFT_RIGHT; import static android.view.KeyEvent.META_ALT_LEFT_ON; import static android.view.KeyEvent.META_ALT_ON; import static android.view.KeyEvent.META_ALT_RIGHT_ON; import static android.view.KeyEvent.META_CTRL_LEFT_ON; import static android.view.KeyEvent.META_CTRL_ON; import static android.view.KeyEvent.META_CTRL_RIGHT_ON; import static android.view.KeyEvent.META_META_LEFT_ON; import static android.view.KeyEvent.META_META_ON; import static android.view.KeyEvent.META_META_RIGHT_ON; import static android.view.KeyEvent.META_SHIFT_LEFT_ON; import static android.view.KeyEvent.META_SHIFT_ON; import static android.view.KeyEvent.META_SHIFT_RIGHT_ON; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static com.android.server.policy.WindowManagerPolicy.ACTION_PASS_TO_USER; import static java.util.Collections.unmodifiableMap; import android.content.Context; import android.os.Looper; import android.os.SystemClock; import android.util.ArrayMap; import android.view.InputDevice; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.ViewConfiguration; import org.junit.After; import org.junit.Before; import java.util.Map; class ShortcutKeyTestBase { TestPhoneWindowManager mPhoneWindowManager; final Context mContext = getInstrumentation().getTargetContext(); /** Modifier key to meta state */ private static final Map<Integer, Integer> MODIFIER; static { final Map<Integer, Integer> map = new ArrayMap<>(); map.put(KEYCODE_CTRL_LEFT, META_CTRL_LEFT_ON | META_CTRL_ON); map.put(KEYCODE_CTRL_RIGHT, META_CTRL_RIGHT_ON | META_CTRL_ON); map.put(KEYCODE_ALT_LEFT, META_ALT_LEFT_ON | META_ALT_ON); map.put(KEYCODE_ALT_RIGHT, META_ALT_RIGHT_ON | META_ALT_ON); map.put(KEYCODE_SHIFT_LEFT, META_SHIFT_LEFT_ON | META_SHIFT_ON); map.put(KEYCODE_SHIFT_RIGHT, META_SHIFT_RIGHT_ON | META_SHIFT_ON); map.put(KEYCODE_META_LEFT, META_META_LEFT_ON | META_META_ON); map.put(KEYCODE_META_RIGHT, META_META_RIGHT_ON | META_META_ON); MODIFIER = unmodifiableMap(map); } @Before public void setUp() { if (Looper.myLooper() == null) { Looper.prepare(); } mPhoneWindowManager = new TestPhoneWindowManager(mContext); } @After public void tearDown() { mPhoneWindowManager.tearDown(); } void sendKeyCombination(int[] keyCodes, long duration) { final long downTime = SystemClock.uptimeMillis(); final int count = keyCodes.length; final KeyEvent[] events = new KeyEvent[count]; int metaState = 0; for (int i = 0; i < count; i++) { final int keyCode = keyCodes[i]; final KeyEvent event = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0 /*repeat*/, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/, InputDevice.SOURCE_KEYBOARD); event.setDisplayId(DEFAULT_DISPLAY); events[i] = event; // The order is important here, metaState could be updated and applied to the next key. metaState |= MODIFIER.getOrDefault(keyCode, 0); } for (KeyEvent event: events) { interceptKey(event); } try { Thread.sleep(duration); } catch (InterruptedException e) { throw new RuntimeException(e); } for (KeyEvent event: events) { final long eventTime = SystemClock.uptimeMillis(); final int keyCode = event.getKeyCode(); final KeyEvent upEvent = new KeyEvent(downTime, eventTime, KeyEvent.ACTION_UP, keyCode, 0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/, InputDevice.SOURCE_KEYBOARD); interceptKey(upEvent); metaState &= ~MODIFIER.getOrDefault(keyCode, 0); } } void sendKey(int keyCode) { sendKey(keyCode, false); } void sendKey(int keyCode, boolean longPress) { final long downTime = SystemClock.uptimeMillis(); final KeyEvent event = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0 /*repeat*/, 0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/, InputDevice.SOURCE_KEYBOARD); event.setDisplayId(DEFAULT_DISPLAY); interceptKey(event); if (longPress) { final long nextDownTime = downTime + ViewConfiguration.getLongPressTimeout(); final KeyEvent nextDownevent = new KeyEvent(downTime, nextDownTime, KeyEvent.ACTION_DOWN, keyCode, 1 /*repeat*/, 0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, KeyEvent.FLAG_LONG_PRESS /*flags*/, InputDevice.SOURCE_KEYBOARD); interceptKey(nextDownevent); } final long eventTime = longPress ? SystemClock.uptimeMillis() + ViewConfiguration.getLongPressTimeout() : SystemClock.uptimeMillis(); final KeyEvent upEvent = new KeyEvent(downTime, eventTime, KeyEvent.ACTION_UP, keyCode, 0 /*repeat*/, 0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/, InputDevice.SOURCE_KEYBOARD); interceptKey(upEvent); } private void interceptKey(KeyEvent keyEvent) { int actions = mPhoneWindowManager.interceptKeyBeforeQueueing(keyEvent); if ((actions & ACTION_PASS_TO_USER) != 0) { if (0 == mPhoneWindowManager.interceptKeyBeforeDispatching(keyEvent)) { mPhoneWindowManager.dispatchUnhandledKey(keyEvent); } } } }