diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index 1fc337c818..09783207b7 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -45,6 +45,7 @@
+
diff --git a/lawnchair/src/app/lawnchair/gestures/DirectionalGestureListener.kt b/lawnchair/src/app/lawnchair/gestures/DirectionalGestureListener.kt
new file mode 100644
index 0000000000..d903ed1aff
--- /dev/null
+++ b/lawnchair/src/app/lawnchair/gestures/DirectionalGestureListener.kt
@@ -0,0 +1,66 @@
+package app.lawnchair.gestures
+
+import android.view.View.OnTouchListener
+import android.view.GestureDetector
+import android.annotation.SuppressLint
+import android.content.Context
+import android.view.MotionEvent
+import android.view.GestureDetector.SimpleOnGestureListener
+import android.view.View
+import java.lang.Exception
+import kotlin.math.abs
+
+open class DirectionalGestureListener(ctx: Context?) : OnTouchListener {
+ private val mGestureDetector: GestureDetector
+ @SuppressLint("ClickableViewAccessibility")
+ override fun onTouch(v: View, event: MotionEvent): Boolean {
+ return mGestureDetector.onTouchEvent(event)
+ }
+
+ @Suppress("PrivatePropertyName")
+ private inner class GestureListener : SimpleOnGestureListener() {
+ private val SWIPE_THRESHOLD = 100
+ private val SWIPE_VELOCITY_THRESHOLD = 100
+
+ override fun onDown(e: MotionEvent): Boolean {
+ return true
+ }
+
+ override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
+ var result = false
+ try {
+ val diffY = e2.y - e1.y
+ val diffX = e2.x - e1.x
+ if (abs(diffX) > abs(diffY)) {
+ if (abs(diffX) > SWIPE_THRESHOLD && abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
+ if (diffX > 0) {
+ onSwipeRight()
+ } else {
+ onSwipeLeft()
+ }
+ result = true
+ }
+ } else if (abs(diffY) > SWIPE_THRESHOLD && abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
+ if (diffY > 0) {
+ onSwipeBottom()
+ } else {
+ onSwipeTop()
+ }
+ result = true
+ }
+ } catch (exception: Exception) {
+ exception.printStackTrace()
+ }
+ return result
+ }
+ }
+
+ fun onSwipeRight() {}
+ fun onSwipeLeft() {}
+ fun onSwipeTop() {}
+ open fun onSwipeBottom() {}
+
+ init {
+ mGestureDetector = GestureDetector(ctx, GestureListener())
+ }
+}
\ No newline at end of file
diff --git a/lawnchair/src/app/lawnchair/gestures/SwipeDownGesture.java b/lawnchair/src/app/lawnchair/gestures/SwipeDownGesture.java
new file mode 100644
index 0000000000..690aea309d
--- /dev/null
+++ b/lawnchair/src/app/lawnchair/gestures/SwipeDownGesture.java
@@ -0,0 +1,29 @@
+package app.lawnchair.gestures;
+
+import android.annotation.SuppressLint;
+import android.app.StatusBarManager;
+import android.content.Context;
+import android.os.Build;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.quickstep.TouchInteractionService;
+
+public class SwipeDownGesture extends DirectionalGestureListener {
+
+ private final Context mContext;
+
+ public SwipeDownGesture(Context context) {
+ super(context);
+ mContext = context;
+ }
+
+ @SuppressLint("WrongConstant")
+ @RequiresApi(api = Build.VERSION_CODES.Q)
+ @Override
+ public void onSwipeBottom() {
+ if (!TouchInteractionService.isInitialized()) {
+ ((StatusBarManager) mContext.getSystemService("statusbar")).expandNotificationsPanel();
+ }
+ }
+}
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index 4fa658e7d5..e776081a0d 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -43,6 +43,8 @@ import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.views.OptionsPopupView;
+import app.lawnchair.gestures.SwipeDownGesture;
+
/**
* Helper class to handle touch on empty space in workspace and show options popup on long press
*/
@@ -69,6 +71,7 @@ public class WorkspaceTouchListener extends GestureDetector.SimpleOnGestureListe
private int mLongPressState = STATE_CANCELLED;
private final GestureDetector mGestureDetector;
+ private final SwipeDownGesture mSwipeDown;
public WorkspaceTouchListener(Launcher launcher, Workspace workspace) {
mLauncher = launcher;
@@ -77,10 +80,12 @@ public class WorkspaceTouchListener extends GestureDetector.SimpleOnGestureListe
// likely to cause movement.
mTouchSlop = 2 * ViewConfiguration.get(launcher).getScaledTouchSlop();
mGestureDetector = new GestureDetector(workspace.getContext(), this);
+ mSwipeDown = new SwipeDownGesture(workspace.getContext());
}
@Override
public boolean onTouch(View view, MotionEvent ev) {
+ mSwipeDown.onTouch(view, ev);
mGestureDetector.onTouchEvent(ev);
int action = ev.getActionMasked();