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

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

Pass Long press assistant start, complete, cancel events

Pass Long press start, complete and cancel events to SysUI using
KeyGestureEvent infra.

Flag: com.android.systemui.shared.enable_lpp_assist_invocation_effect
Bug: 358569822
Test: manual
Change-Id: Ia727e52150191fae28fc89ce26dca770cf7b96cc
parent a06e9b3f
Loading
Loading
Loading
Loading
+26 −3
Original line number Diff line number Diff line
@@ -132,7 +132,8 @@ 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 FLAG_CANCELLED = 1;
    public static final int FLAG_CANCELLED = 1 << 0;
    public static final int FLAG_LONG_PRESS = 1 << 1;

    // NOTE: Valid KeyGestureEvent streams:
    //       - GESTURE_START -> GESTURE_CANCEL
@@ -404,6 +405,10 @@ public final class KeyGestureEvent {
        return (mKeyGestureEvent.flags & FLAG_CANCELLED) != 0;
    }

    public boolean isLongPress() {
        return (mKeyGestureEvent.flags & FLAG_LONG_PRESS) != 0;
    }

    public int getLogEvent() {
        if (getKeyGestureType() == KEY_GESTURE_TYPE_LAUNCH_APPLICATION) {
            return getLogEventFromLaunchAppData(getAppLaunchData());
@@ -432,9 +437,9 @@ public final class KeyGestureEvent {
                + "keycodes = " + java.util.Arrays.toString(mKeyGestureEvent.keycodes) + ", "
                + "modifierState = " + mKeyGestureEvent.modifierState + ", "
                + "keyGestureType = " + keyGestureTypeToString(mKeyGestureEvent.gestureType) + ", "
                + "action = " + mKeyGestureEvent.action + ", "
                + "action = " + actionToString(mKeyGestureEvent.action) + ", "
                + "displayId = " + mKeyGestureEvent.displayId + ", "
                + "flags = " + mKeyGestureEvent.flags + ", "
                + "flags = " + flagsToString(mKeyGestureEvent.flags) + ", "
                + "appLaunchData = " + getAppLaunchData()
                + " }";
    }
@@ -819,4 +824,22 @@ public final class KeyGestureEvent {
                return Integer.toHexString(value);
        }
    }

    private static String actionToString(int action) {
        return action == ACTION_GESTURE_START ? "START" : "COMPLETE";
    }

    private static String flagsToString(int flags) {
        StringBuilder res = new StringBuilder();
        if ((flags & FLAG_CANCELLED) != 0) {
            res.append("CANCELLED");
        }
        if ((flags & FLAG_LONG_PRESS) != 0) {
            if (!res.isEmpty()) {
                res.append(" | ");
            }
            res.append("LONG_PRESS");
        }
        return res.toString();
    }
}
+11 −9
Original line number Diff line number Diff line
@@ -1051,20 +1051,22 @@ final class KeyGestureController {

    @MainThread
    private void notifyKeyGestureEvent(AidlKeyGestureEvent event) {
        notifyAllListeners(event);
        KeyGestureEvent keyGestureEvent = new KeyGestureEvent(event);
        while (mLastHandledEvents.size() >= MAX_TRACKED_EVENTS) {
            mLastHandledEvents.removeFirst();
        }
        mLastHandledEvents.addLast(keyGestureEvent);
        boolean complete = keyGestureEvent.getAction() == KeyGestureEvent.ACTION_GESTURE_COMPLETE
                && !keyGestureEvent.isCancelled();
        if (complete) {
            InputDevice device = getInputDevice(event.deviceId);
            if (device == null) {
                return;
            }
        KeyGestureEvent keyGestureEvent = new KeyGestureEvent(event);
        if (event.action == KeyGestureEvent.ACTION_GESTURE_COMPLETE) {
            KeyboardMetricsCollector.logKeyboardSystemsEventReportedAtom(device, event.keycodes,
                    event.modifierState, keyGestureEvent.getLogEvent());
        }
        notifyAllListeners(event);
        while (mLastHandledEvents.size() >= MAX_TRACKED_EVENTS) {
            mLastHandledEvents.removeFirst();
        }
        mLastHandledEvents.addLast(keyGestureEvent);
    }

    @MainThread
+77 −27
Original line number Diff line number Diff line
@@ -82,7 +82,9 @@ import static android.view.contentprotection.flags.Flags.createAccessibilityOver

import static com.android.hardware.input.Flags.enableNew25q2Keycodes;
import static com.android.hardware.input.Flags.hidBluetoothWakeup;
import static com.android.server.policy.SingleKeyGestureEvent.ACTION_CANCEL;
import static com.android.server.policy.SingleKeyGestureEvent.ACTION_COMPLETE;
import static com.android.server.policy.SingleKeyGestureEvent.ACTION_START;
import static com.android.server.policy.SingleKeyGestureEvent.SINGLE_KEY_GESTURE_TYPE_LONG_PRESS;
import static com.android.server.policy.SingleKeyGestureEvent.SINGLE_KEY_GESTURE_TYPE_PRESS;
import static com.android.server.policy.SingleKeyGestureEvent.SINGLE_KEY_GESTURE_TYPE_VERY_LONG_PRESS;
@@ -1443,21 +1445,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        final int behavior = getResolvedLongPressOnPowerBehavior();
        Slog.d(TAG, "powerLongPress: eventTime=" + eventTime
                + " mLongPressOnPowerBehavior=" + mLongPressOnPowerBehavior);

        // Sending a synthetic KeyEvent to StatusBar service with flag FLAG_LONG_PRESS set, when
        // power button is long pressed
        if (enableLppAssistInvocationEffect()) {
            // Long press is detected in a callback, so there's no explicit hardware KeyEvent
            // available here. Instead, we create a synthetic power key event that has properties
            // similar to the original one.
            final KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KEYCODE_POWER);
            event.setFlags(KeyEvent.FLAG_LONG_PRESS);
            // setting both downTime and eventTime as same as downTime is sent as eventTime for long
            // press event in SingleKeyGestureDetector's handler
            event.setTime(eventTime, eventTime);
            sendSystemKeyToStatusBarAsync(event);
        }

        switch (behavior) {
            case LONG_PRESS_POWER_NOTHING:
                break;
@@ -2509,11 +2496,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            final long startTime = event.getStartTime();
            final int displayId = event.getDisplayId();
            final int pressCount = event.getPressCount();
            if (event.getAction() != ACTION_COMPLETE) {
                return;
            }
            final int action = event.getAction();
            switch (event.getType()) {
                case SINGLE_KEY_GESTURE_TYPE_PRESS:
                    if (action != ACTION_COMPLETE) {
                        return;
                    }
                    if (event.getPressCount() > 1) {
                        onMultiPress(startTime, pressCount, displayId);
                    } else {
@@ -2521,9 +2509,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    }
                    break;
                case SINGLE_KEY_GESTURE_TYPE_LONG_PRESS:
                    onLongPress(startTime);
                    onLongPress(event);
                    break;
                case SINGLE_KEY_GESTURE_TYPE_VERY_LONG_PRESS:
                    if (action != ACTION_COMPLETE) {
                        return;
                    }
                    onVeryLongPress();
                    break;
            }
@@ -2545,14 +2536,39 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            }
        }

        private void onLongPress(long downTime) {
        private void onLongPress(@NonNull SingleKeyGestureEvent event) {
            if (mSingleKeyGestureDetector.beganFromNonInteractive()
                    && !mSupportLongPressPowerWhenNonInteractive) {
                Slog.v(TAG, "Not support long press power when device is not interactive.");
                return;
            }

            powerLongPress(downTime);
            // If Assistant mapped to long press, we send start, complete and cancel gesture
            // This is done to allow Assistant launch animation in SysUI. Will extend
            // this to all single key gestures after moving Single key gestures to
            // KeyGestureController.
            if (enableLppAssistInvocationEffect()) {
                // TODO(b/358569822): Remove this synthetic key event and directly listen to key
                //  gesture event in SysUI
                if (event.getAction() == ACTION_COMPLETE) {
                    // Long press is detected in a callback, so there's no explicit hardware
                    // KeyEvent available here. Instead, we create a synthetic power key event that
                    // has properties similar to the original one.
                    final KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KEYCODE_POWER);
                    keyEvent.setFlags(KeyEvent.FLAG_LONG_PRESS);
                    // setting both downTime and eventTime as same as downTime is sent as eventTime
                    // for long press event in SingleKeyGestureDetector's handler
                    keyEvent.setTime(event.getStartTime(), event.getEventTime());
                    sendSystemKeyToStatusBarAsync(keyEvent);
                }
                if (getResolvedLongPressOnPowerBehavior() == LONG_PRESS_POWER_ASSISTANT) {
                    handleSingleKeyGestureInKeyGestureController(
                            KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT, event);
                    return;
                }
            }
            if (event.getAction() == ACTION_COMPLETE) {
                powerLongPress(event.getStartTime());
            }
        }

        private void onVeryLongPress() {
@@ -2785,6 +2801,34 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        }
    }

    // TODO(b/358569822): This is temporarily added to allow single key gestures to be processed
    //  through key gesture infra but keep the detection logic in PWM.
    private void handleSingleKeyGestureInKeyGestureController(
            @KeyGestureEvent.KeyGestureType int keyGestureType,
            @NonNull SingleKeyGestureEvent event) {
        int flags = 0;
        if (event.getType() == SINGLE_KEY_GESTURE_TYPE_LONG_PRESS) {
            flags |= KeyGestureEvent.FLAG_LONG_PRESS;
        } else {
            // Currently not supporting non-long press gestures
            return;
        }
        if (event.getAction() == ACTION_CANCEL) {
            flags |= KeyGestureEvent.FLAG_CANCELLED;
        }
        mInputManagerInternal.handleKeyGestureInKeyGestureController(
                new KeyGestureEvent.Builder()
                        .setKeycodes(new int[]{event.getKeyCode()})
                        .setDeviceId(event.getDeviceId())
                        .setKeyGestureType(keyGestureType)
                        .setFlags(flags)
                        .setAction(event.getAction() == ACTION_START
                                ? KeyGestureEvent.ACTION_GESTURE_START
                                : KeyGestureEvent.ACTION_GESTURE_COMPLETE)
                        .setDisplayId(event.getDisplayId())
                        .build());
    }

    private void initSingleKeyGestureRules(Looper looper) {
        mSingleKeyGestureDetector = SingleKeyGestureDetector.get(mContext, looper);
        mSingleKeyGestureDetector.addRule(new PowerKeyRule());
@@ -3433,8 +3477,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        int modifierState = event.getModifierState();
        boolean keyguardOn = keyguardOn();
        boolean canLaunchApp = isUserSetupComplete() && !keyguardOn;
        if (!event.isCancelled() && Arrays.stream(event.getKeycodes()).anyMatch(
                (keycode) -> keycode == KeyEvent.KEYCODE_POWER)) {
        boolean isPowerKeyPressed = Arrays.stream(event.getKeycodes()).anyMatch(
                (keycode) -> keycode == KeyEvent.KEYCODE_POWER);
        if (complete && isPowerKeyPressed) {
            mPowerKeyHandled = true;
        }
        switch (gestureType) {
@@ -3454,10 +3499,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                break;
            case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT:
            case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT:
                if (complete && canLaunchApp) {
                    launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD,
                boolean isPowerLongPress = event.isLongPress() && isPowerKeyPressed;
                boolean shouldLaunchAssist = complete && (canLaunchApp || isPowerLongPress);
                if (shouldLaunchAssist) {
                    launchAssistAction(
                            isPowerLongPress ? null : Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD,
                            deviceId, SystemClock.uptimeMillis(),
                            AssistUtils.INVOCATION_TYPE_UNKNOWN);
                            isPowerLongPress
                                    ? AssistUtils.INVOCATION_TYPE_POWER_BUTTON_LONG_PRESS
                                    : AssistUtils.INVOCATION_TYPE_UNKNOWN);
                }
                break;
            case KeyGestureEvent.KEY_GESTURE_TYPE_HOME: