Loading core/java/android/view/WindowManager.java +9 −0 Original line number Diff line number Diff line Loading @@ -3461,6 +3461,15 @@ public interface WindowManager extends ViewManager { */ public static final int PRIVATE_FLAG_NOT_MAGNIFIABLE = 1 << 22; /** * Indicates that the window should receive key events including Action/Meta key. * They will not be intercepted as usual and instead will be passed to the window with other * key events. * TODO(b/358569822) Remove this once we have nicer API for listening to shortcuts * @hide */ public static final int PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS = 1 << 23; /** * Flag to indicate that the window is color space agnostic, and the color can be * interpreted to any color space. Loading services/core/java/com/android/server/policy/PhoneWindowManager.java +15 −0 Original line number Diff line number Diff line Loading @@ -3352,6 +3352,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { mConsumedKeysForDevice.put(deviceId, consumedKeys); } // TODO(b/358569822) Remove below once we have nicer API for listening to shortcuts if ((event.isMetaPressed() || KeyEvent.isMetaKey(keyCode)) && shouldInterceptShortcuts(focusedToken)) { return keyNotConsumed; } if (interceptSystemKeysAndShortcuts(focusedToken, event) && event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { consumedKeys.add(keyCode); Loading Loading @@ -3842,6 +3848,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { return (metaState & KeyEvent.META_META_ON) != 0; } private boolean shouldInterceptShortcuts(IBinder focusedToken) { KeyInterceptionInfo info = mWindowManagerInternal.getKeyInterceptionInfoFromToken(focusedToken); boolean hasInterceptWindowFlag = (info.layoutParamsPrivateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS) != 0; return hasInterceptWindowFlag && mButtonOverridePermissionChecker.canAppOverrideSystemKey( mContext, info.windowOwnerUid); } /** * 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 Loading services/tests/wmtests/src/com/android/server/policy/MetaKeyEventsInterceptionTests.java 0 → 100644 +96 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.WindowManager.LayoutParams.PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS; import static com.google.common.truth.Truth.assertThat; import android.view.KeyEvent; import android.view.WindowManager; import androidx.test.filters.SmallTest; import com.android.internal.policy.KeyInterceptionInfo; import org.junit.Before; import org.junit.Test; import java.util.Arrays; import java.util.List; /** * Testing {@link PhoneWindowManager} functionality of letting app intercepting key events * containing META. */ @SmallTest public class MetaKeyEventsInterceptionTests extends ShortcutKeyTestBase { private static final List<KeyEvent> META_KEY_EVENTS = Arrays.asList( new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_META_LEFT), new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_META_RIGHT), new KeyEvent(/* downTime= */ 0, /* eventTime= */ 0, /* action= */ 0, /* code= */ 0, /* repeat= */ 0, /* metaState= */ KeyEvent.META_META_ON)); @Before public void setUp() { setUpPhoneWindowManager(); } @Test public void doesntInterceptMetaKeyEvents_whenWindowAskedForIt() { mPhoneWindowManager.overrideFocusedWindowButtonOverridePermission(/* granted= */ true); setWindowKeyInterceptionWithPrivateFlags(PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS); META_KEY_EVENTS.forEach(keyEvent -> { assertKeyInterceptionResult(keyEvent, /* intercepted= */ false); }); } @Test public void interceptsMetaKeyEvents_whenWindowDoesntHaveFlagSet() { mPhoneWindowManager.overrideFocusedWindowButtonOverridePermission(/* granted= */ true); setWindowKeyInterceptionWithPrivateFlags(0); META_KEY_EVENTS.forEach(keyEvent -> { assertKeyInterceptionResult(keyEvent, /* intercepted= */ true); }); } @Test public void interceptsMetaKeyEvents_whenWindowDoesntHavePermission() { mPhoneWindowManager.overrideFocusedWindowButtonOverridePermission(/* granted= */ false); setWindowKeyInterceptionWithPrivateFlags(PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS); META_KEY_EVENTS.forEach(keyEvent -> { assertKeyInterceptionResult(keyEvent, /* intercepted= */ true); }); } private void setWindowKeyInterceptionWithPrivateFlags(int privateFlags) { KeyInterceptionInfo info = new KeyInterceptionInfo( WindowManager.LayoutParams.TYPE_APPLICATION, privateFlags, "title", 0); mPhoneWindowManager.overrideWindowKeyInterceptionInfo(info); } private void assertKeyInterceptionResult(KeyEvent keyEvent, boolean intercepted) { long result = mPhoneWindowManager.interceptKeyBeforeDispatching(keyEvent); int expected = intercepted ? -1 : 0; assertThat(result).isEqualTo(expected); } } services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java +5 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ import static org.mockito.Mockito.after; import static org.mockito.Mockito.description; import static org.mockito.Mockito.mockingDetails; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.when; import static org.mockito.Mockito.withSettings; import android.app.ActivityManagerInternal; Loading Loading @@ -613,6 +614,10 @@ class TestPhoneWindowManager { .when(mButtonOverridePermissionChecker).canAppOverrideSystemKey(any(), anyInt()); } void overrideWindowKeyInterceptionInfo(KeyInterceptionInfo info) { when(mWindowManagerInternal.getKeyInterceptionInfoFromToken(any())).thenReturn(info); } void overrideKeyEventPolicyFlags(int flags) { mKeyEventPolicyFlags = flags; } Loading Loading
core/java/android/view/WindowManager.java +9 −0 Original line number Diff line number Diff line Loading @@ -3461,6 +3461,15 @@ public interface WindowManager extends ViewManager { */ public static final int PRIVATE_FLAG_NOT_MAGNIFIABLE = 1 << 22; /** * Indicates that the window should receive key events including Action/Meta key. * They will not be intercepted as usual and instead will be passed to the window with other * key events. * TODO(b/358569822) Remove this once we have nicer API for listening to shortcuts * @hide */ public static final int PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS = 1 << 23; /** * Flag to indicate that the window is color space agnostic, and the color can be * interpreted to any color space. Loading
services/core/java/com/android/server/policy/PhoneWindowManager.java +15 −0 Original line number Diff line number Diff line Loading @@ -3352,6 +3352,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { mConsumedKeysForDevice.put(deviceId, consumedKeys); } // TODO(b/358569822) Remove below once we have nicer API for listening to shortcuts if ((event.isMetaPressed() || KeyEvent.isMetaKey(keyCode)) && shouldInterceptShortcuts(focusedToken)) { return keyNotConsumed; } if (interceptSystemKeysAndShortcuts(focusedToken, event) && event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { consumedKeys.add(keyCode); Loading Loading @@ -3842,6 +3848,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { return (metaState & KeyEvent.META_META_ON) != 0; } private boolean shouldInterceptShortcuts(IBinder focusedToken) { KeyInterceptionInfo info = mWindowManagerInternal.getKeyInterceptionInfoFromToken(focusedToken); boolean hasInterceptWindowFlag = (info.layoutParamsPrivateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS) != 0; return hasInterceptWindowFlag && mButtonOverridePermissionChecker.canAppOverrideSystemKey( mContext, info.windowOwnerUid); } /** * 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 Loading
services/tests/wmtests/src/com/android/server/policy/MetaKeyEventsInterceptionTests.java 0 → 100644 +96 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.WindowManager.LayoutParams.PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS; import static com.google.common.truth.Truth.assertThat; import android.view.KeyEvent; import android.view.WindowManager; import androidx.test.filters.SmallTest; import com.android.internal.policy.KeyInterceptionInfo; import org.junit.Before; import org.junit.Test; import java.util.Arrays; import java.util.List; /** * Testing {@link PhoneWindowManager} functionality of letting app intercepting key events * containing META. */ @SmallTest public class MetaKeyEventsInterceptionTests extends ShortcutKeyTestBase { private static final List<KeyEvent> META_KEY_EVENTS = Arrays.asList( new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_META_LEFT), new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_META_RIGHT), new KeyEvent(/* downTime= */ 0, /* eventTime= */ 0, /* action= */ 0, /* code= */ 0, /* repeat= */ 0, /* metaState= */ KeyEvent.META_META_ON)); @Before public void setUp() { setUpPhoneWindowManager(); } @Test public void doesntInterceptMetaKeyEvents_whenWindowAskedForIt() { mPhoneWindowManager.overrideFocusedWindowButtonOverridePermission(/* granted= */ true); setWindowKeyInterceptionWithPrivateFlags(PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS); META_KEY_EVENTS.forEach(keyEvent -> { assertKeyInterceptionResult(keyEvent, /* intercepted= */ false); }); } @Test public void interceptsMetaKeyEvents_whenWindowDoesntHaveFlagSet() { mPhoneWindowManager.overrideFocusedWindowButtonOverridePermission(/* granted= */ true); setWindowKeyInterceptionWithPrivateFlags(0); META_KEY_EVENTS.forEach(keyEvent -> { assertKeyInterceptionResult(keyEvent, /* intercepted= */ true); }); } @Test public void interceptsMetaKeyEvents_whenWindowDoesntHavePermission() { mPhoneWindowManager.overrideFocusedWindowButtonOverridePermission(/* granted= */ false); setWindowKeyInterceptionWithPrivateFlags(PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS); META_KEY_EVENTS.forEach(keyEvent -> { assertKeyInterceptionResult(keyEvent, /* intercepted= */ true); }); } private void setWindowKeyInterceptionWithPrivateFlags(int privateFlags) { KeyInterceptionInfo info = new KeyInterceptionInfo( WindowManager.LayoutParams.TYPE_APPLICATION, privateFlags, "title", 0); mPhoneWindowManager.overrideWindowKeyInterceptionInfo(info); } private void assertKeyInterceptionResult(KeyEvent keyEvent, boolean intercepted) { long result = mPhoneWindowManager.interceptKeyBeforeDispatching(keyEvent); int expected = intercepted ? -1 : 0; assertThat(result).isEqualTo(expected); } }
services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java +5 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ import static org.mockito.Mockito.after; import static org.mockito.Mockito.description; import static org.mockito.Mockito.mockingDetails; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.when; import static org.mockito.Mockito.withSettings; import android.app.ActivityManagerInternal; Loading Loading @@ -613,6 +614,10 @@ class TestPhoneWindowManager { .when(mButtonOverridePermissionChecker).canAppOverrideSystemKey(any(), anyInt()); } void overrideWindowKeyInterceptionInfo(KeyInterceptionInfo info) { when(mWindowManagerInternal.getKeyInterceptionInfoFromToken(any())).thenReturn(info); } void overrideKeyEventPolicyFlags(int flags) { mKeyEventPolicyFlags = flags; } Loading