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

Commit bc24b511 authored by Vaibhav Devmurari's avatar Vaibhav Devmurari
Browse files

Add long press escape to close current app if keyboard capture on

Bug: 416681006
Test: atest KeyGestureControllerTests
Test: atest KeyGestureEventTests
Flag: com.android.hardware.input.request_key_capture_api
Change-Id: I0e61fecaa1b042e9207c996009861d0ed3d42d7d
parent 0ecadf81
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -132,6 +132,7 @@ public final class KeyGestureEvent {
    public static final int KEY_GESTURE_TYPE_SWITCH_TO_PREVIOUS_DESK = 77;
    public static final int KEY_GESTURE_TYPE_SWITCH_TO_NEXT_DESK = 78;
    public static final int KEY_GESTURE_TYPE_TOGGLE_QUICK_SETTINGS_PANEL = 79;
    public static final int KEY_GESTURE_TYPE_QUIT_FOCUSED_TASK = 80;

    public static final int FLAG_CANCELLED = 1 << 0;
    public static final int FLAG_LONG_PRESS = 1 << 1;
@@ -226,6 +227,7 @@ public final class KeyGestureEvent {
            KEY_GESTURE_TYPE_SWITCH_TO_PREVIOUS_DESK,
            KEY_GESTURE_TYPE_SWITCH_TO_NEXT_DESK,
            KEY_GESTURE_TYPE_TOGGLE_QUICK_SETTINGS_PANEL,
            KEY_GESTURE_TYPE_QUIT_FOCUSED_TASK,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface KeyGestureType {
@@ -824,6 +826,8 @@ public final class KeyGestureEvent {
                return "KEY_GESTURE_TYPE_SWITCH_TO_NEXT_DESK";
            case KEY_GESTURE_TYPE_TOGGLE_QUICK_SETTINGS_PANEL:
                return "KEY_GESTURE_TYPE_TOGGLE_QUICK_SETTINGS_PANEL";
            case KEY_GESTURE_TYPE_QUIT_FOCUSED_TASK:
                return "KEY_GESTURE_TYPE_QUIT_FOCUSED_TASK";
            default:
                return Integer.toHexString(value);
        }
+3 −0
Original line number Diff line number Diff line
@@ -2507,6 +2507,9 @@
    <!-- Description of policy access to disable keyguard features. [CHAR LIMIT=110]-->
    <string name="policydesc_disableKeyguardFeatures">Prevent use of some screen lock features.</string>
    <!-- Text for toast instructing user to long press escape to exit the current application. [CHAR LIMIT=TOAST]-->
    <string name="exit_toast_on_long_press_escape">Long press escape key to quit the application.</string>
    <!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
    <!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->
    <string-array name="phoneTypes">
+2 −0
Original line number Diff line number Diff line
@@ -6274,6 +6274,8 @@
  <java-symbol type="string" name="proximity_provider_service_package_name" />
  <java-symbol type="string" name="proximity_provider_service_class_name" />

  <java-symbol type="string" name="exit_toast_on_long_press_escape" />

  <!-- For App Functions -->
  <java-symbol type="array" name="config_appFunctionDeviceSettingsPackages" />
</resources>
+31 −1
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.widget.Toast;

import com.android.internal.R;
import com.android.internal.accessibility.AccessibilityShortcutController;
@@ -86,6 +87,7 @@ import com.android.internal.policy.KeyInterceptionInfo;
import com.android.internal.util.ScreenshotHelper;
import com.android.internal.util.ScreenshotRequest;
import com.android.server.LocalServices;
import com.android.server.UiThread;
import com.android.server.pm.UserManagerInternal;
import com.android.server.wm.WindowManagerInternal;

@@ -127,6 +129,7 @@ final class KeyGestureController {
    private static final int MSG_LOAD_CUSTOM_GESTURES = 3;
    private static final int MSG_ACCESSIBILITY_SHORTCUT = 4;
    private static final int MSG_SCREENSHOT_SHORTCUT = 5;
    private static final int MSG_EXIT_FOCUSED_APP = 6;

    // must match: config_settingsKeyBehavior in config.xml
    private static final int SETTINGS_KEY_BEHAVIOR_SETTINGS_ACTIVITY = 0;
@@ -148,6 +151,9 @@ final class KeyGestureController {
    // Increase the chord delay when taking a screenshot from the keyguard
    private static final float KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER = 2.5f;

    // Duration to long press escape to exit application when app is capturing keyboard keys
    private static final long LONG_PRESS_DURATION_FOR_EXIT_APP_MS = 1000;

    @LongDef(prefix = {"KEY_INTERCEPT_RESULT_"}, value = {
            KEY_INTERCEPT_RESULT_NOT_CONSUMED_GO_FALLBACK,
            KEY_INTERCEPT_RESULT_CONSUMED,
@@ -804,6 +810,28 @@ final class KeyGestureController {
                    }
                }
                return true;
            case KeyEvent.KEYCODE_ESCAPE:
                // TODO(b/358569822): Currently implemented long press using handler and delayed
                //  message here, instead of using SingleKeyGestureDetector because that detection
                //  logic doesn't have access to focused token. Refactor this so that we don't
                //  have this custom logic to detect long press.
                if (firstDown && canFocusedWindowCaptureKeys(focusedToken)) {
                    // Toast to quit application is shown on key down for ESCAPE key, when the
                    // focused window is capturing keys.
                    Toast.makeText(mContext, UiThread.get().getLooper(),
                            mContext.getString(R.string.exit_toast_on_long_press_escape),
                            Toast.LENGTH_SHORT).show();
                    AidlKeyGestureEvent eventToSend = createKeyGestureEvent(event.getDeviceId(),
                            new int[]{KeyEvent.KEYCODE_ESCAPE},
                            metaState, KeyGestureEvent.KEY_GESTURE_TYPE_QUIT_FOCUSED_TASK,
                            KeyGestureEvent.ACTION_GESTURE_COMPLETE,
                            displayId, /* flags= */0, /* appLaunchData= */ null);
                    Message msg = Message.obtain(mHandler, MSG_EXIT_FOCUSED_APP, eventToSend);
                    mHandler.sendMessageDelayed(msg, LONG_PRESS_DURATION_FOR_EXIT_APP_MS);
                } else if (!down) {
                    mHandler.removeMessages(MSG_EXIT_FOCUSED_APP);
                }
                break;
            case KeyEvent.KEYCODE_ASSIST:
                Slog.wtf(TAG, "KEYCODE_ASSIST should be handled in interceptKeyBeforeQueueing");
                return true;
@@ -1272,7 +1300,9 @@ final class KeyGestureController {
            case MSG_SCREENSHOT_SHORTCUT:
                takeScreenshot(msg.arg1, msg.arg2);
                break;

            case MSG_EXIT_FOCUSED_APP:
                handleKeyGesture((AidlKeyGestureEvent) msg.obj, /* focusedToken= */null);
                break;
        }
        return true;
    }
+21 −1
Original line number Diff line number Diff line
@@ -3467,7 +3467,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_DO_NOT_DISTURB,
                KeyGestureEvent.KEY_GESTURE_TYPE_RINGER_TOGGLE_CHORD,
                KeyGestureEvent.KEY_GESTURE_TYPE_GLOBAL_ACTIONS,
                KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT
                KeyGestureEvent.KEY_GESTURE_TYPE_TV_TRIGGER_BUG_REPORT,
                KeyGestureEvent.KEY_GESTURE_TYPE_QUIT_FOCUSED_TASK
        ));
        if (!com.android.window.flags.Flags.grantManageKeyGesturesToRecents()) {
            // When grantManageKeyGesturesToRecents is enabled, the event is handled in the
@@ -3671,6 +3672,25 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                            "Key gesture DND", true);
                }
                break;
            case KeyGestureEvent.KEY_GESTURE_TYPE_QUIT_FOCUSED_TASK:
                if (complete) {
                    try {
                        RootTaskInfo currentRootTask =
                                mActivityManagerService.getFocusedRootTaskInfo();
                        if (currentRootTask == null) {
                            Slog.e(TAG,
                                    "onKeyGesture: KEY_GESTURE_TYPE_QUIT_FOCUSED_TASK the current"
                                            + " root task is null" );
                            return;
                        }
                        mActivityManagerService.removeTask(currentRootTask.taskId);
                    } catch (RemoteException e) {
                        Slog.e(TAG,
                                "onKeyGesture: KEY_GESTURE_TYPE_QUIT_FOCUSED_TASK failed to close"
                                        + " the current root task",
                                e);
                    }
                }
            default:
                Log.w(TAG, "Received a key gesture " + event
                        + " that was not registered by this handler");
Loading