diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java index e30fe667ff..8cbf2394ae 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java @@ -96,7 +96,7 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr return FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get() ? mLauncher.getStateManager().getLastState() : NORMAL; - } else if (fromState == NORMAL && isDragTowardPositive) { + } else if (fromState == NORMAL && shouldOpenAllApps(isDragTowardPositive)) { return ALL_APPS; } return fromState; diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java index 26ab3d6c52..cda785504b 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java @@ -21,6 +21,7 @@ import static android.view.MotionEvent.ACTION_MOVE; import static android.view.MotionEvent.ACTION_UP; import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY; +import static com.android.launcher3.MotionEventsUtils.isTrackpadScroll; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPE_DOWN_WORKSPACE_NOTISHADE_OPEN; import android.graphics.PointF; @@ -57,6 +58,8 @@ public class StatusBarTouchController implements TouchController { /* If {@code false}, this controller should not handle the input {@link MotionEvent}.*/ private boolean mCanIntercept; + private boolean mIsTrackpadReverseScroll; + public StatusBarTouchController(Launcher l) { mLauncher = l; mSystemUiProxy = SystemUiProxy.INSTANCE.get(mLauncher); @@ -92,6 +95,8 @@ public class StatusBarTouchController implements TouchController { } mDownEvents.clear(); mDownEvents.put(pid, new PointF(ev.getX(), ev.getY())); + mIsTrackpadReverseScroll = !mLauncher.isNaturalScrollingEnabled() + && isTrackpadScroll(ev); } else if (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) { // Check!! should only set it only when threshold is not entered. mDownEvents.put(pid, new PointF(ev.getX(idx), ev.getY(idx))); @@ -102,6 +107,9 @@ public class StatusBarTouchController implements TouchController { if (action == ACTION_MOVE) { float dy = ev.getY(idx) - mDownEvents.get(pid).y; float dx = ev.getX(idx) - mDownEvents.get(pid).x; + if (mIsTrackpadReverseScroll) { + dy = -dy; + } // Currently input dispatcher will not do touch transfer if there are more than // one touch pointer. Hence, even if slope passed, only set the slippery flag // when there is single touch event. (context: InputDispatcher.cpp line 1445) @@ -126,6 +134,7 @@ public class StatusBarTouchController implements TouchController { mLauncher.getStatsLogManager().logger() .log(LAUNCHER_SWIPE_DOWN_WORKSPACE_NOTISHADE_OPEN); setWindowSlippery(false); + mIsTrackpadReverseScroll = false; return true; } return true; diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 5a0cf9daf3..37b3e05056 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -100,6 +100,7 @@ import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK; import static com.android.launcher3.states.RotationHelper.REQUEST_NONE; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.ItemInfoMatcher.forFolderMatch; +import static com.android.launcher3.util.SettingsCache.TOUCHPAD_NATURAL_SCROLLING; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -232,6 +233,7 @@ import com.android.launcher3.util.PendingRequestArgs; import com.android.launcher3.util.RunnableList; import com.android.launcher3.util.ScreenOnTracker; import com.android.launcher3.util.ScreenOnTracker.ScreenOnListener; +import com.android.launcher3.util.SettingsCache; import com.android.launcher3.util.SystemUiController; import com.android.launcher3.util.Themes; import com.android.launcher3.util.Thunk; @@ -415,6 +417,11 @@ public class Launcher extends StatefulActivity private final List mBackPressedHandlers = new ArrayList<>(); private boolean mIsColdStartupAfterReboot; + private boolean mIsNaturalScrollingEnabled; + + private final SettingsCache.OnChangeListener mNaturalScrollingChangedListener = + enabled -> mIsNaturalScrollingEnabled = enabled; + public static Launcher getLauncher(Context context) { return fromContext(context); } @@ -563,6 +570,10 @@ public class Launcher extends StatefulActivity } getRootView().dispatchInsets(); + final SettingsCache settingsCache = SettingsCache.INSTANCE.get(this); + settingsCache.register(TOUCHPAD_NATURAL_SCROLLING, mNaturalScrollingChangedListener); + mIsNaturalScrollingEnabled = settingsCache.getValue(TOUCHPAD_NATURAL_SCROLLING); + // Listen for screen turning off ScreenOnTracker.INSTANCE.get(this).addListener(mScreenOnListener); getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW, @@ -1680,6 +1691,8 @@ public class Launcher extends StatefulActivity super.onDestroy(); ACTIVITY_TRACKER.onActivityDestroyed(this); + SettingsCache.INSTANCE.get(this).unregister(TOUCHPAD_NATURAL_SCROLLING, + mNaturalScrollingChangedListener); ScreenOnTracker.INSTANCE.get(this).removeListener(mScreenOnListener); mWorkspace.removeFolderListeners(); PluginManagerWrapper.INSTANCE.get(this).removePluginListener(this); @@ -3181,6 +3194,10 @@ public class Launcher extends StatefulActivity return !isWorkspaceLoading(); } + public boolean isNaturalScrollingEnabled() { + return mIsNaturalScrollingEnabled; + } + public void setWaitingForResult(PendingRequestArgs args) { mPendingRequestArgs = args; } diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java index cec4574fd8..9aed4ebb51 100644 --- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java +++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java @@ -22,6 +22,7 @@ import static com.android.launcher3.LauncherAnimUtils.newCancelListener; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; +import static com.android.launcher3.MotionEventsUtils.isTrackpadScroll; import static com.android.launcher3.anim.AnimatorListeners.forEndCallback; import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_ALLAPPS; import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME; @@ -68,6 +69,7 @@ public abstract class AbstractStateChangeTouchController protected boolean mGoingBetweenStates = true; // Ratio of transition process [0, 1] to drag displacement (px) protected float mProgressMultiplier; + protected boolean mIsTrackpadReverseScroll; private boolean mNoIntercept; private boolean mIsLogContainerSet; @@ -92,6 +94,9 @@ public abstract class AbstractStateChangeTouchController return false; } + mIsTrackpadReverseScroll = !mLauncher.isNaturalScrollingEnabled() + && isTrackpadScroll(ev); + // Now figure out which direction scroll events the controller will start // calling the callbacks. final int directionsToDetectScroll; @@ -248,6 +253,11 @@ public abstract class AbstractStateChangeTouchController } mIsLogContainerSet = true; } + // Only reverse the gesture to open all apps (not close) when trackpad reverse scrolling is + // on. + if (mIsTrackpadReverseScroll && mStartState == NORMAL) { + displacement = -displacement; + } return onDrag(displacement); } @@ -274,6 +284,11 @@ public abstract class AbstractStateChangeTouchController return; } + // Only reverse the gesture to open all apps (not close) when trackpad reverse scrolling is + // on. + if (mIsTrackpadReverseScroll && mStartState == NORMAL) { + velocity = -velocity; + } boolean fling = mDetector.isFling(velocity); boolean blockedFling = fling && mFlingBlockCheck.isBlocked(); @@ -412,9 +427,15 @@ public abstract class AbstractStateChangeTouchController mGoingBetweenStates = true; mDetector.finishedScrolling(); mDetector.setDetectableScrollConditions(0, false); + mIsTrackpadReverseScroll = false; } private void cancelAnimationControllers() { mCurrentAnimation = null; } + + protected boolean shouldOpenAllApps(boolean isDragTowardPositive) { + return (isDragTowardPositive && !mIsTrackpadReverseScroll) + || (!isDragTowardPositive && mIsTrackpadReverseScroll); + } } diff --git a/src/com/android/launcher3/touch/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java index 447d22b591..8b9bc19e18 100644 --- a/src/com/android/launcher3/touch/AllAppsSwipeController.java +++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java @@ -166,7 +166,7 @@ public class AllAppsSwipeController extends AbstractStateChangeTouchController { @Override protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) { - if (fromState == NORMAL && isDragTowardPositive) { + if (fromState == NORMAL && shouldOpenAllApps(isDragTowardPositive)) { return ALL_APPS; } else if (fromState == ALL_APPS && !isDragTowardPositive) { return NORMAL; diff --git a/src/com/android/launcher3/util/SettingsCache.java b/src/com/android/launcher3/util/SettingsCache.java index 29ec5ab220..e663ac2a8d 100644 --- a/src/com/android/launcher3/util/SettingsCache.java +++ b/src/com/android/launcher3/util/SettingsCache.java @@ -57,6 +57,9 @@ public class SettingsCache extends ContentObserver implements SafeCloseable { "swipe_bottom_to_notification_enabled"; public static final Uri ROTATION_SETTING_URI = Settings.System.getUriFor(ACCELEROMETER_ROTATION); + /** Hidden field {@link Settings.System#TOUCHPAD_NATURAL_SCROLLING}. */ + public static final Uri TOUCHPAD_NATURAL_SCROLLING = Settings.System.getUriFor( + "TOUCHPAD_NATURAL_SCROLLING"); private static final String SYSTEM_URI_PREFIX = Settings.System.CONTENT_URI.toString(); private static final String GLOBAL_URI_PREFIX = Settings.Global.CONTENT_URI.toString();