Loading services/core/java/com/android/server/policy/GlobalKeyIntent.java 0 → 100644 +84 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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 android.annotation.NonNull; import android.content.ComponentName; import android.content.Intent; import android.util.Log; import android.view.KeyEvent; /** * This class wrapped the Intent for global key ops. */ public final class GlobalKeyIntent { private static final String EXTRA_BEGAN_FROM_NON_INTERACTIVE = "EXTRA_BEGAN_FROM_NON_INTERACTIVE"; private final ComponentName mComponentName; private final KeyEvent mKeyEvent; private final boolean mBeganFromNonInteractive; GlobalKeyIntent(@NonNull ComponentName componentName, @NonNull KeyEvent event, boolean beganFromNonInteractive) { mComponentName = componentName; mKeyEvent = new KeyEvent(event); mBeganFromNonInteractive = beganFromNonInteractive; } Intent getIntent() { final Intent intent = new Intent(Intent.ACTION_GLOBAL_BUTTON) .setComponent(mComponentName) .setFlags(Intent.FLAG_RECEIVER_FOREGROUND) .putExtra(Intent.EXTRA_KEY_EVENT, mKeyEvent) .putExtra(EXTRA_BEGAN_FROM_NON_INTERACTIVE, mBeganFromNonInteractive); return intent; } /** * Get the {@link KeyEvent} information of {@link Intent#ACTION_GLOBAL_BUTTON}. */ public KeyEvent getKeyEvent() { return mKeyEvent; } /** * Indicate if the global key is dispatched from non-interactive mode. * Information of {@link Intent#ACTION_GLOBAL_BUTTON}. */ public boolean beganFromNonInteractive() { return mBeganFromNonInteractive; } /** * Generate a GlobalKeyIntent from {@link Intent}, the action must be * {@link Intent#ACTION_GLOBAL_BUTTON}. * * @param intent The received intent of the global key. */ public static GlobalKeyIntent from(@NonNull Intent intent) { if (intent.getAction() != Intent.ACTION_GLOBAL_BUTTON) { Log.wtf("GlobalKeyIntent", "Intent should be ACTION_GLOBAL_BUTTON"); return null; } final KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); final boolean fromNonInteractive = intent.getBooleanExtra(EXTRA_BEGAN_FROM_NON_INTERACTIVE, false); return new GlobalKeyIntent(intent.getComponent(), event, fromNonInteractive); } } services/core/java/com/android/server/policy/GlobalKeyManager.java +48 −12 Original line number Diff line number Diff line Loading @@ -39,6 +39,9 @@ import java.io.PrintWriter; * broadcast to the specified component. The action of the intent will be * {@link Intent#ACTION_GLOBAL_BUTTON} and the KeyEvent will be included in the intent with * {@link Intent#EXTRA_KEY_EVENT}. * * Use {@link GlobalKeyIntent} to get detail information from received {@link Intent}, includes * {@link KeyEvent} and the information about if the key is dispatched from non-interactive mode. */ final class GlobalKeyManager { Loading @@ -49,13 +52,15 @@ final class GlobalKeyManager { private static final String TAG_KEY = "key"; private static final String ATTR_KEY_CODE = "keyCode"; private static final String ATTR_COMPONENT = "component"; private static final String ATTR_DISPATCH_WHEN_NON_INTERACTIVE = "dispatchWhenNonInteractive"; private static final int GLOBAL_KEY_FILE_VERSION = 1; private SparseArray<ComponentName> mKeyMapping; private SparseArray<GlobalKeyAction> mKeyMapping; private boolean mBeganFromNonInteractive = false; public GlobalKeyManager(Context context) { mKeyMapping = new SparseArray<ComponentName>(); mKeyMapping = new SparseArray<>(); loadGlobalKeys(context); } Loading @@ -69,13 +74,15 @@ final class GlobalKeyManager { */ boolean handleGlobalKey(Context context, int keyCode, KeyEvent event) { if (mKeyMapping.size() > 0) { ComponentName component = mKeyMapping.get(keyCode); if (component != null) { Intent intent = new Intent(Intent.ACTION_GLOBAL_BUTTON) .setComponent(component) .setFlags(Intent.FLAG_RECEIVER_FOREGROUND) .putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(event)); GlobalKeyAction action = mKeyMapping.get(keyCode); if (action != null) { final Intent intent = new GlobalKeyIntent(action.mComponentName, event, mBeganFromNonInteractive).getIntent(); context.sendBroadcastAsUser(intent, UserHandle.CURRENT, null); if (event.getAction() == KeyEvent.ACTION_UP) { mBeganFromNonInteractive = false; } return true; } } Loading @@ -85,10 +92,35 @@ final class GlobalKeyManager { /** * Returns {@code true} if the key will be handled globally. */ boolean shouldHandleGlobalKey(int keyCode, KeyEvent event) { boolean shouldHandleGlobalKey(int keyCode) { return mKeyMapping.get(keyCode) != null; } /** * Returns {@code true} if the key will be handled globally. */ boolean shouldDispatchFromNonInteractive(int keyCode) { final GlobalKeyAction action = mKeyMapping.get(keyCode); if (action == null) { return false; } return action.mDispatchWhenNonInteractive; } void setBeganFromNonInteractive() { mBeganFromNonInteractive = true; } class GlobalKeyAction { private ComponentName mComponentName; private boolean mDispatchWhenNonInteractive; GlobalKeyAction(String componentName, String dispatchWhenNonInteractive) { mComponentName = ComponentName.unflattenFromString(componentName); mDispatchWhenNonInteractive = Boolean.valueOf(dispatchWhenNonInteractive); } } private void loadGlobalKeys(Context context) { XmlResourceParser parser = null; try { Loading @@ -105,10 +137,12 @@ final class GlobalKeyManager { if (TAG_KEY.equals(element)) { String keyCodeName = parser.getAttributeValue(null, ATTR_KEY_CODE); String componentName = parser.getAttributeValue(null, ATTR_COMPONENT); String dispatchWhenNonInteractive = parser.getAttributeValue(null, ATTR_DISPATCH_WHEN_NON_INTERACTIVE); int keyCode = KeyEvent.keyCodeFromString(keyCodeName); if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { mKeyMapping.put(keyCode, ComponentName.unflattenFromString( componentName)); mKeyMapping.put(keyCode, new GlobalKeyAction( componentName, dispatchWhenNonInteractive)); } } } Loading Loading @@ -138,7 +172,9 @@ final class GlobalKeyManager { pw.print(prefix); pw.print(KeyEvent.keyCodeToString(mKeyMapping.keyAt(i))); pw.print("="); pw.println(mKeyMapping.valueAt(i).flattenToString()); pw.print(mKeyMapping.valueAt(i).mComponentName.flattenToString()); pw.print(",dispatchWhenNonInteractive="); pw.println(mKeyMapping.valueAt(i).mDispatchWhenNonInteractive); } pw.print(prefix); pw.println("}"); } Loading services/core/java/com/android/server/policy/PhoneWindowManager.java +11 −1 Original line number Diff line number Diff line Loading @@ -3434,7 +3434,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { // If the key would be handled globally, just return the result, don't worry about special // key processing. if (isValidGlobalKey(keyCode) && mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) { && mGlobalKeyManager.shouldHandleGlobalKey(keyCode)) { // Dispatch if global key defined dispatchWhenNonInteractive. if (!interactive && isWakeKey && down && mGlobalKeyManager.shouldDispatchFromNonInteractive(keyCode)) { mGlobalKeyManager.setBeganFromNonInteractive(); result = ACTION_PASS_TO_USER; // Since we're dispatching the input, reset the pending key mPendingWakeKey = PENDING_KEY_NULL; } if (isWakeKey) { wakeUpFromWakeKey(event); } Loading Loading @@ -3988,6 +3997,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { Slog.e(TAG, "RemoteException when checking if dreaming", e); } } // Otherwise, consume events since the user can't see what is being // interacted with. return false; Loading Loading
services/core/java/com/android/server/policy/GlobalKeyIntent.java 0 → 100644 +84 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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 android.annotation.NonNull; import android.content.ComponentName; import android.content.Intent; import android.util.Log; import android.view.KeyEvent; /** * This class wrapped the Intent for global key ops. */ public final class GlobalKeyIntent { private static final String EXTRA_BEGAN_FROM_NON_INTERACTIVE = "EXTRA_BEGAN_FROM_NON_INTERACTIVE"; private final ComponentName mComponentName; private final KeyEvent mKeyEvent; private final boolean mBeganFromNonInteractive; GlobalKeyIntent(@NonNull ComponentName componentName, @NonNull KeyEvent event, boolean beganFromNonInteractive) { mComponentName = componentName; mKeyEvent = new KeyEvent(event); mBeganFromNonInteractive = beganFromNonInteractive; } Intent getIntent() { final Intent intent = new Intent(Intent.ACTION_GLOBAL_BUTTON) .setComponent(mComponentName) .setFlags(Intent.FLAG_RECEIVER_FOREGROUND) .putExtra(Intent.EXTRA_KEY_EVENT, mKeyEvent) .putExtra(EXTRA_BEGAN_FROM_NON_INTERACTIVE, mBeganFromNonInteractive); return intent; } /** * Get the {@link KeyEvent} information of {@link Intent#ACTION_GLOBAL_BUTTON}. */ public KeyEvent getKeyEvent() { return mKeyEvent; } /** * Indicate if the global key is dispatched from non-interactive mode. * Information of {@link Intent#ACTION_GLOBAL_BUTTON}. */ public boolean beganFromNonInteractive() { return mBeganFromNonInteractive; } /** * Generate a GlobalKeyIntent from {@link Intent}, the action must be * {@link Intent#ACTION_GLOBAL_BUTTON}. * * @param intent The received intent of the global key. */ public static GlobalKeyIntent from(@NonNull Intent intent) { if (intent.getAction() != Intent.ACTION_GLOBAL_BUTTON) { Log.wtf("GlobalKeyIntent", "Intent should be ACTION_GLOBAL_BUTTON"); return null; } final KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); final boolean fromNonInteractive = intent.getBooleanExtra(EXTRA_BEGAN_FROM_NON_INTERACTIVE, false); return new GlobalKeyIntent(intent.getComponent(), event, fromNonInteractive); } }
services/core/java/com/android/server/policy/GlobalKeyManager.java +48 −12 Original line number Diff line number Diff line Loading @@ -39,6 +39,9 @@ import java.io.PrintWriter; * broadcast to the specified component. The action of the intent will be * {@link Intent#ACTION_GLOBAL_BUTTON} and the KeyEvent will be included in the intent with * {@link Intent#EXTRA_KEY_EVENT}. * * Use {@link GlobalKeyIntent} to get detail information from received {@link Intent}, includes * {@link KeyEvent} and the information about if the key is dispatched from non-interactive mode. */ final class GlobalKeyManager { Loading @@ -49,13 +52,15 @@ final class GlobalKeyManager { private static final String TAG_KEY = "key"; private static final String ATTR_KEY_CODE = "keyCode"; private static final String ATTR_COMPONENT = "component"; private static final String ATTR_DISPATCH_WHEN_NON_INTERACTIVE = "dispatchWhenNonInteractive"; private static final int GLOBAL_KEY_FILE_VERSION = 1; private SparseArray<ComponentName> mKeyMapping; private SparseArray<GlobalKeyAction> mKeyMapping; private boolean mBeganFromNonInteractive = false; public GlobalKeyManager(Context context) { mKeyMapping = new SparseArray<ComponentName>(); mKeyMapping = new SparseArray<>(); loadGlobalKeys(context); } Loading @@ -69,13 +74,15 @@ final class GlobalKeyManager { */ boolean handleGlobalKey(Context context, int keyCode, KeyEvent event) { if (mKeyMapping.size() > 0) { ComponentName component = mKeyMapping.get(keyCode); if (component != null) { Intent intent = new Intent(Intent.ACTION_GLOBAL_BUTTON) .setComponent(component) .setFlags(Intent.FLAG_RECEIVER_FOREGROUND) .putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(event)); GlobalKeyAction action = mKeyMapping.get(keyCode); if (action != null) { final Intent intent = new GlobalKeyIntent(action.mComponentName, event, mBeganFromNonInteractive).getIntent(); context.sendBroadcastAsUser(intent, UserHandle.CURRENT, null); if (event.getAction() == KeyEvent.ACTION_UP) { mBeganFromNonInteractive = false; } return true; } } Loading @@ -85,10 +92,35 @@ final class GlobalKeyManager { /** * Returns {@code true} if the key will be handled globally. */ boolean shouldHandleGlobalKey(int keyCode, KeyEvent event) { boolean shouldHandleGlobalKey(int keyCode) { return mKeyMapping.get(keyCode) != null; } /** * Returns {@code true} if the key will be handled globally. */ boolean shouldDispatchFromNonInteractive(int keyCode) { final GlobalKeyAction action = mKeyMapping.get(keyCode); if (action == null) { return false; } return action.mDispatchWhenNonInteractive; } void setBeganFromNonInteractive() { mBeganFromNonInteractive = true; } class GlobalKeyAction { private ComponentName mComponentName; private boolean mDispatchWhenNonInteractive; GlobalKeyAction(String componentName, String dispatchWhenNonInteractive) { mComponentName = ComponentName.unflattenFromString(componentName); mDispatchWhenNonInteractive = Boolean.valueOf(dispatchWhenNonInteractive); } } private void loadGlobalKeys(Context context) { XmlResourceParser parser = null; try { Loading @@ -105,10 +137,12 @@ final class GlobalKeyManager { if (TAG_KEY.equals(element)) { String keyCodeName = parser.getAttributeValue(null, ATTR_KEY_CODE); String componentName = parser.getAttributeValue(null, ATTR_COMPONENT); String dispatchWhenNonInteractive = parser.getAttributeValue(null, ATTR_DISPATCH_WHEN_NON_INTERACTIVE); int keyCode = KeyEvent.keyCodeFromString(keyCodeName); if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { mKeyMapping.put(keyCode, ComponentName.unflattenFromString( componentName)); mKeyMapping.put(keyCode, new GlobalKeyAction( componentName, dispatchWhenNonInteractive)); } } } Loading Loading @@ -138,7 +172,9 @@ final class GlobalKeyManager { pw.print(prefix); pw.print(KeyEvent.keyCodeToString(mKeyMapping.keyAt(i))); pw.print("="); pw.println(mKeyMapping.valueAt(i).flattenToString()); pw.print(mKeyMapping.valueAt(i).mComponentName.flattenToString()); pw.print(",dispatchWhenNonInteractive="); pw.println(mKeyMapping.valueAt(i).mDispatchWhenNonInteractive); } pw.print(prefix); pw.println("}"); } Loading
services/core/java/com/android/server/policy/PhoneWindowManager.java +11 −1 Original line number Diff line number Diff line Loading @@ -3434,7 +3434,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { // If the key would be handled globally, just return the result, don't worry about special // key processing. if (isValidGlobalKey(keyCode) && mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) { && mGlobalKeyManager.shouldHandleGlobalKey(keyCode)) { // Dispatch if global key defined dispatchWhenNonInteractive. if (!interactive && isWakeKey && down && mGlobalKeyManager.shouldDispatchFromNonInteractive(keyCode)) { mGlobalKeyManager.setBeganFromNonInteractive(); result = ACTION_PASS_TO_USER; // Since we're dispatching the input, reset the pending key mPendingWakeKey = PENDING_KEY_NULL; } if (isWakeKey) { wakeUpFromWakeKey(event); } Loading Loading @@ -3988,6 +3997,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { Slog.e(TAG, "RemoteException when checking if dreaming", e); } } // Otherwise, consume events since the user can't see what is being // interacted with. return false; Loading