Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d4d9db3 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Support global key can be dispatched from non-interactive" into sc-dev am: 55bd70ff

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14264386

Change-Id: Ic98077708d5d048ee5c1558dace5bb7bdb989d0c
parents 0655026e 55bd70ff
Loading
Loading
Loading
Loading
+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);
    }
}
+48 −12
Original line number Diff line number Diff line
@@ -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 {

@@ -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);
    }

@@ -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;
            }
        }
@@ -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 {
@@ -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));
                        }
                    }
                }
@@ -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("}");
    }
+11 −1
Original line number Diff line number Diff line
@@ -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);
            }
@@ -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;