diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2019-06-28 23:28:44 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2019-06-28 23:28:44 +0000 |
commit | 66b1cc96753fb078b879e2a05fcc1fc906106210 (patch) | |
tree | 8d5be0b3a17d39c5fe4d6a2e5e1ba13ffd315f3d | |
parent | 7d3c299a08e645fd9baa8816634c90a66107fe69 (diff) | |
parent | c4c8b3c69597ac5fdd0c29124cb1e5fb70873a55 (diff) | |
download | android_packages_apps_Trebuchet-66b1cc96753fb078b879e2a05fcc1fc906106210.tar.gz android_packages_apps_Trebuchet-66b1cc96753fb078b879e2a05fcc1fc906106210.tar.bz2 android_packages_apps_Trebuchet-66b1cc96753fb078b879e2a05fcc1fc906106210.zip |
Merge "Revert "Enable FLAG_SLIPPERY window flag when swipe down on workspace"" into ub-launcher3-qt-dev
-rw-r--r-- | quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java | 68 | ||||
-rw-r--r-- | src/com/android/launcher3/touch/TouchEventTranslator.java | 283 |
2 files changed, 300 insertions, 51 deletions
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java index f5ba3725d..fee18204e 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java @@ -17,22 +17,17 @@ package com.android.launcher3.uioverrides.touchcontrollers; import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_MOVE; -import static android.view.MotionEvent.ACTION_UP; -import static android.view.MotionEvent.ACTION_CANCEL; -import android.graphics.PointF; import android.os.RemoteException; import android.util.Log; -import android.util.SparseArray; import android.view.MotionEvent; import android.view.ViewConfiguration; -import android.view.Window; -import android.view.WindowManager; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; +import com.android.launcher3.touch.TouchEventTranslator; import com.android.launcher3.util.TouchController; import com.android.quickstep.RecentsModel; import com.android.systemui.shared.recents.ISystemUiProxy; @@ -41,29 +36,18 @@ import java.io.PrintWriter; /** * TouchController for handling touch events that get sent to the StatusBar. Once the - * Once the event delta mDownY passes the touch slop, the events start getting forwarded. + * Once the event delta y passes the touch slop, the events start getting forwarded. * All events are offset by initial Y value of the pointer. */ public class StatusBarTouchController implements TouchController { private static final String TAG = "StatusBarController"; - /** - * Window flag: Enable touches to slide out of a window into neighboring - * windows in mid-gesture instead of being captured for the duration of - * the gesture. - * - * This flag changes the behavior of touch focus for this window only. - * Touches can slide out of the window but they cannot necessarily slide - * back in (unless the other window with touch focus permits it). - */ - private static final int FLAG_SLIPPERY = 0x20000000; - protected final Launcher mLauncher; + protected final TouchEventTranslator mTranslator; private final float mTouchSlop; private ISystemUiProxy mSysUiProxy; private int mLastAction; - private final SparseArray<PointF> mDownEvents; /* If {@code false}, this controller should not handle the input {@link MotionEvent}.*/ private boolean mCanIntercept; @@ -72,7 +56,7 @@ public class StatusBarTouchController implements TouchController { mLauncher = l; // Guard against TAPs by increasing the touch slop. mTouchSlop = 2 * ViewConfiguration.get(l).getScaledTouchSlop(); - mDownEvents = new SparseArray<>(); + mTranslator = new TouchEventTranslator((MotionEvent ev)-> dispatchTouchEvent(ev)); } @Override @@ -80,6 +64,7 @@ public class StatusBarTouchController implements TouchController { writer.println(prefix + "mCanIntercept:" + mCanIntercept); writer.println(prefix + "mLastAction:" + MotionEvent.actionToString(mLastAction)); writer.println(prefix + "mSysUiProxy available:" + (mSysUiProxy != null)); + } private void dispatchTouchEvent(MotionEvent ev) { @@ -96,31 +81,26 @@ public class StatusBarTouchController implements TouchController { @Override public final boolean onControllerInterceptTouchEvent(MotionEvent ev) { int action = ev.getActionMasked(); - int idx = ev.getActionIndex(); - int pid = ev.getPointerId(idx); if (action == ACTION_DOWN) { mCanIntercept = canInterceptTouch(ev); if (!mCanIntercept) { return false; } - mDownEvents.put(pid, new PointF(ev.getX(), ev.getY())); + mTranslator.reset(); + mTranslator.setDownParameters(0, 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))); + // Check!! should only set it only when threshold is not entered. + mTranslator.setDownParameters(ev.getActionIndex(), ev); } if (!mCanIntercept) { return false; } if (action == ACTION_MOVE) { - float dy = ev.getY(idx) - mDownEvents.get(pid).y; - float dx = ev.getX(idx) - mDownEvents.get(pid).x; - // 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) - if (dy > mTouchSlop && dy > Math.abs(dx) && ev.getPointerCount() == 1) { - ev.setAction(ACTION_DOWN); - dispatchTouchEvent(ev); - setWindowSlippery(true); + 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; } if (Math.abs(dx) > mTouchSlop) { @@ -130,27 +110,13 @@ public class StatusBarTouchController implements TouchController { return false; } + @Override public final boolean onControllerTouchEvent(MotionEvent ev) { - if (ev.getAction() == ACTION_UP || ev.getAction() == ACTION_CANCEL) { - dispatchTouchEvent(ev); - setWindowSlippery(false); - return true; - } + mTranslator.processMotionEvent(ev); return true; } - private void setWindowSlippery(boolean enable) { - Window w = mLauncher.getWindow(); - WindowManager.LayoutParams wlp = w.getAttributes(); - if (enable) { - wlp.flags |= FLAG_SLIPPERY; - } else { - wlp.flags &= ~FLAG_SLIPPERY; - } - w.setAttributes(wlp); - } - private boolean canInterceptTouch(MotionEvent ev) { if (!mLauncher.isInState(LauncherState.NORMAL) || AbstractFloatingView.getTopOpenViewWithType(mLauncher, @@ -166,4 +132,4 @@ public class StatusBarTouchController implements TouchController { mSysUiProxy = RecentsModel.INSTANCE.get(mLauncher).getSystemUiProxy(); return mSysUiProxy != null; } -}
\ No newline at end of file +} diff --git a/src/com/android/launcher3/touch/TouchEventTranslator.java b/src/com/android/launcher3/touch/TouchEventTranslator.java new file mode 100644 index 000000000..3fcda9084 --- /dev/null +++ b/src/com/android/launcher3/touch/TouchEventTranslator.java @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2018 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 java.util.function.Consumer; + +/** + * To minimize the size of the MotionEvent, historic events are not copied and passed via the + * listener. + */ +public class TouchEventTranslator { + + private static final String TAG = "TouchEventTranslator"; + private static final boolean DEBUG = false; + + private class DownState { + long timeStamp; + float downX; + float downY; + public DownState(long timeStamp, float downX, float downY) { + this.timeStamp = timeStamp; + this.downX = downX; + this.downY = downY; + } + }; + private final DownState ZERO = new DownState(0, 0f, 0f); + + private final Consumer<MotionEvent> mListener; + + private final SparseArray<DownState> mDownEvents; + private final SparseArray<PointF> mFingers; + + private final SparseArray<Pair<PointerProperties[], PointerCoords[]>> mCache; + + public TouchEventTranslator(Consumer<MotionEvent> listener) { + mDownEvents = new SparseArray<>(); + mFingers = new SparseArray<>(); + mCache = new SparseArray<>(); + + 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) { + DownState ev = new DownState(e.getEventTime(), e.getX(idx), e.getY(idx)); + mDownEvents.append(idx, ev); + } + + public void dispatchDownEvents(MotionEvent ev) { + for(int i = 0; i < ev.getPointerCount() && i < mDownEvents.size(); i++) { + int pid = ev.getPointerId(i); + put(pid, i, ev.getX(i), 0, mDownEvents.get(i).timeStamp, ev); + } + } + + public void processMotionEvent(MotionEvent ev) { + if (DEBUG) { + printSamples(TAG + " processMotionEvent", ev); + } + int index = ev.getActionIndex(); + float x = ev.getX(index); + float y = ev.getY(index) - mDownEvents.get(index, ZERO).downY; + switch (ev.getActionMasked()) { + case MotionEvent.ACTION_POINTER_DOWN: + int pid = ev.getPointerId(index); + if(mFingers.get(pid, null) != null) { + for(int i=0; i < ev.getPointerCount(); i++) { + pid = ev.getPointerId(i); + position(pid, x, y); + } + generateEvent(ev.getAction(), ev); + } else { + put(pid, index, x, y, ev); + } + break; + case MotionEvent.ACTION_MOVE: + for(int i=0; i < ev.getPointerCount(); i++) { + pid = ev.getPointerId(i); + position(pid, x, y); + } + generateEvent(ev.getAction(), ev); + break; + case MotionEvent.ACTION_POINTER_UP: + case MotionEvent.ACTION_UP: + pid = ev.getPointerId(index); + lift(pid, index, x, y, ev); + break; + case MotionEvent.ACTION_CANCEL: + cancel(ev); + break; + default: + Log.v(TAG, "Didn't process "); + printSamples(TAG, 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) { + checkFingerExistence(id, false); + boolean isInitialDown = (mFingers.size() == 0); + + 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)); + } + + int action; + if (isInitialDown) { + action = MotionEvent.ACTION_DOWN; + } else { + action = MotionEvent.ACTION_POINTER_DOWN; + // Set the id of the changed pointer. + action |= 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) { + checkFingerExistence(id, true); + boolean isFinalUp = (mFingers.size() == 1); + int action; + if (isFinalUp) { + action = MotionEvent.ACTION_UP; + } else { + action = MotionEvent.ACTION_POINTER_UP; + // Set the id of the changed pointer. + action |= 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"); + } + } + + + /** + * Used to debug MotionEvents being sent/received. + */ + public void printSamples(String msg, MotionEvent ev) { + System.out.printf("%s %s", msg, MotionEvent.actionToString(ev.getActionMasked())); + final int pointerCount = ev.getPointerCount(); + System.out.printf("#%d/%d", ev.getActionIndex(), pointerCount); + System.out.printf(" t=%d:", ev.getEventTime()); + for (int p = 0; p < pointerCount; p++) { + System.out.printf(" id=%d: (%f,%f)", + ev.getPointerId(p), ev.getX(p), ev.getY(p)); + } + System.out.println(); + } + + 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() /* buttonState */, + ev.getXPrecision() /* xPrecision */, + ev.getYPrecision() /* yPrecision */, + ev.getDeviceId(), + ev.getEdgeFlags(), + ev.getSource(), + ev.getFlags() /* flags */); + if (DEBUG) { + printSamples(TAG + " generateEvent", event); + } + if (event.getPointerId(event.getActionIndex()) < 0) { + printSamples(TAG + "generateEvent", event); + throw new IllegalStateException(event.getActionIndex() + " not found in MotionEvent"); + } + mListener.accept(event); + event.recycle(); + } + + /** + * Returns the description of the fingers' state expected by 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; + + int index = 0; + 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 = MotionEvent.TOOL_TYPE_FINGER; + properties[index] = property; + + PointerCoords coordinate = coordinates[i]; + coordinate.x = location.x; + coordinate.y = location.y; + coordinate.pressure = 1.0f; + coordinates[index] = coordinate; + + index++; + } + return mCache.get(nFingers); + } +} |