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

Commit e0a25fbd authored by Hyunyoung Song's avatar Hyunyoung Song Committed by Android (Google) Code Review
Browse files

Merge "Add CUSTOM_LPNH_THRESHOLDS feature flag to customize LPNH" into main

parents 9633e5b7 9fbc52f0
Loading
Loading
Loading
Loading
+45 −16
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ import static android.view.View.GONE;
import static android.view.View.VISIBLE;

import static com.android.launcher3.LauncherPrefs.ALL_APPS_OVERVIEW_THRESHOLD;
import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE;
import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_TIMEOUT_MS;
import static com.android.launcher3.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY;
import static com.android.launcher3.uioverrides.plugins.PluginManagerWrapper.PLUGIN_CHANGED;
import static com.android.launcher3.uioverrides.plugins.PluginManagerWrapper.pluginEnabledKey;
@@ -63,6 +65,7 @@ import androidx.preference.PreferenceViewHolder;
import androidx.preference.SeekBarPreference;
import androidx.preference.SwitchPreference;

import com.android.launcher3.ConstantItem;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
@@ -111,6 +114,9 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat {
        if (FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get()) {
            addAllAppsFromOverviewCatergory();
        }
        if (FeatureFlags.CUSTOM_LPNH_THRESHOLDS.get()) {
            addCustomLpnhCatergory();
        }

        if (getActivity() != null) {
            getActivity().setTitle("Developer Options");
@@ -400,29 +406,52 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat {

    private void addAllAppsFromOverviewCatergory() {
        PreferenceCategory category = newCategory("All Apps from Overview Config");
        category.addPreference(createSeekBarPreference("Threshold to open All Apps from Overview",
                105, 500, 100, ALL_APPS_OVERVIEW_THRESHOLD));
    }

        SeekBarPreference thresholdPref = new SeekBarPreference(getContext());
        thresholdPref.setTitle("Threshold to open All Apps from Overview");
        thresholdPref.setSingleLineTitle(false);
    private void addCustomLpnhCatergory() {
        PreferenceCategory category = newCategory("Long Press Nav Handle Config");
        category.addPreference(createSeekBarPreference("Slop multiplier (applied to edge slop, "
                        + "which is generally already 50% higher than touch slop)",
                25, 200, 100, LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE));
        category.addPreference(createSeekBarPreference("Trigger milliseconds",
                100, 500, 1, LONG_PRESS_NAV_HANDLE_TIMEOUT_MS));
    }

        // These values are 100x swipe up shift value (100 = where overview sits).
        thresholdPref.setMax(500);
        thresholdPref.setMin(105);
        thresholdPref.setUpdatesContinuously(true);
        thresholdPref.setIconSpaceReserved(false);
    /**
     * Create a preference with text and a seek bar. Should be added to a PreferenceCategory.
     *
     * @param title text to show for this seek bar
     * @param min min value for the seek bar
     * @param max max value for the seek bar
     * @param scale how much to divide the value to convert int to float
     * @param launcherPref used to store the current value
     */
    private SeekBarPreference createSeekBarPreference(String title, int min, int max, int scale,
            ConstantItem<Integer> launcherPref) {
        SeekBarPreference seekBarPref = new SeekBarPreference(getContext());
        seekBarPref.setTitle(title);
        seekBarPref.setSingleLineTitle(false);

        seekBarPref.setMax(max);
        seekBarPref.setMin(min);
        seekBarPref.setUpdatesContinuously(true);
        seekBarPref.setIconSpaceReserved(false);
        // Don't directly save to shared prefs, use LauncherPrefs instead.
        thresholdPref.setPersistent(false);
        thresholdPref.setOnPreferenceChangeListener((preference, newValue) -> {
            LauncherPrefs.get(getContext()).put(ALL_APPS_OVERVIEW_THRESHOLD, newValue);
            preference.setSummary(String.valueOf((int) newValue / 100f));
        seekBarPref.setPersistent(false);
        seekBarPref.setOnPreferenceChangeListener((preference, newValue) -> {
            LauncherPrefs.get(getContext()).put(launcherPref, newValue);
            preference.setSummary(String.valueOf(scale == 1 ? newValue
                    : (int) newValue / (float) scale));
            return true;
        });
        int value = LauncherPrefs.get(getContext()).get(ALL_APPS_OVERVIEW_THRESHOLD);
        thresholdPref.setValue(value);
        int value = LauncherPrefs.get(getContext()).get(launcherPref);
        seekBarPref.setValue(value);
        // For some reason the initial value is not triggering the summary update, so call manually.
        thresholdPref.getOnPreferenceChangeListener().onPreferenceChange(thresholdPref, value);
        seekBarPref.getOnPreferenceChangeListener().onPreferenceChange(seekBarPref, value);

        category.addPreference(thresholdPref);
        return seekBarPref;
    }

    private String toName(String action) {
+58 −3
Original line number Diff line number Diff line
@@ -15,14 +15,19 @@
 */
package com.android.quickstep.inputconsumers;

import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE;
import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_TIMEOUT_MS;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;

import android.content.Context;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.ViewConfiguration;

import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.InputConsumer;
import com.android.systemui.shared.system.InputMonitorCompat;
@@ -37,19 +42,31 @@ public class NavHandleLongPressInputConsumer extends DelegateInputConsumer {
    private final float mNavHandleWidth;
    private final float mScreenWidth;

    // Below are only used if CUSTOM_LPNH_THRESHOLDS is enabled.
    private final float mCustomTouchSlopSquared;
    private final int mCustomLongPressTimeout;
    private final Runnable mTriggerCustomLongPress = this::triggerCustomLongPress;
    private MotionEvent mCurrentCustomDownEvent;

    public NavHandleLongPressInputConsumer(Context context, InputConsumer delegate,
            InputMonitorCompat inputMonitor) {
        super(delegate, inputMonitor);
        mNavHandleWidth = context.getResources().getDimensionPixelSize(
                R.dimen.navigation_home_handle_width);
        mScreenWidth = DisplayController.INSTANCE.get(context).getInfo().currentSize.x;
        float customSlopMultiplier =
                LauncherPrefs.get(context).get(LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE) / 100f;
        float customTouchSlop =
                ViewConfiguration.get(context).getScaledEdgeSlop() * customSlopMultiplier;
        mCustomTouchSlopSquared = customTouchSlop * customTouchSlop;
        mCustomLongPressTimeout = LauncherPrefs.get(context).get(LONG_PRESS_NAV_HANDLE_TIMEOUT_MS);

        mNavHandleLongPressHandler = NavHandleLongPressHandler.newInstance(context);

        mLongPressDetector = new GestureDetector(context, new SimpleOnGestureListener() {
            @Override
            public void onLongPress(MotionEvent motionEvent) {
                if (isInArea(motionEvent.getRawX())) {
                if (isInNavBarHorizontalArea(motionEvent.getRawX())) {
                    Runnable longPressRunnable = mNavHandleLongPressHandler.getLongPressRunnable();
                    if (longPressRunnable != null) {
                        OtherActivityInputConsumer oaic = getInputConsumerOfClass(
@@ -74,13 +91,51 @@ public class NavHandleLongPressInputConsumer extends DelegateInputConsumer {

    @Override
    public void onMotionEvent(MotionEvent ev) {
        if (!FeatureFlags.CUSTOM_LPNH_THRESHOLDS.get()) {
            mLongPressDetector.onTouchEvent(ev);
        } else {
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN -> {
                    if (mCurrentCustomDownEvent != null) {
                        mCurrentCustomDownEvent.recycle();
                    }
                    mCurrentCustomDownEvent = MotionEvent.obtain(ev);
                    if (isInNavBarHorizontalArea(ev.getRawX())) {
                        MAIN_EXECUTOR.getHandler().postDelayed(mTriggerCustomLongPress,
                                mCustomLongPressTimeout);
                    }
                }
                case MotionEvent.ACTION_MOVE -> {
                    double touchDeltaSquared =
                            Math.pow(ev.getX() - mCurrentCustomDownEvent.getX(), 2)
                            + Math.pow(ev.getY() - mCurrentCustomDownEvent.getY(), 2);
                    if (touchDeltaSquared > mCustomTouchSlopSquared) {
                        cancelCustomLongPress();
                    }
                }
                case MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> cancelCustomLongPress();
            }
        }

        if (mState != STATE_ACTIVE) {
            mDelegate.onMotionEvent(ev);
        }
    }

    protected boolean isInArea(float x) {
    private void triggerCustomLongPress() {
        Runnable longPressRunnable = mNavHandleLongPressHandler.getLongPressRunnable();
        if (longPressRunnable != null) {
            setActive(mCurrentCustomDownEvent);

            MAIN_EXECUTOR.post(longPressRunnable);
        }
    }

    private void cancelCustomLongPress() {
        MAIN_EXECUTOR.getHandler().removeCallbacks(mTriggerCustomLongPress);
    }

    private boolean isInNavBarHorizontalArea(float x) {
        float areaFromMiddle = mNavHandleWidth / 2.0f;
        float distFromMiddle = Math.abs(mScreenWidth / 2.0f - x);

+4 −0
Original line number Diff line number Diff line
@@ -66,6 +66,10 @@ public class LauncherAppState implements SafeCloseable {
    public static final String ACTION_FORCE_ROLOAD = "force-reload-launcher";
    public static final String KEY_ICON_STATE = "pref_icon_shape_path";
    public static final String KEY_ALL_APPS_OVERVIEW_THRESHOLD = "pref_all_apps_overview_threshold";
    public static final String KEY_LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE =
            "pref_long_press_nav_handle_slop_multiplier";
    public static final String KEY_LONG_PRESS_NAV_HANDLE_TIMEOUT_MS =
            "pref_long_press_nav_handle_timeout_ms";

    // We do not need any synchronization for this variable as its only written on UI thread.
    public static final MainThreadInitializedObject<LauncherAppState> INSTANCE =
+15 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.content.Context.MODE_PRIVATE
import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.util.Log
import android.view.ViewConfiguration
import androidx.annotation.VisibleForTesting
import com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN
import com.android.launcher3.LauncherFiles.DEVICE_PREFERENCES_KEY
@@ -308,6 +309,20 @@ class LauncherPrefs(private val encryptedContext: Context) {
                EncryptionType.MOVE_TO_DEVICE_PROTECTED
            )
        @JvmField
        val LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE =
            nonRestorableItem(
                LauncherAppState.KEY_LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE,
                100,
                EncryptionType.MOVE_TO_DEVICE_PROTECTED
            )
        @JvmField
        val LONG_PRESS_NAV_HANDLE_TIMEOUT_MS =
            nonRestorableItem(
                LauncherAppState.KEY_LONG_PRESS_NAV_HANDLE_TIMEOUT_MS,
                ViewConfiguration.getLongPressTimeout(),
                EncryptionType.MOVE_TO_DEVICE_PROTECTED
            )
        @JvmField
        val THEMED_ICONS =
            backedUpItem(Themes.KEY_THEMED_ICONS, false, EncryptionType.MOVE_TO_DEVICE_PROTECTED)
        @JvmField val PROMISE_ICON_IDS = backedUpItem(InstallSessionHelper.PROMISE_ICON_IDS, "")
+4 −0
Original line number Diff line number Diff line
@@ -119,6 +119,10 @@ public final class FeatureFlags {
            getDebugFlag(275132633, "ENABLE_ALL_APPS_FROM_OVERVIEW", DISABLED,
                    "Allow entering All Apps from Overview (e.g. long swipe up from app)");

    public static final BooleanFlag CUSTOM_LPNH_THRESHOLDS =
            getDebugFlag(301680992, "CUSTOM_LPNH_THRESHOLDS", DISABLED,
                    "Add dev options to customize the LPNH trigger slop and milliseconds");

    public static final BooleanFlag ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS = getReleaseFlag(
            270394468, "ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", ENABLED,
            "Enable option to show keyboard when going to all-apps");