summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSunny Goyal <sunnygoyal@google.com>2019-06-24 16:01:13 -0700
committerSunny Goyal <sunnygoyal@google.com>2019-06-25 13:25:30 -0700
commit700dc99d9b3d7df7e1910fa5661d60714a7f6a0d (patch)
tree46153ce762cfe17853aafbc4495ddbca3a85ea6e
parenta90531cd00ad64fb8501c8190f99e068f9d581d6 (diff)
downloadandroid_packages_apps_Trebuchet-700dc99d9b3d7df7e1910fa5661d60714a7f6a0d.tar.gz
android_packages_apps_Trebuchet-700dc99d9b3d7df7e1910fa5661d60714a7f6a0d.tar.bz2
android_packages_apps_Trebuchet-700dc99d9b3d7df7e1910fa5661d60714a7f6a0d.zip
Enabling simple gesture navigation for 3P launcher
In case of 3P launcher, swipe-up will go to Launcher and there will be no way to reach overview. Bug: 135769778 Change-Id: Ib2c6bb1b13e6055d30b7360ec077b0a2fece66ff
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java5
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java358
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java2
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java2
-rw-r--r--quickstep/src/com/android/quickstep/OverviewComponentObserver.java27
5 files changed, 392 insertions, 2 deletions
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index 22ebe6140..8f08f0de9 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -81,6 +81,7 @@ import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
import com.android.quickstep.inputconsumers.AssistantTouchConsumer;
import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer;
+import com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer;
import com.android.quickstep.inputconsumers.InputConsumer;
import com.android.quickstep.inputconsumers.OtherActivityInputConsumer;
import com.android.quickstep.inputconsumers.OverviewInputConsumer;
@@ -614,6 +615,10 @@ public class TouchInteractionService extends Service implements
} else if (mGestureBlockingActivity != null && runningTaskInfo != null
&& mGestureBlockingActivity.equals(runningTaskInfo.topActivity)) {
return mResetGestureInputConsumer;
+ } else if (mMode == Mode.NO_BUTTON && !mOverviewComponentObserver.isHomeAndOverviewSame()) {
+ return new FallbackNoButtonInputConsumer(this, activityControl,
+ mInputMonitorCompat, mSwipeSharedState, mSwipeTouchRegion,
+ mOverviewComponentObserver, disableHorizontalSwipe(event), runningTaskInfo);
} else {
return createOtherActivityInputConsumer(event, runningTaskInfo);
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java
new file mode 100644
index 000000000..d05ca2a16
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2019 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.quickstep.inputconsumers;
+
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_POINTER_DOWN;
+import static android.view.MotionEvent.ACTION_POINTER_UP;
+import static android.view.MotionEvent.ACTION_UP;
+import static android.view.MotionEvent.INVALID_POINTER_ID;
+
+import static com.android.quickstep.WindowTransformSwipeHandler.MAX_SWIPE_DURATION;
+import static com.android.quickstep.WindowTransformSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW;
+import static com.android.quickstep.WindowTransformSwipeHandler.MIN_SWIPE_DURATION;
+import static com.android.quickstep.inputconsumers.OtherActivityInputConsumer.QUICKSTEP_TOUCH_SLOP_RATIO;
+import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.ViewConfiguration;
+import android.view.WindowManager;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.R;
+import com.android.quickstep.ActivityControlHelper;
+import com.android.quickstep.OverviewComponentObserver;
+import com.android.quickstep.SwipeSharedState;
+import com.android.quickstep.util.ClipAnimationHelper;
+import com.android.quickstep.util.ClipAnimationHelper.TransformParams;
+import com.android.quickstep.util.NavBarPosition;
+import com.android.quickstep.util.RecentsAnimationListenerSet;
+import com.android.quickstep.util.SwipeAnimationTargetSet;
+import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.BackgroundExecutor;
+import com.android.systemui.shared.system.InputMonitorCompat;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+
+public class FallbackNoButtonInputConsumer implements InputConsumer, SwipeAnimationListener {
+
+ private static final int STATE_NOT_FINISHED = 0;
+ private static final int STATE_FINISHED_TO_HOME = 1;
+ private static final int STATE_FINISHED_TO_APP = 2;
+
+ private static final float PROGRESS_TO_END_GESTURE = -2;
+
+ private final ActivityControlHelper mActivityControlHelper;
+ private final InputMonitorCompat mInputMonitor;
+ private final Context mContext;
+ private final NavBarPosition mNavBarPosition;
+ private final SwipeSharedState mSwipeSharedState;
+ private final OverviewComponentObserver mOverviewComponentObserver;
+ private final int mRunningTaskId;
+
+ private final ClipAnimationHelper mClipAnimationHelper;
+ private final TransformParams mTransformParams = new TransformParams();
+ private final float mTransitionDragLength;
+ private final DeviceProfile mDP;
+
+ private final RectF mSwipeTouchRegion;
+ private final boolean mDisableHorizontalSwipe;
+
+ private final PointF mDownPos = new PointF();
+ private final PointF mLastPos = new PointF();
+
+ private int mActivePointerId = -1;
+ // Slop used to determine when we say that the gesture has started.
+ private boolean mPassedPilferInputSlop;
+
+ private VelocityTracker mVelocityTracker;
+
+ // Distance after which we start dragging the window.
+ private final float mTouchSlop;
+
+ // Might be displacement in X or Y, depending on the direction we are swiping from the nav bar.
+ private float mStartDisplacement;
+ private SwipeAnimationTargetSet mSwipeAnimationTargetSet;
+ private float mProgress;
+
+ private int mState = STATE_NOT_FINISHED;
+
+ public FallbackNoButtonInputConsumer(Context context,
+ ActivityControlHelper activityControlHelper, InputMonitorCompat inputMonitor,
+ SwipeSharedState swipeSharedState, RectF swipeTouchRegion,
+ OverviewComponentObserver overviewComponentObserver,
+ boolean disableHorizontalSwipe, RunningTaskInfo runningTaskInfo) {
+ mContext = context;
+ mActivityControlHelper = activityControlHelper;
+ mInputMonitor = inputMonitor;
+ mOverviewComponentObserver = overviewComponentObserver;
+ mRunningTaskId = runningTaskInfo.id;
+
+ mSwipeSharedState = swipeSharedState;
+ mSwipeTouchRegion = swipeTouchRegion;
+ mDisableHorizontalSwipe = disableHorizontalSwipe;
+
+ mNavBarPosition = new NavBarPosition(context);
+ mVelocityTracker = VelocityTracker.obtain();
+
+ mTouchSlop = QUICKSTEP_TOUCH_SLOP_RATIO
+ * ViewConfiguration.get(context).getScaledTouchSlop();
+
+ mClipAnimationHelper = new ClipAnimationHelper(context);
+
+ mDP = InvariantDeviceProfile.INSTANCE.get(context).getDeviceProfile(context).copy(context);
+ Rect tempRect = new Rect();
+ mTransitionDragLength = mActivityControlHelper.getSwipeUpDestinationAndLength(
+ mDP, context, tempRect);
+ mClipAnimationHelper.updateTargetRect(tempRect);
+ }
+
+ @Override
+ public int getType() {
+ return TYPE_FALLBACK_NO_BUTTON;
+ }
+
+ @Override
+ public void onMotionEvent(MotionEvent ev) {
+ if (mVelocityTracker == null) {
+ return;
+ }
+
+ mVelocityTracker.addMovement(ev);
+ if (ev.getActionMasked() == ACTION_POINTER_UP) {
+ mVelocityTracker.clear();
+ }
+
+ switch (ev.getActionMasked()) {
+ case ACTION_DOWN: {
+ mActivePointerId = ev.getPointerId(0);
+ mDownPos.set(ev.getX(), ev.getY());
+ mLastPos.set(mDownPos);
+ break;
+ }
+ case ACTION_POINTER_DOWN: {
+ if (!mPassedPilferInputSlop) {
+ // Cancel interaction in case of multi-touch interaction
+ int ptrIdx = ev.getActionIndex();
+ if (!mSwipeTouchRegion.contains(ev.getX(ptrIdx), ev.getY(ptrIdx))) {
+ forceCancelGesture(ev);
+ }
+ }
+ break;
+ }
+ case ACTION_POINTER_UP: {
+ int ptrIdx = ev.getActionIndex();
+ int ptrId = ev.getPointerId(ptrIdx);
+ if (ptrId == mActivePointerId) {
+ final int newPointerIdx = ptrIdx == 0 ? 1 : 0;
+ mDownPos.set(
+ ev.getX(newPointerIdx) - (mLastPos.x - mDownPos.x),
+ ev.getY(newPointerIdx) - (mLastPos.y - mDownPos.y));
+ mLastPos.set(ev.getX(newPointerIdx), ev.getY(newPointerIdx));
+ mActivePointerId = ev.getPointerId(newPointerIdx);
+ }
+ break;
+ }
+ case ACTION_MOVE: {
+ int pointerIndex = ev.findPointerIndex(mActivePointerId);
+ if (pointerIndex == INVALID_POINTER_ID) {
+ break;
+ }
+ mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
+ float displacement = getDisplacement(ev);
+
+ if (!mPassedPilferInputSlop) {
+ if (mDisableHorizontalSwipe && Math.abs(mLastPos.x - mDownPos.x)
+ > Math.abs(mLastPos.y - mDownPos.y)) {
+ // Horizontal gesture is not allowed in this region
+ forceCancelGesture(ev);
+ break;
+ }
+
+ if (Math.abs(displacement) >= mTouchSlop) {
+ mPassedPilferInputSlop = true;
+
+ // Deferred gesture, start the animation and gesture tracking once
+ // we pass the actual touch slop
+ startTouchTrackingForWindowAnimation(displacement);
+ }
+ } else {
+ updateDisplacement(displacement - mStartDisplacement);
+ }
+ break;
+ }
+ case ACTION_CANCEL:
+ case ACTION_UP: {
+ finishTouchTracking(ev);
+ break;
+ }
+ }
+ }
+
+ private void startTouchTrackingForWindowAnimation(float displacement) {
+ mStartDisplacement = Math.min(displacement, -mTouchSlop);
+
+ RecentsAnimationListenerSet listenerSet =
+ mSwipeSharedState.newRecentsAnimationListenerSet();
+ listenerSet.addListener(this);
+ Intent homeIntent = mOverviewComponentObserver.getHomeIntent();
+ BackgroundExecutor.get().submit(
+ () -> ActivityManagerWrapper.getInstance().startRecentsActivity(
+ homeIntent, null, listenerSet, null, null));
+
+ ActivityManagerWrapper.getInstance().closeSystemWindows(
+ CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
+ mInputMonitor.pilferPointers();
+ }
+
+ private void updateDisplacement(float displacement) {
+ mProgress = displacement / mTransitionDragLength;
+ mTransformParams.setProgress(mProgress);
+
+ if (mSwipeAnimationTargetSet != null) {
+ mClipAnimationHelper.applyTransform(mSwipeAnimationTargetSet, mTransformParams);
+ }
+ }
+
+ private void forceCancelGesture(MotionEvent ev) {
+ int action = ev.getAction();
+ ev.setAction(ACTION_CANCEL);
+ finishTouchTracking(ev);
+ ev.setAction(action);
+ }
+
+ /**
+ * Called when the gesture has ended. Does not correlate to the completion of the interaction as
+ * the animation can still be running.
+ */
+ private void finishTouchTracking(MotionEvent ev) {
+ if (ev.getAction() == ACTION_CANCEL) {
+ mState = STATE_FINISHED_TO_APP;
+ } else {
+ mVelocityTracker.computeCurrentVelocity(1000,
+ ViewConfiguration.get(mContext).getScaledMaximumFlingVelocity());
+ float velocityX = mVelocityTracker.getXVelocity(mActivePointerId);
+ float velocityY = mVelocityTracker.getYVelocity(mActivePointerId);
+ float velocity = mNavBarPosition.isRightEdge() ? velocityX
+ : mNavBarPosition.isLeftEdge() ? -velocityX
+ : velocityY;
+ float flingThreshold = mContext.getResources()
+ .getDimension(R.dimen.quickstep_fling_threshold_velocity);
+ boolean isFling = Math.abs(velocity) > flingThreshold;
+
+ boolean goingHome;
+ if (!isFling) {
+ goingHome = -mProgress >= MIN_PROGRESS_FOR_OVERVIEW;
+ } else {
+ goingHome = velocity < 0;
+ }
+
+ if (goingHome) {
+ mState = STATE_FINISHED_TO_HOME;
+ } else {
+ mState = STATE_FINISHED_TO_APP;
+ }
+ }
+
+ if (mSwipeAnimationTargetSet != null) {
+ finishAnimationTargetSet();
+ }
+ }
+
+ private void finishAnimationTargetSet() {
+ if (mState == STATE_FINISHED_TO_APP) {
+ mSwipeAnimationTargetSet.finishController(false, null, false);
+ } else {
+ if (mProgress < PROGRESS_TO_END_GESTURE) {
+ mSwipeAnimationTargetSet.finishController(true, null, true);
+ } else {
+ long duration = (long) (Math.min(mProgress - PROGRESS_TO_END_GESTURE, 1)
+ * MAX_SWIPE_DURATION / Math.abs(PROGRESS_TO_END_GESTURE));
+ if (duration < 0) {
+ duration = MIN_SWIPE_DURATION;
+ }
+
+ ValueAnimator anim = ValueAnimator.ofFloat(mProgress, PROGRESS_TO_END_GESTURE);
+ anim.addUpdateListener(a -> {
+ float p = (Float) anim.getAnimatedValue();
+ mTransformParams.setProgress(p);
+ mClipAnimationHelper.applyTransform(mSwipeAnimationTargetSet, mTransformParams);
+ });
+ anim.setDuration(duration);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mSwipeAnimationTargetSet.finishController(true, null, true);
+ }
+ });
+ anim.start();
+ }
+ }
+ }
+
+ @Override
+ public void onRecentsAnimationStart(SwipeAnimationTargetSet targetSet) {
+ mSwipeAnimationTargetSet = targetSet;
+ Rect overviewStackBounds = new Rect(0, 0, mDP.widthPx, mDP.heightPx);
+ RemoteAnimationTargetCompat runningTaskTarget = targetSet.findTask(mRunningTaskId);
+
+ mDP.updateIsSeascape(mContext.getSystemService(WindowManager.class));
+ if (runningTaskTarget != null) {
+ mClipAnimationHelper.updateSource(overviewStackBounds, runningTaskTarget);
+ }
+ mClipAnimationHelper.prepareAnimation(mDP, false /* isOpening */);
+
+ overviewStackBounds
+ .inset(-overviewStackBounds.width() / 5, -overviewStackBounds.height() / 5);
+ mClipAnimationHelper.updateTargetRect(overviewStackBounds);
+ mClipAnimationHelper.applyTransform(mSwipeAnimationTargetSet, mTransformParams);
+
+ if (mState != STATE_NOT_FINISHED) {
+ finishAnimationTargetSet();
+ }
+ }
+
+ @Override
+ public void onRecentsAnimationCanceled() { }
+
+ private float getDisplacement(MotionEvent ev) {
+ if (mNavBarPosition.isRightEdge()) {
+ return ev.getX() - mDownPos.x;
+ } else if (mNavBarPosition.isLeftEdge()) {
+ return mDownPos.x - ev.getX();
+ } else {
+ return ev.getY() - mDownPos.y;
+ }
+ }
+
+ @Override
+ public boolean allowInterceptByParent() {
+ return !mPassedPilferInputSlop;
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java
index a1e5d47a5..f5cf654b1 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java
@@ -33,6 +33,7 @@ public interface InputConsumer {
int TYPE_SCREEN_PINNED = 1 << 6;
int TYPE_OVERVIEW_WITHOUT_FOCUS = 1 << 7;
int TYPE_RESET_GESTURE = 1 << 8;
+ int TYPE_FALLBACK_NO_BUTTON = 1 << 9;
String[] NAMES = new String[] {
"TYPE_NO_OP", // 0
@@ -44,6 +45,7 @@ public interface InputConsumer {
"TYPE_SCREEN_PINNED", // 6
"TYPE_OVERVIEW_WITHOUT_FOCUS", // 7
"TYPE_RESET_GESTURE", // 8
+ "TYPE_FALLBACK_NO_BUTTON", // 9
};
InputConsumer NO_OP = () -> TYPE_NO_OP;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 6bc543f07..4c137d3bf 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -79,7 +79,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
private static final String UP_EVT = "OtherActivityInputConsumer.UP";
// TODO: Move to quickstep contract
- private static final float QUICKSTEP_TOUCH_SLOP_RATIO = 3;
+ public static final float QUICKSTEP_TOUCH_SLOP_RATIO = 3;
private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher();
private final RunningTaskInfo mRunningTask;
diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
index 0a73b8b19..0738affa9 100644
--- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
+++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
@@ -33,7 +33,6 @@ import android.content.pm.ResolveInfo;
import com.android.systemui.shared.system.PackageManagerWrapper;
-import com.android.systemui.shared.system.QuickStepContract;
import java.util.ArrayList;
/**
@@ -58,7 +57,9 @@ public final class OverviewComponentObserver {
private String mUpdateRegisteredPackage;
private ActivityControlHelper mActivityControlHelper;
private Intent mOverviewIntent;
+ private Intent mHomeIntent;
private int mSystemUiStateFlags;
+ private boolean mIsHomeAndOverviewSame;
public OverviewComponentObserver(Context context) {
mContext = context;
@@ -93,11 +94,14 @@ public final class OverviewComponentObserver {
final String overviewIntentCategory;
ComponentName overviewComponent;
+ mHomeIntent = null;
+
if ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0 &&
(defaultHome == null || mMyHomeComponent.equals(defaultHome))) {
// User default home is same as out home app. Use Overview integrated in Launcher.
overviewComponent = mMyHomeComponent;
mActivityControlHelper = new LauncherActivityControllerHelper();
+ mIsHomeAndOverviewSame = true;
overviewIntentCategory = Intent.CATEGORY_HOME;
if (mUpdateRegisteredPackage != null) {
@@ -109,8 +113,12 @@ public final class OverviewComponentObserver {
// The default home app is a different launcher. Use the fallback Overview instead.
overviewComponent = new ComponentName(mContext, RecentsActivity.class);
mActivityControlHelper = new FallbackActivityControllerHelper();
+ mIsHomeAndOverviewSame = false;
overviewIntentCategory = Intent.CATEGORY_DEFAULT;
+ mHomeIntent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME)
+ .setComponent(defaultHome);
// User's default home app can change as a result of package updates of this app (such
// as uninstalling the app or removing the "Launcher" feature in an update).
// Listen for package updates of this app (and remove any previously attached
@@ -135,6 +143,9 @@ public final class OverviewComponentObserver {
.addCategory(overviewIntentCategory)
.setComponent(overviewComponent)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ if (mHomeIntent == null) {
+ mHomeIntent = mOverviewIntent;
+ }
}
/**
@@ -159,6 +170,20 @@ public final class OverviewComponentObserver {
}
/**
+ * Get the current intent for going to the home activity.
+ */
+ public Intent getHomeIntent() {
+ return mHomeIntent;
+ }
+
+ /**
+ * Returns true if home and overview are same activity.
+ */
+ public boolean isHomeAndOverviewSame() {
+ return mIsHomeAndOverviewSame;
+ }
+
+ /**
* Get the current activity control helper for managing interactions to the overview activity.
*
* @return the current activity control helper