diff options
| author | 2024-08-19 18:41:14 +0000 | |
|---|---|---|
| committer | 2024-08-19 18:41:14 +0000 | |
| commit | 94e64d081d5b4e636b0c7d4c996d06d8996b6f5f (patch) | |
| tree | ef1624c9c41fa34170c85b38acda4ed6eca65c33 | |
| parent | 80462ae2d37e27fd17b58589dd3f8fa901cb0a48 (diff) | |
| parent | 20c78a6c479a954de660cc8aae33742151dfb7f4 (diff) | |
Merge "Passing meta/action key related key events when private flag is set" into main
4 files changed, 125 insertions, 0 deletions
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 017e004a7f13..67a207e34a1a 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -3462,6 +3462,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. * @hide diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index aa56e8d8eb55..ba3de33d865c 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -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); @@ -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 diff --git a/services/tests/wmtests/src/com/android/server/policy/MetaKeyEventsInterceptionTests.java b/services/tests/wmtests/src/com/android/server/policy/MetaKeyEventsInterceptionTests.java new file mode 100644 index 000000000000..b979335233e3 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/policy/MetaKeyEventsInterceptionTests.java @@ -0,0 +1,96 @@ +/* + * 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); + } +} 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 43b065dbb6a5..79c7ac193b40 100644 --- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java +++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java @@ -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; @@ -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; } |