summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuca Stefani <luca.stefani.ge1@gmail.com>2019-02-01 22:08:39 +0100
committerBruno Martins <bgcngm@gmail.com>2019-02-04 14:52:05 +0100
commite653623bfae6cbee7dc8b8029ef626113810ecb2 (patch)
tree291a7d47ec483bb756aada2994d602011e464512
parent51fcc5b08f3a7aef613c6176e6351604cf7ca5eb (diff)
downloadandroid_packages_apps_Trebuchet-e653623bfae6cbee7dc8b8029ef626113810ecb2.tar.gz
android_packages_apps_Trebuchet-e653623bfae6cbee7dc8b8029ef626113810ecb2.tar.bz2
android_packages_apps_Trebuchet-e653623bfae6cbee7dc8b8029ef626113810ecb2.zip
Trebuchet: Add reverse engineered Q swipe down gesture
Change-Id: I4b6fd72299ebd34fa17397eacbb14617b4cedc90
-rw-r--r--quickstep/libs/sysui_shared.jarbin133150 -> 118069 bytes
-rw-r--r--quickstep/src/com/android/launcher3/uioverrides/StatusBarTouchController.java116
-rw-r--r--quickstep/src/com/android/launcher3/uioverrides/UiFactory.java9
-rw-r--r--res/values/lineage_strings.xml3
-rw-r--r--res/xml/launcher_preferences.xml6
-rw-r--r--src/com/android/launcher3/AbstractFloatingView.java4
-rw-r--r--src/com/android/launcher3/Utilities.java4
-rw-r--r--src/com/android/launcher3/touch/TouchEventTranslator.java218
8 files changed, 356 insertions, 4 deletions
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index 27de1e907..4ed224193 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/src/com/android/launcher3/uioverrides/StatusBarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/StatusBarTouchController.java
new file mode 100644
index 000000000..86ec3231f
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/StatusBarTouchController.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.uioverrides;
+
+import android.content.SharedPreferences;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.touch.TouchEventTranslator;
+import com.android.launcher3.util.TouchController;
+import com.android.quickstep.RecentsModel;
+import com.android.systemui.shared.recents.ISystemUiProxy;
+
+public class StatusBarTouchController implements TouchController {
+ private static final String TAG = StatusBarTouchController.class.getSimpleName();
+ private static final String PREF_STATUSBAR_EXPAND = "pref_expand_statusbar";
+
+ private boolean mCanIntercept;
+ private ISystemUiProxy mSysUiProxy;
+
+ private final Launcher mLauncher;
+ private final SharedPreferences mSharedPreferences;
+ private final float mTouchSlop;
+
+ protected final TouchEventTranslator mTranslator =
+ new TouchEventTranslator(this::dispatchTouchEvent);
+
+ public StatusBarTouchController(Launcher launcher) {
+ mLauncher = launcher;
+ mSharedPreferences = Utilities.getPrefs(launcher);
+ mTouchSlop = ViewConfiguration.get(launcher).getScaledTouchSlop() * 2;
+ }
+
+ private void dispatchTouchEvent(MotionEvent ev) {
+ try {
+ if (mSysUiProxy != null) {
+ mSysUiProxy.onStatusBarMotionEvent(ev);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Remote exception on sysUiProxy.", e);
+ }
+ }
+
+ @Override
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ int action = ev.getActionMasked();
+ if (action == MotionEvent.ACTION_DOWN) {
+ mCanIntercept = canInterceptTouch(ev);
+ if (!mCanIntercept) {
+ return false;
+ }
+ mTranslator.reset();
+ mTranslator.setDownParameters(0, ev);
+ } else if (action == MotionEvent.ACTION_POINTER_DOWN) {
+ mTranslator.setDownParameters(ev.getActionIndex(), ev);
+ }
+
+ if (mCanIntercept && action == MotionEvent.ACTION_MOVE) {
+ float dy = ev.getY() - mTranslator.getDownY();
+ float dx = ev.getX() - mTranslator.getDownX();
+ if (dy > mTouchSlop && dy > Math.abs(dx)) {
+ mTranslator.dispatchDownEvents(ev);
+ mTranslator.processMotionEvent(ev);
+ return true;
+ } else if (Math.abs(dx) > mTouchSlop) {
+ mCanIntercept = false;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onControllerTouchEvent(MotionEvent ev) {
+ mTranslator.processMotionEvent(ev);
+ return true;
+ }
+
+ private boolean canInterceptTouch(MotionEvent ev) {
+ if (!mSharedPreferences.getBoolean(PREF_STATUSBAR_EXPAND, true)) {
+ return false;
+ }
+
+ if (mLauncher.isInState(LauncherState.NORMAL)) {
+ if (AbstractFloatingView.getTopOpenViewWithType(
+ mLauncher, AbstractFloatingView.TYPE_STATUS_BAR_SWIPE_DOWN_DISALLOW) == null) {
+ if (ev.getY() > mLauncher.getDragLayer().getHeight() -
+ mLauncher.getDeviceProfile().getInsets().bottom) {
+ return false;
+ }
+ mSysUiProxy = RecentsModel.getInstance(mLauncher).getSystemUiProxy();
+ return mSysUiProxy != null;
+ }
+ }
+ return false;
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index ac9f8634e..47e67005f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -63,19 +63,22 @@ public class UiFactory {
return new TouchController[] {
launcher.getDragController(),
new OverviewToAllAppsTouchController(launcher),
- new LauncherTaskViewController(launcher)};
+ new LauncherTaskViewController(launcher),
+ new StatusBarTouchController(launcher)};
}
if (launcher.getDeviceProfile().isVerticalBarLayout()) {
return new TouchController[] {
launcher.getDragController(),
new OverviewToAllAppsTouchController(launcher),
new LandscapeEdgeSwipeController(launcher),
- new LauncherTaskViewController(launcher)};
+ new LauncherTaskViewController(launcher),
+ new StatusBarTouchController(launcher)};
} else {
return new TouchController[] {
launcher.getDragController(),
new PortraitStatesTouchController(launcher),
- new LauncherTaskViewController(launcher)};
+ new LauncherTaskViewController(launcher),
+ new StatusBarTouchController(launcher)};
}
}
diff --git a/res/values/lineage_strings.xml b/res/values/lineage_strings.xml
index 14d6f83bc..828f2d465 100644
--- a/res/values/lineage_strings.xml
+++ b/res/values/lineage_strings.xml
@@ -62,6 +62,9 @@
<string name="google_title" translatable="false">Google</string>
<string name="play_folder_title">Play</string>
+ <!-- Expand statusbar -->
+ <string name="statusbar_expand">Swipe down to show notifications</string>
+
<!-- Hidden apps -->
<string name="hidden_apps_manager_name">Hidden apps</string>
<string name="hidden_apps_auth_manager">Unlock to manage the hidden apps</string>
diff --git a/res/xml/launcher_preferences.xml b/res/xml/launcher_preferences.xml
index a268116e1..e33f48511 100644
--- a/res/xml/launcher_preferences.xml
+++ b/res/xml/launcher_preferences.xml
@@ -57,6 +57,12 @@
android:title="@string/desktop_show_labels"
android:defaultValue="true"
android:persistent="true" />
+
+ <SwitchPreference
+ android:key="pref_expand_statusbar"
+ android:title="@string/statusbar_expand"
+ android:defaultValue="true"
+ android:persistent="true" />
</PreferenceCategory>
<PreferenceCategory
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index b614ec9d6..cf3f09889 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -52,6 +52,7 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
TYPE_WIDGETS_FULL_SHEET,
TYPE_ON_BOARD_POPUP,
TYPE_DISCOVERY_BOUNCE,
+ TYPE_STATUS_BAR_SWIPE_DOWN_DISALLOW,
TYPE_QUICKSTEP_PREVIEW,
TYPE_TASK_MENU,
@@ -66,6 +67,7 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
public static final int TYPE_WIDGETS_FULL_SHEET = 1 << 4;
public static final int TYPE_ON_BOARD_POPUP = 1 << 5;
public static final int TYPE_DISCOVERY_BOUNCE = 1 << 6;
+ public static final int TYPE_STATUS_BAR_SWIPE_DOWN_DISALLOW = 1 << 10;
// Popups related to quickstep UI
public static final int TYPE_QUICKSTEP_PREVIEW = 1 << 7;
@@ -75,7 +77,7 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
public static final int TYPE_ALL = TYPE_FOLDER | TYPE_ACTION_POPUP
| TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_WIDGETS_FULL_SHEET
| TYPE_QUICKSTEP_PREVIEW | TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE | TYPE_TASK_MENU
- | TYPE_OPTIONS_POPUP;
+ | TYPE_OPTIONS_POPUP | TYPE_STATUS_BAR_SWIPE_DOWN_DISALLOW;
// Type of popups which should be kept open during launcher rebind
public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 2330b10e3..67d70537a 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -136,6 +136,10 @@ public final class Utilities {
return Log.isLoggable(propertyName, Log.VERBOSE);
}
+ public interface Consumer<T> {
+ void accept(T t);
+ }
+
/**
* Given a coordinate relative to the descendant, find the coordinate in a parent view's
* coordinates.
diff --git a/src/com/android/launcher3/touch/TouchEventTranslator.java b/src/com/android/launcher3/touch/TouchEventTranslator.java
new file mode 100644
index 000000000..4228a120a
--- /dev/null
+++ b/src/com/android/launcher3/touch/TouchEventTranslator.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.touch;
+
+import android.graphics.PointF;
+import android.util.Log;
+import android.util.Pair;
+import android.util.SparseArray;
+import android.view.MotionEvent;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
+
+import com.android.launcher3.Utilities.Consumer;
+
+public class TouchEventTranslator {
+ private static final String TAG = TouchEventTranslator.class.getSimpleName();
+
+ private final DownState ZERO = new DownState(0, 0.0f, 0.0f);
+ private final SparseArray<Pair<PointerProperties[], PointerCoords[]>> mCache =
+ new SparseArray<>();
+ private final SparseArray<DownState> mDownEvents = new SparseArray<>();
+ private final SparseArray<PointF> mFingers = new SparseArray<>();
+ private final Consumer<MotionEvent> mListener;
+
+ private class DownState {
+ float downX;
+ float downY;
+ long timeStamp;
+
+ public DownState(long timeStamp, float downX, float downY) {
+ this.timeStamp = timeStamp;
+ this.downX = downX;
+ this.downY = downY;
+ }
+ }
+
+ public TouchEventTranslator(Consumer<MotionEvent> listener) {
+ mListener = listener;
+ }
+
+ public void reset() {
+ mDownEvents.clear();
+ mFingers.clear();
+ }
+
+ public float getDownX() {
+ return mDownEvents.get(0).downX;
+ }
+
+ public float getDownY() {
+ return mDownEvents.get(0).downY;
+ }
+
+ public void setDownParameters(int idx, MotionEvent e) {
+ mDownEvents.append(idx, new DownState(e.getEventTime(), e.getX(idx), e.getY(idx)));
+ }
+
+ public void dispatchDownEvents(MotionEvent ev) {
+ for (int i = 0; i < ev.getPointerCount() && i < mDownEvents.size(); i++) {
+ put(ev.getPointerId(i), i, ev.getX(i), 0.0f, mDownEvents.get(i).timeStamp, ev);
+ }
+ }
+
+ public void processMotionEvent(MotionEvent ev) {
+ int index = ev.getActionIndex();
+ float x = ev.getX(index);
+ float y = ev.getY(index) - mDownEvents.get(index, ZERO).downY;
+ int actionMasked = ev.getActionMasked();
+ if (actionMasked != MotionEvent.ACTION_UP) {
+ if (actionMasked == MotionEvent.ACTION_MOVE) {
+ for (int i = 0; i < ev.getPointerCount(); i++) {
+ position(ev.getPointerId(i), x, y);
+ }
+ generateEvent(ev.getAction(), ev);
+ return;
+ } else if (actionMasked == MotionEvent.ACTION_CANCEL) {
+ cancel(ev);
+ return;
+ } else if (actionMasked == MotionEvent.ACTION_POINTER_DOWN) {
+ int pid = ev.getPointerId(index);
+ if (mFingers.get(pid, null) != null) {
+ for (int i = 0; i < ev.getPointerCount(); i++) {
+ position(ev.getPointerId(i), x, y);
+ }
+ generateEvent(ev.getAction(), ev);
+ return;
+ }
+ put(pid, index, x, y, ev);
+ return;
+ } else if (actionMasked != MotionEvent.ACTION_POINTER_UP) {
+ Log.v(TAG, "Didn't process ");
+ return;
+ }
+ }
+ lift(ev.getPointerId(index), index, x, y, ev);
+ }
+
+ private TouchEventTranslator put(int id, int index, float x, float y, MotionEvent ev) {
+ return put(id, index, x, y, ev.getEventTime(), ev);
+ }
+
+ private TouchEventTranslator put(int id, int index, float x, float y, long ms, MotionEvent ev) {
+ int action;
+ checkFingerExistence(id, false);
+ mFingers.put(id, new PointF(x, y));
+ int n = mFingers.size();
+ if (mCache.get(n) == null) {
+ PointerProperties[] properties = new PointerProperties[n];
+ PointerCoords[] coords = new PointerCoords[n];
+ for (int i = 0; i < n; i++) {
+ properties[i] = new PointerProperties();
+ coords[i] = new PointerCoords();
+ }
+ mCache.put(n, new Pair<>(properties, coords));
+ }
+
+ boolean isInitialDown = mFingers.size() == 0;
+ action = isInitialDown ?
+ MotionEvent.ACTION_DOWN :
+ MotionEvent.ACTION_POINTER_DOWN | (index << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
+ generateEvent(action, ms, ev);
+ return this;
+ }
+
+ public TouchEventTranslator position(int id, float x, float y) {
+ checkFingerExistence(id, true);
+ mFingers.get(id).set(x, y);
+ return this;
+ }
+
+ private TouchEventTranslator lift(int id, int index, MotionEvent ev) {
+ int action;
+ checkFingerExistence(id, true);
+
+ boolean isFinalUp = mFingers.size() == 1;
+ action = isFinalUp ?
+ MotionEvent.ACTION_UP :
+ MotionEvent.ACTION_POINTER_UP | (index << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
+ generateEvent(action, ev);
+ mFingers.remove(id);
+ return this;
+ }
+
+ private TouchEventTranslator lift(int id, int index, float x, float y, MotionEvent ev) {
+ checkFingerExistence(id, true);
+ mFingers.get(id).set(x, y);
+ return lift(id, index, ev);
+ }
+
+ public TouchEventTranslator cancel(MotionEvent ev) {
+ generateEvent(MotionEvent.ACTION_CANCEL, ev);
+ mFingers.clear();
+ return this;
+ }
+
+ private void checkFingerExistence(int id, boolean shouldExist) {
+ if (shouldExist == (mFingers.get(id, null) == null)) {
+ throw new IllegalArgumentException(
+ shouldExist ? "Finger does not exist" : "Finger already exists");
+ }
+ }
+
+ private void generateEvent(int action, MotionEvent ev) {
+ generateEvent(action, ev.getEventTime(), ev);
+ }
+
+ private void generateEvent(int action, long ms, MotionEvent ev) {
+ Pair<PointerProperties[], PointerCoords[]> state = getFingerState();
+ MotionEvent event = MotionEvent.obtain(
+ mDownEvents.get(0).timeStamp, ms, action,
+ state.first.length, state.first, state.second,
+ ev.getMetaState(), ev.getButtonState(), ev.getXPrecision(),
+ ev.getYPrecision(), ev.getDeviceId(), ev.getEdgeFlags(),
+ ev.getSource(), ev.getFlags());
+ if (event.getPointerId(event.getActionIndex()) >= 0) {
+ mListener.accept(event);
+ event.recycle();
+ return;
+ }
+ throw new IllegalStateException(String.valueOf(event.getActionIndex()) +
+ " not found in MotionEvent");
+ }
+
+ private Pair<PointerProperties[], PointerCoords[]> getFingerState() {
+ int nFingers = mFingers.size();
+ Pair<PointerProperties[], PointerCoords[]> result = mCache.get(nFingers);
+ PointerProperties[] properties = result.first;
+ PointerCoords[] coordinates = result.second;
+ for (int i = 0; i < mFingers.size(); i++) {
+ int id = mFingers.keyAt(i);
+ PointF location = mFingers.get(id);
+ PointerProperties property = properties[i];
+ property.id = id;
+ property.toolType = 1;
+ properties[i] = property;
+ PointerCoords coordinate = coordinates[i];
+ coordinate.x = location.x;
+ coordinate.y = location.y;
+ coordinate.pressure = 1.0f;
+ coordinates[i] = coordinate;
+ }
+ return mCache.get(nFingers);
+ }
+}