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

Commit c24f69dd authored by Nico's avatar Nico Committed by Bruno Martins
Browse files

Implement edge long swipe gesture

Author: Nico <nicorg2529@gmail.com>
Date:   Sun Mar 8 11:39:47 2020 +0000

    Implement edge long swipe gesture [1/3]

    The gesture will activate if user executes edge swipe for a long
    horizontal motion. The triggered action is configurable in Button
    Settings.

    Reference:
    https://gerrit.dirtyunicorns.com/q/topic:%22back-longswipe-actions%22

    Change-Id: Ie1bbe6645b6a00d346af60d6bb5e4d584997d6e9

Author: LuK1337 <priv.luk@gmail.com>
Date:   Thu Nov 25 17:39:29 2021 +0100

    Use custom flag for edge long swipe gesture

    Previously we were using same flags that'd be used for regular back key
    long press thus being unable to determine whether the event was sent
    from EdgeBackGestureHandle or not.

    Fixes: https://gitlab.com/LineageOS/issues/android/-/issues/4194
    Change-Id: I5c4fd455f581ac5c9c5e3a146095be33e82e8d6e

Change-Id: Iad2252081bc89e82ac70600e4178b0cb3a7f86c5
parent 797c882b
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -1248,6 +1248,12 @@ public class KeyEvent extends InputEvent implements Parcelable {
     */
    public static final int FLAG_TRACKING = 0x200;

    /**
     * Private flag that indicates that event was sent from EdgeBackGestureHandler.
     * @hide
     */
    public static final int FLAG_LONG_SWIPE = 0x800;

    /**
     * Set when a key event has been synthesized to implement default behavior
     * for an event that the application did not handle.
+5 −0
Original line number Diff line number Diff line
@@ -46,6 +46,11 @@ public interface BackAnimation {
     */
    void setTriggerBack(boolean triggerBack);

    /**
     * Sets whether the back long swipe gesture is past the trigger threshold or not.
     */
    void setTriggerLongSwipe(boolean triggerLongSwipe);

    /**
     * Returns a binder that can be passed to an external process to update back animations.
     */
+43 −0
Original line number Diff line number Diff line
@@ -30,13 +30,18 @@ import android.database.ContentObserver;
import android.graphics.Point;
import android.graphics.PointF;
import android.hardware.HardwareBuffer;
import android.hardware.input.InputManager;
import android.net.Uri;
import android.os.Handler;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings.Global;
import android.util.Log;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
@@ -92,6 +97,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
    private boolean mTransitionInProgress = false;
    /** @see #setTriggerBack(boolean) */
    private boolean mTriggerBack;
    /** @see #setTriggerLongSwipe(boolean) */
    private boolean mTriggerLongSwipe;

    @Nullable
    private BackNavigationInfo mBackNavigationInfo;
@@ -193,6 +200,12 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
            mShellExecutor.execute(() -> BackAnimationController.this.setTriggerBack(triggerBack));
        }

        @Override
        public void setTriggerLongSwipe(boolean triggerLongSwipe) {
            mShellExecutor.execute(
                    () -> BackAnimationController.this.setTriggerLongSwipe(triggerLongSwipe));
        }

        @Override
        public void setSwipeThresholds(float triggerThreshold, float progressThreshold) {
            mShellExecutor.execute(() -> BackAnimationController.this.setSwipeThresholds(
@@ -381,6 +394,12 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
        if (!mBackGestureStarted || mBackNavigationInfo == null) {
            return;
        }
        if (mTriggerLongSwipe) {
            // Let key event handlers deal with back long swipe gesture
            sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK, KeyEvent.FLAG_LONG_SWIPE);
            sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK, KeyEvent.FLAG_LONG_SWIPE);
            return;
        }
        int backType = mBackNavigationInfo.getType();
        boolean shouldDispatchToLauncher = shouldDispatchToLauncher(backType);
        IOnBackInvokedCallback targetCallback = shouldDispatchToLauncher
@@ -400,6 +419,18 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
        }
    }

    private boolean sendEvent(int action, int code, int flags) {
        long when = SystemClock.uptimeMillis();
        final KeyEvent ev = new KeyEvent(when, when, action, code, 0 /* repeat */,
                0 /* metaState */, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */,
                flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
                InputDevice.SOURCE_KEYBOARD);

        ev.setDisplayId(mContext.getDisplay().getDisplayId());
        return InputManager.getInstance()
                .injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
    }

    private boolean shouldDispatchToLauncher(int backType) {
        return backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
                && mBackToLauncherCallback != null
@@ -461,6 +492,17 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
        mTriggerBack = triggerBack;
    }

    /**
     * Sets to true when the back long swipe gesture has passed the triggering threshold,
     * false otherwise.
     */
    public void setTriggerLongSwipe(boolean triggerLongSwipe) {
        if (mTransitionInProgress) {
            return;
        }
        mTriggerLongSwipe = triggerLongSwipe;
    }

    private void setSwipeThresholds(float triggerThreshold, float progressThreshold) {
        mProgressThreshold = progressThreshold;
        mTriggerThreshold = triggerThreshold;
@@ -475,6 +517,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
        boolean triggerBack = mTriggerBack;
        mBackNavigationInfo = null;
        mTriggerBack = false;
        mTriggerLongSwipe = false;
        if (backNavigationInfo == null) {
            return;
        }
+4 −1
Original line number Diff line number Diff line
@@ -45,6 +45,9 @@ public interface NavigationEdgeBackPlugin extends Plugin {
    /** Sets the callback that should be invoked when a Back gesture is detected. */
    void setBackCallback(BackCallback callback);

    /** Specifies if the long swipe should be enabled or not. */
    void setLongSwipeEnabled(boolean enabled);

    /** Sets the base LayoutParams for the UI. */
    void setLayoutParams(WindowManager.LayoutParams layoutParams);

@@ -57,7 +60,7 @@ public interface NavigationEdgeBackPlugin extends Plugin {
    /** Callback to let the system react to the detected back gestures. */
    interface BackCallback {
        /** Indicates that a Back gesture was recognized and the system should go back. */
        void triggerBack();
        void triggerBack(boolean isLongPress);

        /** Indicates that the gesture was cancelled and the system should not go back. */
        void cancelBack();
+40 −6
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_

import static com.android.systemui.classifier.Classifier.BACK_GESTURE;

import static org.lineageos.internal.util.DeviceKeysConstants.Action;

import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
@@ -58,6 +60,7 @@ import android.view.WindowMetrics;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.policy.GestureNavigationSettingsObserver;
import com.android.internal.util.LatencyTracker;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -81,8 +84,11 @@ import com.android.systemui.shared.tracing.ProtoTraceable;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.tracing.nano.EdgeBackGestureHandlerProto;
import com.android.systemui.tracing.nano.SystemUiTraceProto;
import com.android.systemui.tuner.TunerService;
import com.android.wm.shell.back.BackAnimation;

import lineageos.providers.LineageSettings;

import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
@@ -96,12 +102,16 @@ import javax.inject.Inject;
 * Utility class to handle edge swipes for back gesture
 */
public class EdgeBackGestureHandler extends CurrentUserTracker
        implements PluginListener<NavigationEdgeBackPlugin>, ProtoTraceable<SystemUiTraceProto> {
        implements PluginListener<NavigationEdgeBackPlugin>, ProtoTraceable<SystemUiTraceProto>,
        TunerService.Tunable {

    private static final String TAG = "EdgeBackGestureHandler";
    private static final int MAX_LONG_PRESS_TIMEOUT = SystemProperties.getInt(
            "gestures.back_timeout", 250);

    private static final String KEY_EDGE_LONG_SWIPE_ACTION =
            "lineagesystem:" + LineageSettings.System.KEY_EDGE_LONG_SWIPE_ACTION;

    private static final int MAX_NUM_LOGGED_PREDICTIONS = 10;
    private static final int MAX_NUM_LOGGED_GESTURES = 10;

@@ -228,6 +238,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
    private boolean mIsEnabled;
    private boolean mIsNavBarShownTransiently;
    private boolean mIsBackGestureAllowed;
    private boolean mIsLongSwipeEnabled;
    private boolean mGestureBlockingActivityRunning;
    private boolean mIsInPipMode;

@@ -239,6 +250,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
    private int mLeftInset;
    private int mRightInset;
    private int mSysUiFlags;
    private float mLongSwipeWidth;

    // For Tf-Lite model.
    private BackGestureTfClassifierProvider mBackGestureTfClassifierProvider;
@@ -260,14 +272,16 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
    private final NavigationEdgeBackPlugin.BackCallback mBackCallback =
            new NavigationEdgeBackPlugin.BackCallback() {
                @Override
                public void triggerBack() {
                public void triggerBack(boolean isLongPress) {
                    // Notify FalsingManager that an intentional gesture has occurred.
                    // TODO(b/186519446): use a different method than isFalseTouch
                    mFalsingManager.isFalseTouch(BACK_GESTURE);
                    // Only inject back keycodes when ahead-of-time back dispatching is disabled.
                    if (mBackAnimation == null) {
                        boolean sendDown = sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
                        boolean sendUp = sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
                        boolean sendDown = sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK,
                                isLongPress ? KeyEvent.FLAG_LONG_SWIPE : 0);
                        boolean sendUp = sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK,
                                isLongPress ? KeyEvent.FLAG_LONG_SWIPE : 0);
                        if (DEBUG_MISSING_GESTURE) {
                            Log.d(DEBUG_MISSING_GESTURE_TAG, "Triggered back: down="
                                    + sendDown + ", up=" + sendUp);
@@ -379,6 +393,9 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
        if (mMLEnableWidth > mEdgeWidthRight) mMLEnableWidth = mEdgeWidthRight;
        if (mMLEnableWidth > mEdgeWidthLeft) mMLEnableWidth = mEdgeWidthLeft;

        final TunerService tunerService = Dependency.get(TunerService.class);
        tunerService.addTunable(this, KEY_EDGE_LONG_SWIPE_ACTION);

        // Reduce the default touch slop to ensure that we can intercept the gesture
        // before the app starts to react to it.
        // TODO(b/130352502) Tune this value and extract into a constant
@@ -511,6 +528,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
                    new NavigationBarEdgePanel(mContext, mBackAnimation, mLatencyTracker));
            mPluginManager.addPluginListener(
                    this, NavigationEdgeBackPlugin.class, /*allowMultiple=*/ false);
            updateLongSwipeWidth();
        }
        // Update the ML model resources.
        updateMLModelState();
@@ -540,6 +558,21 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
        return mIsEnabled && mIsBackGestureAllowed;
    }

    @Override
    public void onTuningChanged(String key, String newValue) {
        if (KEY_EDGE_LONG_SWIPE_ACTION.equals(key)) {
            mIsLongSwipeEnabled = Action.fromIntSafe(TunerService.parseInteger(
                    newValue, 0)) != Action.NOTHING;
            updateLongSwipeWidth();
        }
    }

    private void updateLongSwipeWidth() {
        if (mIsEnabled && mEdgeBackPlugin != null) {
            mEdgeBackPlugin.setLongSwipeEnabled(mIsLongSwipeEnabled);
        }
    }

    /**
     * Update the PiP bounds, used for exclusion calculation.
     */
@@ -869,13 +902,14 @@ public class EdgeBackGestureHandler extends CurrentUserTracker
        if (mEdgeBackPlugin != null) {
            mEdgeBackPlugin.setDisplaySize(mDisplaySize);
        }
        updateLongSwipeWidth();
    }

    private boolean sendEvent(int action, int code) {
    private boolean sendEvent(int action, int code, int flags) {
        long when = SystemClock.uptimeMillis();
        final KeyEvent ev = new KeyEvent(when, when, action, code, 0 /* repeat */,
                0 /* metaState */, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */,
                KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
                flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
                InputDevice.SOURCE_KEYBOARD);

        ev.setDisplayId(mContext.getDisplay().getDisplayId());
Loading