summaryrefslogtreecommitdiffstats
path: root/quickstep/recents_ui_overrides/src/com/android/quickstep
diff options
context:
space:
mode:
authorWinson Chung <winsonc@google.com>2019-06-26 18:33:32 -0700
committerWinson Chung <winsonc@google.com>2019-06-26 18:36:10 -0700
commit5cd4333b5c62b249d3f0b52020864bb9598f92c9 (patch)
treefc4c828efc9854fa46dc60117dcfa7364b578542 /quickstep/recents_ui_overrides/src/com/android/quickstep
parent5ce8c9f73bec627dc74121c868ee73bda51073b5 (diff)
parent1703eb8b88d1557696b13f6dbbd1db2c15a5993c (diff)
downloadandroid_packages_apps_Trebuchet-5cd4333b5c62b249d3f0b52020864bb9598f92c9.tar.gz
android_packages_apps_Trebuchet-5cd4333b5c62b249d3f0b52020864bb9598f92c9.tar.bz2
android_packages_apps_Trebuchet-5cd4333b5c62b249d3f0b52020864bb9598f92c9.zip
Merging ub-launcher3-qt-dev, build 5691374
Test: Manual Bug:115582915 P2 [Testing] Make all launcher tests gesture-stable Bug:121280703 P2 Finish implementation of PortraitLandscape annotation for tests Bug:124524897 P2 Enable some tests in OOP mode Bug:129158983 P1 Badge bubbles with app icon; use launcher lib for icon, dot, badge rendering Bug:131116002 P2 Convert tests to TAPL and enable them Bug:131356741 P1 use transferFocus to implement SWIPE DOWN on homescreen to open noti shade Bug:131360075 P1 [Gesture Nav] Polish/finish landscape Bug:132309376 P1 Launcher held ION buffers after clearing all apps in Recent Apps Bug:132455160 P1 [Gesture Nav] Home to Overview Transition Improvement Bug:132461400 P1 Fatal exceptions in Launcher3 Bug:132811175 P1 Jump cut if you quickly open an app after going home Bug:133450867 P1 App window draws outside of icon shape during app to home transition Bug:133765434 P1 [Flaky test] Launching task didn't open a new window Bug:133867119 P2 Lab-only flake: want to switch from workspace to all apps; Swipe failed to receive an event for the swipe end Bug:134609899 P1 Overscrolling on all apps leads to a wrong current task Bug:135011207 P0 Corner Invocation / Inconsistent - F/C Bug:135150619 P1 [Launcher] Trigger heapdump on RSS HWM measurements Bug:135150767 P4 [Launcher] Test reduced resolution snapshots Bug:135161289 P2 KB3 on qt-dev can't pick Launcher3GoIconRecents from vendor Makefile Bug:135222111 P1 Major issues with hotseat when predictions are disabled Bug:135287203 P1 Overview crashes on rotation Bug:135299165 P1 Configuration changes might result in Launcher ending up in a corrupt state Bug:135472635 P2 Bad overriden class: java.lang.ClassNotFoundException: com.android.quickstep.QuickstepProcessInitializer Bug:135473571 P0 Pixel launcher keeps stopping in SuW Bug:135571566 P4 Search bar is above icons. Even opening and closing launcher does not help Bug:135686388 P1 Quickswitch sometimes jump Bug:135687556 P1 Increase assistant gesture touch region on new devices Bug:135766310 P2 Concerns over config changes during state transitions #2 Bug:135769778 P1 "System navigation changed" notification is shown during P4 setup
Diffstat (limited to 'quickstep/recents_ui_overrides/src/com/android/quickstep')
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java95
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepProcessInitializer.java54
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java5
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java12
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java8
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java80
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java86
-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/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java2
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java10
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java4
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java14
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java28
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java5
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java6
17 files changed, 560 insertions, 211 deletions
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
index 0d06c19ab..07c049642 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
@@ -18,12 +18,13 @@ package com.android.quickstep;
import static android.view.View.TRANSLATION_Y;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_RECENTS_FADE_ANIM;
+import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_RECENTS_TRANSLATE_X_ANIM;
+import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_SHELF_ANIM;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherStateManager.ANIM_ALL;
-import static com.android.launcher3.allapps.AllAppsTransitionController.SPRING_DAMPING_RATIO;
-import static com.android.launcher3.allapps.AllAppsTransitionController.SPRING_STIFFNESS;
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.launcher3.anim.Interpolators.INSTANT;
@@ -31,7 +32,6 @@ import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.WindowTransformSwipeHandler.RECENTS_ATTACH_DURATION;
import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
@@ -48,8 +48,6 @@ import android.view.animation.Interpolator;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
-import androidx.dynamicanimation.animation.SpringAnimation;
-import androidx.dynamicanimation.animation.SpringForce;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
@@ -60,13 +58,14 @@ import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
-import com.android.launcher3.anim.SpringObjectAnimator;
import com.android.launcher3.testing.TestProtocol;
+import com.android.launcher3.uioverrides.states.OverviewState;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.views.FloatingIconView;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
+import com.android.quickstep.views.LauncherRecentsView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -216,10 +215,7 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
activity.getAppsView().getContentView().setVisibility(View.GONE);
return new AnimationFactory() {
- private Animator mShelfAnim;
private ShelfAnimState mShelfState;
- private Animator mAttachToWindowFadeAnim;
- private SpringAnimation mAttachToWindowTranslationXAnim;
private boolean mIsAttachedToWindow;
@Override
@@ -252,31 +248,26 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
return;
}
mShelfState = shelfState;
- if (mShelfAnim != null) {
- mShelfAnim.cancel();
- }
+ activity.getStateManager().cancelStateElementAnimation(INDEX_SHELF_ANIM);
if (mShelfState == ShelfAnimState.CANCEL) {
return;
}
float shelfHiddenProgress = BACKGROUND_APP.getVerticalProgress(activity);
float shelfOverviewProgress = OVERVIEW.getVerticalProgress(activity);
+ // Peek based on default overview progress so we can see hotseat if we're showing
+ // that instead of predictions in overview.
+ float defaultOverviewProgress = OverviewState.getDefaultVerticalProgress(activity);
float shelfPeekingProgress = shelfHiddenProgress
- - (shelfHiddenProgress - shelfOverviewProgress) * 0.25f;
+ - (shelfHiddenProgress - defaultOverviewProgress) * 0.25f;
float toProgress = mShelfState == ShelfAnimState.HIDE
? shelfHiddenProgress
: mShelfState == ShelfAnimState.PEEK
? shelfPeekingProgress
: shelfOverviewProgress;
- mShelfAnim = createShelfAnim(activity, toProgress);
- mShelfAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mShelfAnim = null;
- }
- });
- mShelfAnim.setInterpolator(interpolator);
- mShelfAnim.setDuration(duration);
- mShelfAnim.start();
+ Animator shelfAnim = activity.getStateManager()
+ .createStateElementAnimation(INDEX_SHELF_ANIM, toProgress);
+ shelfAnim.setInterpolator(interpolator);
+ shelfAnim.setDuration(duration).start();
}
@Override
@@ -285,12 +276,10 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
return;
}
mIsAttachedToWindow = attached;
- if (mAttachToWindowFadeAnim != null) {
- mAttachToWindowFadeAnim.cancel();
- }
- RecentsView recentsView = activity.getOverviewPanel();
- mAttachToWindowFadeAnim = ObjectAnimator.ofFloat(recentsView,
- RecentsView.CONTENT_ALPHA, attached ? 1 : 0);
+ LauncherRecentsView recentsView = activity.getOverviewPanel();
+ Animator fadeAnim = activity.getStateManager()
+ .createStateElementAnimation(
+ INDEX_RECENTS_FADE_ANIM, attached ? 1 : 0);
int runningTaskIndex = recentsView.getRunningTaskIndex();
if (runningTaskIndex == 0) {
@@ -312,33 +301,28 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
float fromTranslationX = attached ? offscreenX - scrollOffsetX : 0;
float toTranslationX = attached ? 0 : offscreenX - scrollOffsetX;
- if (mAttachToWindowTranslationXAnim == null) {
- mAttachToWindowTranslationXAnim = new SpringAnimation(recentsView,
- SpringAnimation.TRANSLATION_X).setSpring(new SpringForce()
- .setDampingRatio(0.8f)
- .setStiffness(250));
- }
+ activity.getStateManager()
+ .cancelStateElementAnimation(INDEX_RECENTS_TRANSLATE_X_ANIM);
+
if (!recentsView.isShown() && animate) {
recentsView.setTranslationX(fromTranslationX);
- mAttachToWindowTranslationXAnim.setStartValue(fromTranslationX);
+ } else {
+ fromTranslationX = recentsView.getTranslationX();
}
- mAttachToWindowTranslationXAnim.animateToFinalPosition(toTranslationX);
- if (!animate && mAttachToWindowTranslationXAnim.canSkipToEnd()) {
- mAttachToWindowTranslationXAnim.skipToEnd();
+
+ if (!animate) {
+ recentsView.setTranslationX(toTranslationX);
+ } else {
+ activity.getStateManager().createStateElementAnimation(
+ INDEX_RECENTS_TRANSLATE_X_ANIM,
+ fromTranslationX, toTranslationX).start();
}
- mAttachToWindowFadeAnim.setInterpolator(attached ? INSTANT : ACCEL_2);
+ fadeAnim.setInterpolator(attached ? INSTANT : ACCEL_2);
} else {
- mAttachToWindowFadeAnim.setInterpolator(ACCEL_DEACCEL);
+ fadeAnim.setInterpolator(ACCEL_DEACCEL);
}
- mAttachToWindowFadeAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mAttachToWindowFadeAnim = null;
- }
- });
- mAttachToWindowFadeAnim.setDuration(animate ? RECENTS_ATTACH_DURATION : 0);
- mAttachToWindowFadeAnim.start();
+ fadeAnim.setDuration(animate ? RECENTS_ATTACH_DURATION : 0).start();
}
};
}
@@ -354,10 +338,10 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
if (!activity.getDeviceProfile().isVerticalBarLayout()
&& SysUINavigationMode.getMode(activity) != Mode.NO_BUTTON) {
// Don't animate the shelf when the mode is NO_BUTTON, because we update it atomically.
- Animator shiftAnim = createShelfAnim(activity,
+ anim.play(activity.getStateManager().createStateElementAnimation(
+ INDEX_SHELF_ANIM,
fromState.getVerticalProgress(activity),
- endState.getVerticalProgress(activity));
- anim.play(shiftAnim);
+ endState.getVerticalProgress(activity)));
}
playScaleDownAnim(anim, activity, fromState, endState);
@@ -375,13 +359,6 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
callback.accept(controller);
}
- private Animator createShelfAnim(Launcher activity, float ... progressValues) {
- Animator shiftAnim = new SpringObjectAnimator<>(activity.getAllAppsController(),
- "allAppsSpringFromACH", activity.getAllAppsController().getShiftRange(),
- SPRING_DAMPING_RATIO, SPRING_STIFFNESS, progressValues);
- return shiftAnim;
- }
-
/**
* Scale down recents from the center task being full screen to being in overview.
*/
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepProcessInitializer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepProcessInitializer.java
deleted file mode 100644
index befeee0db..000000000
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepProcessInitializer.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.quickstep;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.UserManager;
-import android.util.Log;
-
-import com.android.launcher3.BuildConfig;
-import com.android.launcher3.MainProcessInitializer;
-import com.android.systemui.shared.system.ThreadedRendererCompat;
-
-@SuppressWarnings("unused")
-public class QuickstepProcessInitializer extends MainProcessInitializer {
-
- private static final String TAG = "QuickstepProcessInitializer";
-
- public QuickstepProcessInitializer(Context context) { }
-
- @Override
- protected void init(Context context) {
- // Workaround for b/120550382, an external app can cause the launcher process to start for
- // a work profile user which we do not support. Disable the application immediately when we
- // detect this to be the case.
- UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
- if (um.isManagedProfile()) {
- PackageManager pm = context.getPackageManager();
- pm.setApplicationEnabledSetting(context.getPackageName(),
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0 /* flags */);
- Log.w(TAG, "Disabling " + BuildConfig.APPLICATION_ID
- + ", unable to run in a managed profile");
- return;
- }
-
- super.init(context);
-
- // Elevate GPU priority for Quickstep and Remote animations.
- ThreadedRendererCompat.setContextPriority(ThreadedRendererCompat.EGL_CONTEXT_PRIORITY_HIGH_IMG);
- }
-}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java
index 5eecf1713..ddd28a350 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java
@@ -19,6 +19,8 @@ import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;
+import static com.android.launcher3.Utilities.FLAG_NO_GESTURES;
+
import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -182,7 +184,10 @@ public class RecentsAnimationWrapper {
}
}
if (mInputConsumer != null) {
+ int flags = ev.getEdgeFlags();
+ ev.setEdgeFlags(flags | FLAG_NO_GESTURES);
mInputConsumer.onMotionEvent(ev);
+ ev.setEdgeFlags(flags);
}
return true;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java
index 6689ce3d7..c55f656df 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java
@@ -72,13 +72,15 @@ public class SwipeSharedState implements SwipeAnimationListener {
mLastAnimationRunning = false;
}
- private void clearListenerState() {
+ private void clearListenerState(boolean finishAnimation) {
if (mRecentsAnimationListener != null) {
mRecentsAnimationListener.removeListener(this);
mRecentsAnimationListener.cancelListener();
if (mLastAnimationRunning && mLastAnimationTarget != null) {
Utilities.postAsyncCallback(MAIN_THREAD_EXECUTOR.getHandler(),
- mLastAnimationTarget::cancelAnimation);
+ finishAnimation
+ ? mLastAnimationTarget::finishAnimation
+ : mLastAnimationTarget::cancelAnimation);
mLastAnimationTarget = null;
}
}
@@ -106,7 +108,7 @@ public class SwipeSharedState implements SwipeAnimationListener {
}
}
- clearListenerState();
+ clearListenerState(false /* finishAnimation */);
boolean shouldMinimiseSplitScreen = mOverviewComponentObserver == null ? false
: mOverviewComponentObserver.getActivityControlHelper().shouldMinimizeSplitScreen();
mRecentsAnimationListener = new RecentsAnimationListenerSet(
@@ -138,8 +140,8 @@ public class SwipeSharedState implements SwipeAnimationListener {
mLastAnimationTarget = mLastAnimationTarget.cloneWithoutTargets();
}
- public void clearAllState() {
- clearListenerState();
+ public void clearAllState(boolean finishAnimation) {
+ clearListenerState(finishAnimation);
canGestureBeContinued = false;
recentsAnimationFinishInterrupted = false;
nextRunningTaskId = -1;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
index d0ea73a6f..6897c1e7d 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
@@ -29,8 +29,6 @@ import android.view.View;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.ItemInfo;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppState;
import com.android.launcher3.Utilities;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.util.MultiValueUpdateListener;
@@ -123,6 +121,7 @@ public final class TaskViewUtils {
new RemoteAnimationTargetSet(targets, MODE_OPENING);
targetSet.addDependentTransactionApplier(applier);
+ final RecentsView recentsView = v.getRecentsView();
final ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
appAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
appAnimator.addUpdateListener(new MultiValueUpdateListener() {
@@ -153,7 +152,10 @@ public final class TaskViewUtils {
// TODO: Take into account the current fullscreen progress for animating the insets
params.setProgress(1 - percent);
RectF taskBounds = inOutHelper.applyTransform(targetSet, params);
- if (!skipViewChanges) {
+ int taskIndex = recentsView.indexOfChild(v);
+ int centerTaskIndex = recentsView.getCurrentPage();
+ boolean parallaxCenterAndAdjacentTask = taskIndex != centerTaskIndex;
+ if (!skipViewChanges && parallaxCenterAndAdjacentTask) {
float scale = taskBounds.width() / mThumbnailRect.width();
v.setScaleX(scale);
v.setScaleY(scale);
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 769d207ab..53da0f92d 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;
@@ -224,14 +225,18 @@ public class TouchInteractionService extends Service implements
};
private static boolean sConnected = false;
+ private static final SwipeSharedState sSwipeSharedState = new SwipeSharedState();
public static boolean isConnected() {
return sConnected;
}
- private final SwipeSharedState mSwipeSharedState = new SwipeSharedState();
+ public static SwipeSharedState getSwipeSharedState() {
+ return sSwipeSharedState;
+ }
+
private final InputConsumer mResetGestureInputConsumer =
- new ResetGestureInputConsumer(mSwipeSharedState);
+ new ResetGestureInputConsumer(sSwipeSharedState);
private ActivityManagerWrapper mAM;
private RecentsModel mRecentsModel;
@@ -267,6 +272,9 @@ public class TouchInteractionService extends Service implements
private Mode mMode = Mode.THREE_BUTTONS;
private int mDefaultDisplayId;
private final RectF mSwipeTouchRegion = new RectF();
+ private final RectF mAssistantLeftRegion = new RectF();
+ private final RectF mAssistantRightRegion = new RectF();
+
private ComponentName mGestureBlockingActivity;
private Region mExclusionRegion;
@@ -349,9 +357,25 @@ public class TouchInteractionService extends Service implements
defaultDisplay.getRealSize(realSize);
mSwipeTouchRegion.set(0, 0, realSize.x, realSize.y);
if (mMode == Mode.NO_BUTTON) {
- mSwipeTouchRegion.top = mSwipeTouchRegion.bottom -
- getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
+ int touchHeight = getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
+ mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - touchHeight;
+
+ final int assistantWidth = getResources()
+ .getDimensionPixelSize(R.dimen.gestures_assistant_width);
+ final float assistantHeight = Math.max(touchHeight,
+ QuickStepContract.getWindowCornerRadius(getResources()));
+ mAssistantLeftRegion.bottom = mAssistantRightRegion.bottom = mSwipeTouchRegion.bottom;
+ mAssistantLeftRegion.top = mAssistantRightRegion.top =
+ mSwipeTouchRegion.bottom - assistantHeight;
+
+ mAssistantLeftRegion.left = 0;
+ mAssistantLeftRegion.right = assistantWidth;
+
+ mAssistantRightRegion.right = mSwipeTouchRegion.right;
+ mAssistantRightRegion.left = mSwipeTouchRegion.right - assistantWidth;
} else {
+ mAssistantLeftRegion.setEmpty();
+ mAssistantRightRegion.setEmpty();
switch (defaultDisplay.getRotation()) {
case Surface.ROTATION_90:
mSwipeTouchRegion.left = mSwipeTouchRegion.right
@@ -416,7 +440,7 @@ public class TouchInteractionService extends Service implements
mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
mIsUserUnlocked = true;
- mSwipeSharedState.setOverviewComponentObserver(mOverviewComponentObserver);
+ sSwipeSharedState.setOverviewComponentObserver(mOverviewComponentObserver);
mInputConsumer.registerInputConsumer();
onSystemUiProxySet();
onSystemUiFlagsChanged();
@@ -491,6 +515,15 @@ public class TouchInteractionService extends Service implements
mConsumer = newConsumer(useSharedState, event);
TOUCH_INTERACTION_LOG.addLog("setInputConsumer", mConsumer.getType());
mUncheckedConsumer = mConsumer;
+ } else if (mIsUserUnlocked && mMode == Mode.NO_BUTTON
+ && canTriggerAssistantAction(event)) {
+ // Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we should
+ // not interrupt it. QuickSwitch assumes that interruption can only happen if the
+ // next gesture is also quick switch.
+ mUncheckedConsumer =
+ new AssistantTouchConsumer(this, mISystemUiProxy,
+ mOverviewComponentObserver.getActivityControlHelper(),
+ InputConsumer.NO_OP, mInputMonitorCompat);
} else {
mUncheckedConsumer = InputConsumer.NO_OP;
}
@@ -505,6 +538,14 @@ public class TouchInteractionService extends Service implements
|| (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0);
}
+ private boolean canTriggerAssistantAction(MotionEvent ev) {
+ return mAssistantAvailable
+ && !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)
+ && (mAssistantLeftRegion.contains(ev.getX(), ev.getY()) ||
+ mAssistantRightRegion.contains(ev.getX(), ev.getY()))
+ && !ActivityManagerWrapper.getInstance().isLockToAppActive();
+ }
+
private InputConsumer newConsumer(boolean useSharedState, MotionEvent event) {
boolean isInValidSystemUiState = validSystemUiFlags();
@@ -525,10 +566,7 @@ public class TouchInteractionService extends Service implements
if (mMode == Mode.NO_BUTTON) {
final ActivityControlHelper activityControl =
mOverviewComponentObserver.getActivityControlHelper();
- if (mAssistantAvailable
- && !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)
- && AssistantTouchConsumer.withinTouchRegion(this, event)
- && !ActivityManagerWrapper.getInstance().isLockToAppActive()) {
+ if (canTriggerAssistantAction(event)) {
base = new AssistantTouchConsumer(this, mISystemUiProxy, activityControl, base,
mInputMonitorCompat);
}
@@ -555,7 +593,7 @@ public class TouchInteractionService extends Service implements
private InputConsumer newBaseConsumer(boolean useSharedState, MotionEvent event) {
final RunningTaskInfo runningTaskInfo = mAM.getRunningTask(0);
if (!useSharedState) {
- mSwipeSharedState.clearAllState();
+ sSwipeSharedState.clearAllState(false /* finishAnimation */);
}
if ((mSystemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0) {
// This handles apps showing over the lockscreen (e.g. camera)
@@ -565,22 +603,26 @@ public class TouchInteractionService extends Service implements
final ActivityControlHelper activityControl =
mOverviewComponentObserver.getActivityControlHelper();
- if (runningTaskInfo == null && !mSwipeSharedState.goingToLauncher
- && !mSwipeSharedState.recentsAnimationFinishInterrupted) {
+ if (runningTaskInfo == null && !sSwipeSharedState.goingToLauncher
+ && !sSwipeSharedState.recentsAnimationFinishInterrupted) {
return mResetGestureInputConsumer;
- } else if (mSwipeSharedState.recentsAnimationFinishInterrupted) {
+ } else if (sSwipeSharedState.recentsAnimationFinishInterrupted) {
// If the finish animation was interrupted, then continue using the other activity input
// consumer but with the next task as the running task
RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
- info.id = mSwipeSharedState.nextRunningTaskId;
+ info.id = sSwipeSharedState.nextRunningTaskId;
return createOtherActivityInputConsumer(event, info);
- } else if (mSwipeSharedState.goingToLauncher || activityControl.isResumed()) {
+ } else if (sSwipeSharedState.goingToLauncher || activityControl.isResumed()) {
return createOverviewInputConsumer(event);
} else if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityControl.isInLiveTileMode()) {
return createOverviewInputConsumer(event);
} 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, sSwipeSharedState, mSwipeTouchRegion,
+ mOverviewComponentObserver, disableHorizontalSwipe(event), runningTaskInfo);
} else {
return createOtherActivityInputConsumer(event, runningTaskInfo);
}
@@ -602,13 +644,13 @@ public class TouchInteractionService extends Service implements
return new OtherActivityInputConsumer(this, runningTaskInfo, mRecentsModel,
mOverviewComponentObserver.getOverviewIntent(), activityControl,
shouldDefer, mOverviewCallbacks, mInputConsumer, this::onConsumerInactive,
- mSwipeSharedState, mInputMonitorCompat, mSwipeTouchRegion,
+ sSwipeSharedState, mInputMonitorCompat, mSwipeTouchRegion,
disableHorizontalSwipe(event));
}
private InputConsumer createDeviceLockedInputConsumer(RunningTaskInfo taskInfo) {
if (mMode == Mode.NO_BUTTON && taskInfo != null) {
- return new DeviceLockedInputConsumer(this, mSwipeSharedState, mInputMonitorCompat,
+ return new DeviceLockedInputConsumer(this, sSwipeSharedState, mInputMonitorCompat,
mSwipeTouchRegion, taskInfo.taskId);
} else {
return mResetGestureInputConsumer;
@@ -623,7 +665,7 @@ public class TouchInteractionService extends Service implements
return mResetGestureInputConsumer;
}
- if (activity.getRootView().hasWindowFocus() || mSwipeSharedState.goingToLauncher) {
+ if (activity.getRootView().hasWindowFocus() || sSwipeSharedState.goingToLauncher) {
return new OverviewInputConsumer(activity, mInputMonitorCompat,
false /* startingInActivityBounds */);
} else {
@@ -670,7 +712,7 @@ public class TouchInteractionService extends Service implements
+ mOverviewComponentObserver.getActivityControlHelper().isResumed());
pw.println(" useSharedState=" + mConsumer.useSharedSwipeState());
if (mConsumer.useSharedSwipeState()) {
- mSwipeSharedState.dump(" ", pw);
+ sSwipeSharedState.dump(" ", pw);
}
pw.println(" mConsumer=" + mConsumer.getName());
pw.println("FeatureFlags:");
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java
index 837423ace..38b5a137c 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java
@@ -39,6 +39,8 @@ import android.os.Bundle;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
+import android.view.GestureDetector;
+import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -47,17 +49,14 @@ import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.logging.UserEventDispatcher;
-import com.android.launcher3.touch.SwipeDetector;
import com.android.quickstep.ActivityControlHelper;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.InputMonitorCompat;
-import com.android.systemui.shared.system.QuickStepContract;
/**
* Touch consumer for handling events to launch assistant from launcher
*/
-public class AssistantTouchConsumer extends DelegateInputConsumer
- implements SwipeDetector.Listener {
+public class AssistantTouchConsumer extends DelegateInputConsumer {
private static final String TAG = "AssistantTouchConsumer";
private static final long RETRACT_ANIMATION_DURATION_MS = 300;
@@ -68,7 +67,6 @@ public class AssistantTouchConsumer extends DelegateInputConsumer
private static final int OPA_BUNDLE_TRIGGER_DIAG_SWIPE_GESTURE = 83;
private static final String INVOCATION_TYPE_KEY = "invocation_type";
private static final int INVOCATION_TYPE_GESTURE = 1;
- private static final int INVOCATION_TYPE_FLING = 6;
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
@@ -90,7 +88,7 @@ public class AssistantTouchConsumer extends DelegateInputConsumer
private final float mSquaredSlop;
private final ISystemUiProxy mSysUiProxy;
private final Context mContext;
- private final SwipeDetector mSwipeDetector;
+ private final GestureDetector mGestureDetector;
public AssistantTouchConsumer(Context context, ISystemUiProxy systemUiProxy,
ActivityControlHelper activityControlHelper, InputConsumer delegate,
@@ -107,8 +105,8 @@ public class AssistantTouchConsumer extends DelegateInputConsumer
mSquaredSlop = slop * slop;
mActivityControlHelper = activityControlHelper;
- mSwipeDetector = new SwipeDetector(mContext, this, SwipeDetector.VERTICAL);
- mSwipeDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_POSITIVE, false);
+
+ mGestureDetector = new GestureDetector(context, new AssistantGestureListener());
}
@Override
@@ -119,7 +117,7 @@ public class AssistantTouchConsumer extends DelegateInputConsumer
@Override
public void onMotionEvent(MotionEvent ev) {
// TODO add logging
- mSwipeDetector.onTouchEvent(ev);
+ mGestureDetector.onTouchEvent(ev);
switch (ev.getActionMasked()) {
case ACTION_DOWN: {
@@ -171,13 +169,8 @@ public class AssistantTouchConsumer extends DelegateInputConsumer
mStartDragPos.set(mLastPos.x, mLastPos.y);
mDragTime = SystemClock.uptimeMillis();
- // Determine if angle is larger than threshold for assistant detection
- float angle = (float) Math.toDegrees(
- Math.atan2(mDownPos.y - mLastPos.y, mDownPos.x - mLastPos.x));
- mDirection = angle > 90 ? UPLEFT : UPRIGHT;
- angle = angle > 90 ? 180 - angle : angle;
-
- if (angle > mAngleThreshold && angle < 90) {
+ if (isValidAssistantGestureAngle(
+ mDownPos.x - mLastPos.x, mDownPos.y - mLastPos.y)) {
setActive(ev);
} else {
mState = STATE_DELEGATE_ACTIVE;
@@ -261,40 +254,41 @@ public class AssistantTouchConsumer extends DelegateInputConsumer
}
}
- public static boolean withinTouchRegion(Context context, MotionEvent ev) {
- final Resources res = context.getResources();
- final int width = res.getDisplayMetrics().widthPixels;
- final int height = res.getDisplayMetrics().heightPixels;
- final int size = res.getDimensionPixelSize(R.dimen.gestures_assistant_size);
- return (ev.getX() > width - size || ev.getX() < size) && ev.getY() > height - size;
- }
-
- @Override
- public void onDragStart(boolean start) {
- // do nothing
+ /**
+ * Determine if angle is larger than threshold for assistant detection
+ */
+ private boolean isValidAssistantGestureAngle(float deltaX, float deltaY) {
+ float angle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX));
+ mDirection = angle > 90 ? UPLEFT : UPRIGHT;
+
+ // normalize so that angle is measured clockwise from horizontal in the bottom right corner
+ // and counterclockwise from horizontal in the bottom left corner
+ angle = angle > 90 ? 180 - angle : angle;
+ return (angle > mAngleThreshold && angle < 90);
}
- @Override
- public boolean onDrag(float displacement) {
- return false;
- }
+ private class AssistantGestureListener extends SimpleOnGestureListener {
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+ if (isValidAssistantGestureAngle(velocityX, -velocityY)
+ && !mLaunchedAssistant && mState != STATE_DELEGATE_ACTIVE) {
+ mLastProgress = 1;
+ try {
+ mSysUiProxy.onAssistantGestureCompletion(
+ (float) Math.sqrt(velocityX * velocityX + velocityY * velocityY));
+ startAssistantInternal(FLING);
- @Override
- public void onDragEnd(float velocity, boolean fling) {
- if (fling && !mLaunchedAssistant && mState != STATE_DELEGATE_ACTIVE) {
- mLastProgress = 1;
- try {
- mSysUiProxy.onAssistantGestureCompletion(velocity);
- startAssistantInternal(FLING);
-
- Bundle args = new Bundle();
- args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_GESTURE);
- mSysUiProxy.startAssistant(args);
- mLaunchedAssistant = true;
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to send SysUI start/send assistant progress: " + mLastProgress,
- e);
+ Bundle args = new Bundle();
+ args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_GESTURE);
+ mSysUiProxy.startAssistant(args);
+ mLaunchedAssistant = true;
+ } catch (RemoteException e) {
+ Log.w(TAG,
+ "Failed to send SysUI start/send assistant progress: " + mLastProgress,
+ e);
+ }
}
+ return true;
}
}
}
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/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java
index 56cba2192..8eede81b8 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java
@@ -39,7 +39,7 @@ public class ResetGestureInputConsumer implements InputConsumer {
public void onMotionEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN
&& mSwipeSharedState.getActiveListener() != null) {
- mSwipeSharedState.clearAllState();
+ mSwipeSharedState.clearAllState(false /* finishAnimation */);
}
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index 9eda2f9d4..07e96869e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -17,19 +17,15 @@ package com.android.quickstep.util;
import android.animation.Animator;
import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
-import androidx.dynamicanimation.animation.SpringForce;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils.ViewProgressProperty;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
@@ -40,6 +36,7 @@ import com.android.launcher3.anim.SpringObjectAnimator;
import java.util.ArrayList;
import java.util.List;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
@@ -147,9 +144,8 @@ public class StaggeredWorkspaceAnim {
long startDelay = (long) ((invertedRow + 1) * APP_CLOSE_ROW_START_DELAY_MS);
v.setTranslationY(mSpringTransY);
- SpringObjectAnimator springTransY = new SpringObjectAnimator<>(
- new ViewProgressProperty(v, View.TRANSLATION_Y), "staggeredSpringTransY", 1f,
- DAMPING_RATIO, STIFFNESS, mSpringTransY, 0);
+ SpringObjectAnimator springTransY = new SpringObjectAnimator<>(v, VIEW_TRANSLATE_Y,
+ 1f, DAMPING_RATIO, STIFFNESS, mSpringTransY, 0);
springTransY.setStartDelay(startDelay);
mAnimators.add(springTransY);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java
index df9efa247..381c27a28 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java
@@ -106,6 +106,10 @@ public class SwipeAnimationTargetSet extends RemoteAnimationTargetSet {
finishController(false /* toRecents */, null, false /* sendUserLeaveHint */);
}
+ public void finishAnimation() {
+ finishController(true /* toRecents */, null, false /* sendUserLeaveHint */);
+ }
+
public interface SwipeAnimationListener {
void onRecentsAnimationStart(SwipeAnimationTargetSet targetSet);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
index 5b2e27e53..03441c87e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -33,9 +33,11 @@ import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
+import android.view.MotionEvent;
import android.view.View;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Hotseat;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.StateListener;
@@ -250,4 +252,16 @@ public class LauncherRecentsView extends RecentsView<Launcher> implements StateL
setDisallowScrollToClearAll(!hasClearAllButton);
}
}
+
+ @Override
+ protected boolean shouldStealTouchFromSiblingsBelow(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ // Allow touches to go through to the hotseat.
+ Hotseat hotseat = mActivity.getHotseat();
+ boolean touchingHotseat = hotseat.isShown()
+ && mActivity.getDragLayer().isEventOverView(hotseat, ev, this);
+ return !touchingHotseat;
+ }
+ return super.shouldStealTouchFromSiblingsBelow(ev);
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index 9058e7eda..a98df0fa1 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -16,9 +16,13 @@
package com.android.quickstep.views;
+import static androidx.dynamicanimation.animation.DynamicAnimation.MIN_VISIBLE_CHANGE_PIXELS;
+
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.Utilities.squaredTouchSlop;
@@ -79,7 +83,6 @@ import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherAnimUtils.ViewProgressProperty;
import com.android.launcher3.LauncherState;
import com.android.launcher3.PagedView;
import com.android.launcher3.R;
@@ -124,10 +127,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
private static final String TAG = RecentsView.class.getSimpleName();
- public static final float SPRING_MIN_VISIBLE_CHANGE = 0.001f;
- public static final float SPRING_DAMPING_RATIO = SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY;
- public static final float SPRING_STIFFNESS = SpringForce.STIFFNESS_MEDIUM;
-
public static final FloatProperty<RecentsView> CONTENT_ALPHA =
new FloatProperty<RecentsView>("contentAlpha") {
@Override
@@ -521,6 +520,10 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
// Do not let touch escape to siblings below this view.
+ return isHandlingTouch() || shouldStealTouchFromSiblingsBelow(ev);
+ }
+
+ protected boolean shouldStealTouchFromSiblingsBelow(MotionEvent ev) {
return true;
}
@@ -1027,9 +1030,10 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
private void addDismissedTaskAnimations(View taskView, AnimatorSet anim, long duration) {
addAnim(ObjectAnimator.ofFloat(taskView, ALPHA, 0), duration, ACCEL_2, anim);
if (QUICKSTEP_SPRINGS.get() && taskView instanceof TaskView)
- addAnim(new SpringObjectAnimator<>(new ViewProgressProperty(taskView,
- View.TRANSLATION_Y), "taskViewTransY", SPRING_MIN_VISIBLE_CHANGE,
- SPRING_DAMPING_RATIO, SPRING_STIFFNESS, 0, -taskView.getHeight()),
+ addAnim(new SpringObjectAnimator<>(taskView, VIEW_TRANSLATE_Y,
+ MIN_VISIBLE_CHANGE_PIXELS, SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY,
+ SpringForce.STIFFNESS_MEDIUM,
+ 0, -taskView.getHeight()),
duration, LINEAR, anim);
else {
addAnim(ObjectAnimator.ofFloat(taskView, TRANSLATION_Y, -taskView.getHeight()),
@@ -1105,10 +1109,10 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
int scrollDiff = newScroll[i] - oldScroll[i] + offset;
if (scrollDiff != 0) {
if (QUICKSTEP_SPRINGS.get() && child instanceof TaskView) {
- addAnim(new SpringObjectAnimator<>(
- new ViewProgressProperty(child, View.TRANSLATION_X),
- "taskViewTransX", SPRING_MIN_VISIBLE_CHANGE, SPRING_DAMPING_RATIO,
- SPRING_STIFFNESS, 0, scrollDiff), duration, ACCEL, anim);
+ addAnim(new SpringObjectAnimator<>(child, VIEW_TRANSLATE_X,
+ MIN_VISIBLE_CHANGE_PIXELS, SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY,
+ SpringForce.STIFFNESS_MEDIUM,
+ 0, scrollDiff), duration, ACCEL, anim);
} else {
addAnim(ObjectAnimator.ofFloat(child, TRANSLATION_X, scrollDiff), duration,
ACCEL, anim);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
index 6f10b42fb..d55a52044 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -367,8 +367,11 @@ public class TaskThumbnailView extends View {
}
mRotated = isRotated;
- updateOverlay();
invalidate();
+
+ // Update can be called from {@link #onSizeChanged} during layout, post handling of overlay
+ // as overlay could modify the views in the overlay as a side effect of its update.
+ post(this::updateOverlay);
}
@Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
index e7e41893c..b26fdce92 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
@@ -368,6 +368,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
} else {
mSnapshotView.setThumbnail(null, null);
setIcon(null);
+ // Reset the task thumbnail reference as well (it will be fetched from the cache or
+ // reloaded next time we need it)
+ mTask.thumbnail = null;
}
}
@@ -488,9 +491,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
mSnapshotView.setThumbnail(mTask, null);
setOverlayEnabled(false);
onTaskListVisibilityChanged(false);
- if (mTask != null) {
- mTask.thumbnail = null;
- }
}
@Override