summaryrefslogtreecommitdiffstats
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
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
-rw-r--r--Android.mk2
-rw-r--r--go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java21
-rw-r--r--go/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java40
-rw-r--r--go/quickstep/src/com/android/quickstep/TouchInteractionService.java51
-rw-r--r--iconloaderlib/build.gradle16
-rw-r--r--iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java8
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java35
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java21
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java12
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java16
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java45
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java39
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java95
-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
-rw-r--r--quickstep/res/values/dimens.xml5
-rw-r--r--quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java2
-rw-r--r--quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java9
-rw-r--r--quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java68
-rw-r--r--quickstep/src/com/android/quickstep/OverviewComponentObserver.java27
-rw-r--r--quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java (renamed from quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepProcessInitializer.java)13
-rw-r--r--quickstep/src/com/android/quickstep/RecentTasksList.java12
-rw-r--r--quickstep/src/com/android/quickstep/util/LayoutUtils.java2
-rw-r--r--quickstep/src/com/android/quickstep/views/ShelfScrimView.java18
-rw-r--r--quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java17
-rw-r--r--quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java17
-rw-r--r--quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java2
-rw-r--r--src/com/android/launcher3/BubbleTextView.java13
-rw-r--r--src/com/android/launcher3/Launcher.java31
-rw-r--r--src/com/android/launcher3/LauncherAnimUtils.java53
-rw-r--r--src/com/android/launcher3/LauncherAppTransitionManager.java12
-rw-r--r--src/com/android/launcher3/LauncherModel.java3
-rw-r--r--src/com/android/launcher3/LauncherState.java53
-rw-r--r--src/com/android/launcher3/LauncherStateManager.java112
-rw-r--r--src/com/android/launcher3/PagedView.java9
-rw-r--r--src/com/android/launcher3/SecondaryDropTarget.java2
-rw-r--r--src/com/android/launcher3/Utilities.java10
-rw-r--r--src/com/android/launcher3/WorkspaceStateTransitionAnimation.java13
-rw-r--r--src/com/android/launcher3/allapps/AllAppsTransitionController.java42
-rw-r--r--src/com/android/launcher3/anim/AnimatorSetBuilder.java12
-rw-r--r--src/com/android/launcher3/anim/SpringObjectAnimator.java46
-rw-r--r--src/com/android/launcher3/config/BaseFlags.java2
-rw-r--r--src/com/android/launcher3/touch/TouchEventTranslator.java283
-rw-r--r--src/com/android/launcher3/views/BaseDragLayer.java17
-rw-r--r--src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java4
-rw-r--r--tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java44
-rw-r--r--tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java29
-rw-r--r--tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java63
-rw-r--r--tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java10
-rw-r--r--tests/src/com/android/launcher3/ui/TestViewHelpers.java15
-rw-r--r--tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java47
-rw-r--r--tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java64
-rw-r--r--tests/src/com/android/launcher3/util/rule/FailureWatcher.java16
-rw-r--r--tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java5
-rw-r--r--tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java41
-rw-r--r--tests/tapl/com/android/launcher3/tapl/Background.java32
-rw-r--r--tests/tapl/com/android/launcher3/tapl/Folder.java35
-rw-r--r--tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java68
-rw-r--r--tests/tapl/com/android/launcher3/tapl/OverviewTask.java9
-rw-r--r--tests/tapl/com/android/launcher3/tapl/Widget.java (renamed from src/com/android/launcher3/ProgressInterface.java)16
-rw-r--r--tests/tapl/com/android/launcher3/tapl/Workspace.java26
74 files changed, 1535 insertions, 917 deletions
diff --git a/Android.mk b/Android.mk
index 7956d2810..9d113d954 100644
--- a/Android.mk
+++ b/Android.mk
@@ -298,7 +298,7 @@ LOCAL_PROGUARD_ENABLED := full
LOCAL_PACKAGE_NAME := Launcher3GoIconRecents
LOCAL_PRIVILEGED_MODULE := true
LOCAL_PRODUCT_MODULE := true
-LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3 Launcher3Go Launcher3QuickStep Launcher3QuickStepGo
+LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3 Launcher3Go Launcher3QuickStep
LOCAL_REQUIRED_MODULES := privapp_whitelist_com.android.launcher3
LOCAL_FULL_LIBS_MANIFEST_FILES := \
diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
index b5fefb46d..cbc77d272 100644
--- a/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
+++ b/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
@@ -16,11 +16,6 @@
package com.android.launcher3.uioverrides;
-import static android.view.View.VISIBLE;
-import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
-
-import android.view.View;
-
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherStateManager.StateHandler;
@@ -43,8 +38,6 @@ import java.util.ArrayList;
public abstract class RecentsUiFactory {
public static final boolean GO_LOW_RAM_RECENTS_ENABLED = true;
- // Scale recents takes before animating in
- private static final float RECENTS_PREPARE_SCALE = 1.33f;
public static TouchController[] createTouchControllers(Launcher launcher) {
ArrayList<TouchController> list = new ArrayList<>();
@@ -77,18 +70,6 @@ public abstract class RecentsUiFactory {
}
/**
- * Prepare the recents view to animate in.
- *
- * @param launcher the launcher activity
- */
- public static void prepareToShowOverview(Launcher launcher) {
- View overview = launcher.getOverviewPanel();
- if (overview.getVisibility() != VISIBLE) {
- SCALE_PROPERTY.set(overview, RECENTS_PREPARE_SCALE);
- }
- }
-
- /**
* Clean-up logic that occurs when recents is no longer in use/visible.
*
* @param launcher the launcher activity
@@ -108,4 +89,6 @@ public abstract class RecentsUiFactory {
public static RotationMode getRotationMode(DeviceProfile dp) {
return RotationMode.NORMAL;
}
+
+ public static void clearSwipeSharedState(boolean finishAnimation) {}
}
diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/go/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 1b24fc856..d0cfcf97a 100644
--- a/go/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/go/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -16,15 +16,31 @@
package com.android.launcher3.uioverrides.states;
+import static android.view.View.VISIBLE;
+
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_X;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE;
+import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
+import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
+import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7;
import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
+import android.view.View;
+
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
+import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.views.IconRecentsView;
/**
@@ -32,6 +48,9 @@ import com.android.quickstep.views.IconRecentsView;
*/
public class OverviewState extends LauncherState {
+ // Scale recents takes before animating in
+ private static final float RECENTS_PREPARE_SCALE = 1.33f;
+
private static final int STATE_FLAGS = FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED
| FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI | FLAG_DISABLE_ACCESSIBILITY;
@@ -103,6 +122,27 @@ public class OverviewState extends LauncherState {
return dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx;
}
+ @Override
+ public void prepareForAtomicAnimation(Launcher launcher, LauncherState fromState,
+ AnimatorSetBuilder builder) {
+ if (fromState == NORMAL && this == OVERVIEW) {
+ if (SysUINavigationMode.getMode(launcher) == SysUINavigationMode.Mode.NO_BUTTON) {
+ builder.setInterpolator(ANIM_WORKSPACE_SCALE, ACCEL);
+ builder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL);
+ } else {
+ builder.setInterpolator(ANIM_WORKSPACE_SCALE, OVERSHOOT_1_2);
+ }
+ builder.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
+ builder.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
+ builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_7);
+ builder.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2);
+
+ View overview = launcher.getOverviewPanel();
+ if (overview.getVisibility() != VISIBLE) {
+ SCALE_PROPERTY.set(overview, RECENTS_PREPARE_SCALE);
+ }
+ }
+ }
public static OverviewState newBackgroundState(int id) {
return new OverviewState(id);
diff --git a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 39f8448d1..900b94e18 100644
--- a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -19,15 +19,21 @@ import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYS
import android.annotation.TargetApi;
import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.graphics.Region;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
import android.view.MotionEvent;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.compat.UserManagerCompat;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
@@ -37,7 +43,16 @@ import com.android.systemui.shared.recents.ISystemUiProxy;
@TargetApi(Build.VERSION_CODES.O)
public class TouchInteractionService extends Service {
- private static final String TAG = "TouchInteractionService";
+ private static final String TAG = "GoTouchInteractionService";
+ private boolean mIsUserUnlocked;
+ private BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
+ initWhenUserUnlocked();
+ }
+ }
+ };
private final IBinder mMyBinder = new IOverviewProxy.Stub() {
@@ -53,17 +68,21 @@ public class TouchInteractionService extends Service {
@Override
public void onOverviewToggle() {
- mOverviewCommandHelper.onOverviewToggle();
+ if (mIsUserUnlocked) {
+ mOverviewCommandHelper.onOverviewToggle();
+ }
}
@Override
public void onOverviewShown(boolean triggeredFromAltTab) {
- mOverviewCommandHelper.onOverviewShown(triggeredFromAltTab);
+ if (mIsUserUnlocked) {
+ mOverviewCommandHelper.onOverviewShown(triggeredFromAltTab);
+ }
}
@Override
public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
- if (triggeredFromAltTab && !triggeredFromHomeKey) {
+ if (mIsUserUnlocked && triggeredFromAltTab && !triggeredFromHomeKey) {
// onOverviewShownFromAltTab hides the overview and ends at the target app
mOverviewCommandHelper.onOverviewHidden();
}
@@ -71,7 +90,9 @@ public class TouchInteractionService extends Service {
@Override
public void onTip(int actionType, int viewType) {
- mOverviewCommandHelper.onTip(actionType, viewType);
+ if (mIsUserUnlocked) {
+ mOverviewCommandHelper.onTip(actionType, viewType);
+ }
}
@Override
@@ -123,17 +144,31 @@ public class TouchInteractionService extends Service {
@Override
public void onCreate() {
super.onCreate();
+ if (UserManagerCompat.getInstance(this).isUserUnlocked(Process.myUserHandle())) {
+ initWhenUserUnlocked();
+ } else {
+ mIsUserUnlocked = false;
+ registerReceiver(mUserUnlockedReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
+ }
+
+ sConnected = true;
+ }
+
+ private void initWhenUserUnlocked() {
mRecentsModel = RecentsModel.INSTANCE.get(this);
mOverviewComponentObserver = new OverviewComponentObserver(this);
mOverviewCommandHelper = new OverviewCommandHelper(this,
mOverviewComponentObserver);
-
- sConnected = true;
+ mIsUserUnlocked = true;
+ Utilities.unregisterReceiverSafely(this, mUserUnlockedReceiver);
}
@Override
public void onDestroy() {
- mOverviewComponentObserver.onDestroy();
+ if (mIsUserUnlocked) {
+ mOverviewComponentObserver.onDestroy();
+ }
+ Utilities.unregisterReceiverSafely(this, mUserUnlockedReceiver);
sConnected = false;
super.onDestroy();
}
diff --git a/iconloaderlib/build.gradle b/iconloaderlib/build.gradle
index 49d427ede..8a4d2b76e 100644
--- a/iconloaderlib/build.gradle
+++ b/iconloaderlib/build.gradle
@@ -1,13 +1,3 @@
-buildscript {
- repositories {
- mavenCentral()
- google()
- }
- dependencies {
- classpath GRADLE_CLASS_PATH
- }
-}
-
apply plugin: 'com.android.library'
android {
@@ -44,12 +34,6 @@ android {
}
}
-
-repositories {
- mavenCentral()
- google()
-}
-
dependencies {
implementation "androidx.core:core:${ANDROID_X_VERSION}"
}
diff --git a/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java b/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java
index af07aa3a9..97a0fd3ff 100644
--- a/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java
+++ b/iconloaderlib/src/com/android/launcher3/icons/DotRenderer.java
@@ -85,6 +85,14 @@ public class DotRenderer {
return pos;
}
+ public float[] getLeftDotPosition() {
+ return mLeftDotPosition;
+ }
+
+ public float[] getRightDotPosition() {
+ return mRightDotPosition;
+ }
+
/**
* Draw a circle on top of the canvas according to the given params.
*/
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index eac4dce18..371161ebd 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -16,25 +16,32 @@
package com.android.launcher3;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
import static com.android.quickstep.TaskViewUtils.getRecentsWindowAnimator;
+import static androidx.dynamicanimation.animation.DynamicAnimation.MIN_VISIBLE_CHANGE_PIXELS;
+import static androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY;
+import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_MEDIUM;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
-import android.app.ActivityOptions;
import android.content.Context;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.anim.SpringObjectAnimator;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -46,11 +53,12 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
*/
public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransitionManagerImpl {
- private RecentsView mRecentsView;
+ public static final int INDEX_SHELF_ANIM = 0;
+ public static final int INDEX_RECENTS_FADE_ANIM = 1;
+ public static final int INDEX_RECENTS_TRANSLATE_X_ANIM = 2;
public LauncherAppTransitionManagerImpl(Context context) {
super(context);
- mRecentsView = mLauncher.getOverviewPanel();
}
@Override
@@ -133,4 +141,25 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti
mLauncher.getStateManager().reapplyState();
};
}
+
+ @Override
+ public int getStateElementAnimationsCount() {
+ return 3;
+ }
+
+ @Override
+ public Animator createStateElementAnimation(int index, float... values) {
+ switch (index) {
+ case INDEX_SHELF_ANIM:
+ return mLauncher.getAllAppsController().createSpringAnimation(values);
+ case INDEX_RECENTS_FADE_ANIM:
+ return ObjectAnimator.ofFloat(mLauncher.getOverviewPanel(),
+ RecentsView.CONTENT_ALPHA, values);
+ case INDEX_RECENTS_TRANSLATE_X_ANIM:
+ return new SpringObjectAnimator<>(mLauncher.getOverviewPanel(),
+ VIEW_TRANSLATE_X, MIN_VISIBLE_CHANGE_PIXELS, 0.8f, 250, values);
+ default:
+ return super.createStateElementAnimation(index, values);
+ }
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
index d84362c9f..6ecf1c11b 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
@@ -16,8 +16,6 @@
package com.android.launcher3.uioverrides;
-import static android.view.View.VISIBLE;
-import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
@@ -48,6 +46,7 @@ import com.android.launcher3.util.UiThreadHelper;
import com.android.launcher3.util.UiThreadHelper.AsyncCommand;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
+import com.android.quickstep.TouchInteractionService;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.WindowManagerWrapper;
@@ -62,9 +61,6 @@ public abstract class RecentsUiFactory {
private static final AsyncCommand SET_SHELF_HEIGHT_CMD = (visible, height) ->
WindowManagerWrapper.getInstance().setShelfHeight(visible != 0, height);
- // Scale recents takes before animating in
- private static final float RECENTS_PREPARE_SCALE = 1.33f;
-
public static RotationMode ROTATION_LANDSCAPE = new RotationMode(-90) {
@Override
public void mapRect(int left, int top, int right, int bottom, Rect out) {
@@ -189,19 +185,10 @@ public abstract class RecentsUiFactory {
}
/**
- * Prepare the recents view to animate in.
- *
- * @param launcher the launcher activity
+ * Clears the swipe shared state for the current swipe gesture.
*/
- public static void prepareToShowOverview(Launcher launcher) {
- if (SysUINavigationMode.getMode(launcher) == NO_BUTTON) {
- // Overview lives on the side, so doesn't scale in from above.
- return;
- }
- RecentsView overview = launcher.getOverviewPanel();
- if (overview.getVisibility() != VISIBLE || overview.getContentAlpha() == 0) {
- SCALE_PROPERTY.set(overview, RECENTS_PREPARE_SCALE);
- }
+ public static void clearSwipeSharedState(boolean finishAnimation) {
+ TouchInteractionService.getSwipeSharedState().clearAllState(finishAnimation);
}
/**
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index 1c6696858..d14de70c5 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -83,4 +83,16 @@ public class BackgroundAppState extends OverviewState {
public int getVisibleElements(Launcher launcher) {
return super.getVisibleElements(launcher) & ~RECENTS_CLEAR_ALL_BUTTON;
}
+
+ @Override
+ public ScaleAndTranslation getHotseatScaleAndTranslation(Launcher launcher) {
+ if ((getVisibleElements(launcher) & HOTSEAT_ICONS) != 0) {
+ // Translate hotseat offscreen if we show it in overview.
+ ScaleAndTranslation scaleAndTranslation = super.getHotseatScaleAndTranslation(launcher);
+ scaleAndTranslation.translationY = LayoutUtils.getShelfTrackingDistance(launcher,
+ launcher.getDeviceProfile());
+ return scaleAndTranslation;
+ }
+ return super.getHotseatScaleAndTranslation(launcher);
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java
index bc1d4ba0c..c95476283 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java
@@ -14,8 +14,15 @@
* limitations under the License.
*/
package com.android.launcher3.uioverrides.states;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_X;
+import static com.android.launcher3.anim.Interpolators.INSTANT;
+import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7;
+
import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
+import com.android.launcher3.anim.AnimatorSetBuilder;
public class OverviewPeekState extends OverviewState {
public OverviewPeekState(int id) {
@@ -29,4 +36,13 @@ public class OverviewPeekState extends OverviewState {
- launcher.getResources().getDimension(R.dimen.overview_peek_distance);
return result;
}
+
+ @Override
+ public void prepareForAtomicAnimation(Launcher launcher, LauncherState fromState,
+ AnimatorSetBuilder builder) {
+ if (this == OVERVIEW_PEEK && fromState == NORMAL) {
+ builder.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT);
+ builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_7);
+ }
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 9a99c1552..5543860ee 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -15,8 +15,20 @@
*/
package com.android.launcher3.uioverrides.states;
+import static android.view.View.VISIBLE;
+
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_X;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE;
+import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
+import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
+import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
@@ -30,8 +42,11 @@ import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.Workspace;
import com.android.launcher3.allapps.DiscoveryBounce;
+import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.uioverrides.UiFactory;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -40,6 +55,9 @@ import com.android.quickstep.views.TaskView;
*/
public class OverviewState extends LauncherState {
+ // Scale recents takes before animating in
+ private static final float RECENTS_PREPARE_SCALE = 1.33f;
+
protected static final Rect sTempRect = new Rect();
private static final int STATE_FLAGS = FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED
@@ -127,6 +145,10 @@ public class OverviewState extends LauncherState {
// We have no all apps content, so we're still at the fully down progress.
return super.getVerticalProgress(launcher);
}
+ return getDefaultVerticalProgress(launcher);
+ }
+
+ public static float getDefaultVerticalProgress(Launcher launcher) {
return 1 - (getDefaultSwipeHeight(launcher)
/ launcher.getAllAppsController().getShiftRange());
}
@@ -156,6 +178,29 @@ public class OverviewState extends LauncherState {
}
}
+ @Override
+ public void prepareForAtomicAnimation(Launcher launcher, LauncherState fromState,
+ AnimatorSetBuilder builder) {
+ if (fromState == NORMAL && this == OVERVIEW) {
+ if (SysUINavigationMode.getMode(launcher) == SysUINavigationMode.Mode.NO_BUTTON) {
+ builder.setInterpolator(ANIM_WORKSPACE_SCALE, ACCEL);
+ builder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL);
+ } else {
+ builder.setInterpolator(ANIM_WORKSPACE_SCALE, OVERSHOOT_1_2);
+
+ // Scale up the recents, if it is not coming from the side
+ RecentsView overview = launcher.getOverviewPanel();
+ if (overview.getVisibility() != VISIBLE || overview.getContentAlpha() == 0) {
+ SCALE_PROPERTY.set(overview, RECENTS_PREPARE_SCALE);
+ }
+ }
+ builder.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
+ builder.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
+ builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_7);
+ builder.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2);
+ }
+ }
+
public static OverviewState newBackgroundState(int id) {
return new BackgroundAppState(id);
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
index e3e339add..3fe4bcfd9 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
@@ -16,11 +16,20 @@
package com.android.launcher3.uioverrides.touchcontrollers;
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.OVERVIEW_PEEK;
import static com.android.launcher3.LauncherStateManager.ANIM_ALL;
import static com.android.launcher3.LauncherStateManager.ATOMIC_OVERVIEW_PEEK_COMPONENT;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_SCALE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_TRANSLATE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
@@ -38,14 +47,14 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.quickstep.OverviewInteractionState;
import com.android.quickstep.util.MotionPauseDetector;
import com.android.quickstep.views.RecentsView;
-import com.android.systemui.shared.system.QuickStepContract;
/**
* Touch controller which handles swipe and hold to go to Overview
*/
public class FlingAndHoldTouchController extends PortraitStatesTouchController {
- private static final long PEEK_ANIM_DURATION = 100;
+ private static final long PEEK_IN_ANIM_DURATION = 240;
+ private static final long PEEK_OUT_ANIM_DURATION = 100;
private static final float MAX_DISPLACEMENT_PERCENT = 0.75f;
private final MotionPauseDetector mMotionPauseDetector;
@@ -81,9 +90,9 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
}
LauncherState fromState = isPaused ? NORMAL : OVERVIEW_PEEK;
LauncherState toState = isPaused ? OVERVIEW_PEEK : NORMAL;
+ long peekDuration = isPaused ? PEEK_IN_ANIM_DURATION : PEEK_OUT_ANIM_DURATION;
mPeekAnim = mLauncher.getStateManager().createAtomicAnimation(fromState, toState,
- new AnimatorSetBuilder(), ATOMIC_OVERVIEW_PEEK_COMPONENT,
- PEEK_ANIM_DURATION);
+ new AnimatorSetBuilder(), ATOMIC_OVERVIEW_PEEK_COMPONENT, peekDuration);
mPeekAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -107,6 +116,21 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
}
@Override
+ protected AnimatorSetBuilder getAnimatorSetBuilderForStates(LauncherState fromState,
+ LauncherState toState) {
+ if (fromState == NORMAL && toState == ALL_APPS) {
+ AnimatorSetBuilder builder = new AnimatorSetBuilder();
+
+ // Get workspace out of the way quickly, to prepare for potential pause.
+ builder.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL_3);
+ builder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, DEACCEL_3);
+ builder.setInterpolator(ANIM_WORKSPACE_FADE, DEACCEL_3);
+ return builder;
+ }
+ return super.getAnimatorSetBuilderForStates(fromState, toState);
+ }
+
+ @Override
public boolean onDrag(float displacement, MotionEvent event) {
float upDisplacement = -displacement;
mMotionPauseDetector.setDisallowPause(upDisplacement < mMotionPauseMinDisplacement
@@ -123,8 +147,11 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
}
AnimatorSetBuilder builder = new AnimatorSetBuilder();
- builder.setInterpolator(AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2);
- builder.setInterpolator(AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE, OVERSHOOT_1_2);
+ builder.setInterpolator(ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2);
+ if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
+ builder.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2);
+ builder.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2);
+ }
AnimatorSet overviewAnim = mLauncher.getStateManager().createAtomicAnimation(
NORMAL, OVERVIEW, builder, ANIM_ALL, ATOMIC_DURATION);
overviewAnim.addListener(new AnimatorListenerAdapter() {
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/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
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 82d1aa672..71259fd7a 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -24,7 +24,7 @@
<dimen name="recents_page_spacing">10dp</dimen>
<dimen name="recents_clear_all_deadzone_vertical_margin">70dp</dimen>
- <dimen name="overview_peek_distance">32dp</dimen>
+ <dimen name="overview_peek_distance">96dp</dimen>
<!-- The speed in dp/s at which the user needs to be scrolling in recents such that we start
loading full resolution screenshots. -->
@@ -66,7 +66,8 @@
<dimen name="shelf_surface_offset">24dp</dimen>
<!-- Assistant Gestures -->
- <dimen name="gestures_assistant_size">48dp</dimen>
+ <!-- Distance from the vertical edges of the screen in which assist gestures are recognized -->
+ <dimen name="gestures_assistant_width">48dp</dimen>
<dimen name="gestures_assistant_drag_threshold">55dp</dimen>
<!-- Distance to move elements when swiping up to go home from launcher -->
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index 864316095..44324cb2e 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -765,7 +765,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
LauncherAnimationRunner.AnimationResult result) {
if (!mLauncher.hasBeenResumed()) {
// If launcher is not resumed, wait until new async-frame after resume
- mLauncher.setOnResumeCallback(() ->
+ mLauncher.addOnResumeCallback(() ->
postAsyncCallback(mHandler, () ->
onCreateAnimation(targetCompats, result)));
return;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index ab24f5f5a..85a954507 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -23,6 +23,7 @@ import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.quickstep.SysUINavigationMode;
/**
* Definition for AllApps state
@@ -63,7 +64,13 @@ public class AllAppsState extends LauncherState {
public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
ScaleAndTranslation scaleAndTranslation = LauncherState.OVERVIEW
.getWorkspaceScaleAndTranslation(launcher);
- scaleAndTranslation.scale = 1;
+ if (SysUINavigationMode.getMode(launcher) == SysUINavigationMode.Mode.NO_BUTTON) {
+ float normalScale = 1;
+ // Scale down halfway to where we'd be in overview, to prepare for a potential pause.
+ scaleAndTranslation.scale = (scaleAndTranslation.scale + normalScale) / 2;
+ } else {
+ scaleAndTranslation.scale = 1;
+ }
return scaleAndTranslation;
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
index fee18204e..f5ba3725d 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
@@ -17,17 +17,22 @@ 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;
@@ -36,18 +41,29 @@ import java.io.PrintWriter;
/**
* TouchController for handling touch events that get sent to the StatusBar. Once the
- * Once the event delta y passes the touch slop, the events start getting forwarded.
+ * Once the event delta mDownY 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;
@@ -56,7 +72,7 @@ public class StatusBarTouchController implements TouchController {
mLauncher = l;
// Guard against TAPs by increasing the touch slop.
mTouchSlop = 2 * ViewConfiguration.get(l).getScaledTouchSlop();
- mTranslator = new TouchEventTranslator((MotionEvent ev)-> dispatchTouchEvent(ev));
+ mDownEvents = new SparseArray<>();
}
@Override
@@ -64,7 +80,6 @@ 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) {
@@ -81,26 +96,31 @@ 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;
}
- mTranslator.reset();
- mTranslator.setDownParameters(0, ev);
+ mDownEvents.put(pid, new PointF(ev.getX(), ev.getY()));
} else if (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
- // Check!! should only set it only when threshold is not entered.
- mTranslator.setDownParameters(ev.getActionIndex(), ev);
+ // Check!! should only set it only when threshold is not entered.
+ mDownEvents.put(pid, new PointF(ev.getX(idx), ev.getY(idx)));
}
if (!mCanIntercept) {
return false;
}
if (action == ACTION_MOVE) {
- float dy = ev.getY() - mTranslator.getDownY();
- float dx = ev.getX() - mTranslator.getDownX();
- if (dy > mTouchSlop && dy > Math.abs(dx)) {
- mTranslator.dispatchDownEvents(ev);
- mTranslator.processMotionEvent(ev);
+ 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);
return true;
}
if (Math.abs(dx) > mTouchSlop) {
@@ -110,13 +130,27 @@ public class StatusBarTouchController implements TouchController {
return false;
}
-
@Override
public final boolean onControllerTouchEvent(MotionEvent ev) {
- mTranslator.processMotionEvent(ev);
+ if (ev.getAction() == ACTION_UP || ev.getAction() == ACTION_CANCEL) {
+ dispatchTouchEvent(ev);
+ setWindowSlippery(false);
+ return true;
+ }
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,
@@ -132,4 +166,4 @@ public class StatusBarTouchController implements TouchController {
mSysUiProxy = RecentsModel.INSTANCE.get(mLauncher).getSystemUiProxy();
return mSysUiProxy != null;
}
-}
+} \ No newline at end of file
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
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepProcessInitializer.java b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
index befeee0db..7bfa9a0f9 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepProcessInitializer.java
+++ b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
@@ -15,6 +15,7 @@
*/
package com.android.quickstep;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.UserManager;
@@ -22,17 +23,29 @@ import android.util.Log;
import com.android.launcher3.BuildConfig;
import com.android.launcher3.MainProcessInitializer;
+import com.android.launcher3.Utilities;
import com.android.systemui.shared.system.ThreadedRendererCompat;
@SuppressWarnings("unused")
public class QuickstepProcessInitializer extends MainProcessInitializer {
private static final String TAG = "QuickstepProcessInitializer";
+ private static final int HEAP_LIMIT_MB = 250;
public QuickstepProcessInitializer(Context context) { }
@Override
protected void init(Context context) {
+ if (Utilities.IS_DEBUG_DEVICE) {
+ try {
+ // Trigger a heap dump if the PSS reaches beyond the target heap limit
+ final ActivityManager am = context.getSystemService(ActivityManager.class);
+ am.setWatchHeapLimit(HEAP_LIMIT_MB * 1024 * 1024);
+ } catch (SecurityException e) {
+ // Do nothing
+ }
+ }
+
// 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.
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 353837312..f27ba8538 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -84,7 +84,7 @@ public class RecentTasksList extends TaskStackChangeListener {
final int requestLoadId = mChangeId;
Runnable resultCallback = callback == null
? () -> { }
- : () -> callback.accept(mTasks);
+ : () -> callback.accept(copyOf(mTasks));
if (mLastLoadedId == mChangeId && (!mLastLoadHadKeysOnly || loadKeysOnly)) {
// The list is up to date, callback with the same list
@@ -183,4 +183,14 @@ public class RecentTasksList extends TaskStackChangeListener {
return allTasks;
}
+
+ private ArrayList<Task> copyOf(ArrayList<Task> tasks) {
+ ArrayList<Task> newTasks = new ArrayList<>();
+ for (int i = 0; i < tasks.size(); i++) {
+ Task t = tasks.get(i);
+ newTasks.add(new Task(t.key, t.colorPrimary, t.colorBackground, t.isDockable,
+ t.isLocked, t.taskDescription, t.topActivity));
+ }
+ return newTasks;
+ }
} \ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index c8aed8191..050bdff09 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -110,7 +110,7 @@ public class LayoutUtils {
float y = insets.top + Math.max(topIconMargin,
(launcherVisibleHeight - extraVerticalSpace - outHeight) / 2);
outRect.set(Math.round(x), Math.round(y),
- Math.round(x + outWidth), Math.round(y + outHeight));
+ Math.round(x) + Math.round(outWidth), Math.round(y) + Math.round(outHeight));
}
public static int getShelfTrackingDistance(Context context, DeviceProfile dp) {
diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
index 36521e5cc..b6ddb5fd1 100644
--- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
+++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
@@ -18,6 +18,7 @@ package com.android.quickstep.views;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
@@ -29,6 +30,7 @@ import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.Path.Op;
import android.util.AttributeSet;
+import android.view.animation.Interpolator;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
@@ -69,6 +71,9 @@ public class ShelfScrimView extends ScrimView implements NavigationModeChangeLis
private int mMidAlpha;
private float mMidProgress;
+ private Interpolator mBeforeMidProgressColorInterpolator = ACCEL;
+ private Interpolator mAfterMidProgressColorInterpolator = ACCEL;
+
private float mShiftRange;
private final float mShelfOffset;
@@ -120,6 +125,15 @@ public class ShelfScrimView extends ScrimView implements NavigationModeChangeLis
@Override
public void onNavigationModeChanged(Mode newMode) {
mSysUINavigationMode = newMode;
+ // Note that these interpolators are inverted because progress goes 1 to 0.
+ if (mSysUINavigationMode == Mode.NO_BUTTON) {
+ // Show the shelf more quickly before reaching overview progress.
+ mBeforeMidProgressColorInterpolator = ACCEL_2;
+ mAfterMidProgressColorInterpolator = ACCEL;
+ } else {
+ mBeforeMidProgressColorInterpolator = ACCEL;
+ mAfterMidProgressColorInterpolator = Interpolators.clampToProgress(ACCEL, 0.5f, 1f);
+ }
}
@Override
@@ -171,7 +185,7 @@ public class ShelfScrimView extends ScrimView implements NavigationModeChangeLis
mRemainingScreenColor = 0;
int alpha = Math.round(Utilities.mapToRange(
- mProgress, mMidProgress, 1, mMidAlpha, 0, ACCEL));
+ mProgress, mMidProgress, 1, mMidAlpha, 0, mBeforeMidProgressColorInterpolator));
mShelfColor = setColorAlphaBound(mEndScrim, alpha);
} else {
mDragHandleOffset += mShiftRange * (mMidProgress - mProgress);
@@ -179,7 +193,7 @@ public class ShelfScrimView extends ScrimView implements NavigationModeChangeLis
// Note that these ranges and interpolators are inverted because progress goes 1 to 0.
int alpha = Math.round(
Utilities.mapToRange(mProgress, (float) 0, mMidProgress, (float) mEndAlpha,
- (float) mMidAlpha, Interpolators.clampToProgress(ACCEL, 0.5f, 1f)));
+ (float) mMidAlpha, mAfterMidProgressColorInterpolator));
mShelfColor = setColorAlphaBound(mEndScrim, alpha);
int remainingScrimAlpha = Math.round(
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 013591171..e5f949b88 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -43,10 +43,12 @@ import androidx.test.uiautomator.Until;
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.testcomponent.TestCommandReceiver;
+import com.android.launcher3.util.rule.FailureWatcher;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.model.Statement;
@@ -62,10 +64,14 @@ public class FallbackRecentsTest {
private final LauncherInstrumentation mLauncher;
private final ActivityInfo mOtherLauncherActivity;
- @Rule public final TestRule mDisableHeadsUpNotification = disableHeadsUpNotification();
- @Rule public final TestRule mQuickstepOnOffExecutor;
+ @Rule
+ public final TestRule mDisableHeadsUpNotification = disableHeadsUpNotification();
- @Rule public final TestRule mSetLauncherCommand;
+ @Rule
+ public final TestRule mSetLauncherCommand;
+
+ @Rule
+ public final TestRule mOrderSensitiveRules;
public FallbackRecentsTest() throws RemoteException {
Instrumentation instrumentation = getInstrumentation();
@@ -74,7 +80,10 @@ public class FallbackRecentsTest {
mDevice.setOrientationNatural();
mLauncher = new LauncherInstrumentation(instrumentation);
- mQuickstepOnOffExecutor = new NavigationModeSwitchRule(mLauncher);
+ mOrderSensitiveRules = RuleChain.
+ outerRule(new NavigationModeSwitchRule(mLauncher)).
+ around(new FailureWatcher(mDevice));
+
mOtherLauncherActivity = context.getPackageManager().queryIntentActivities(
getHomeIntentInPackage(context),
MATCH_DISABLED_COMPONENTS).get(0).activityInfo;
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index 90763b871..3b35c86af 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -159,13 +159,20 @@ public class NavigationModeSwitchRule implements TestRule {
}
for (int i = 0; i != 100; ++i) {
- if (mLauncher.getNavigationModel() == expectedMode) {
- Thread.sleep(5000);
- return;
- }
+ if (mLauncher.getNavigationModel() == expectedMode) break;
+ Thread.sleep(100);
+ }
+ Assert.assertTrue("Couldn't switch to " + overlayPackage,
+ mLauncher.getNavigationModel() == expectedMode);
+
+ for (int i = 0; i != 100; ++i) {
+ if (mLauncher.getNavigationModeMismatchError() == null) break;
Thread.sleep(100);
}
- Assert.fail("Couldn't switch to " + overlayPackage);
+ final String error = mLauncher.getNavigationModeMismatchError();
+ Assert.assertTrue("Switching nav mode: " + error, error == null);
+
+ Thread.sleep(5000);
}
private void setOverlayPackageEnabled(String overlayPackage, boolean enable)
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index f02859f46..9e3bf2f56 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -208,7 +208,7 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest {
@Test
@NavigationModeSwitch
- @PortraitLandscape
+// @PortraitLandscape
public void testBackground() throws Exception {
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
final Background background = mLauncher.getBackground();
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 7085c6052..1619e3645 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -43,6 +43,7 @@ import android.view.ViewDebug;
import android.widget.TextView;
import com.android.launcher3.Launcher.OnResumeCallback;
+import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.graphics.DrawableFactory;
@@ -227,6 +228,18 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
applyFromWorkspaceItem(info, false);
}
+ @Override
+ public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
+ if (delegate instanceof LauncherAccessibilityDelegate) {
+ super.setAccessibilityDelegate(delegate);
+ } else {
+ // NO-OP
+ // Workaround for b/129745295 where RecyclerView is setting our Accessibility
+ // delegate incorrectly. There are no cases when we shouldn't be using the
+ // LauncherAccessibilityDelegate for BubbleTextView.
+ }
+ }
+
public void applyFromWorkspaceItem(WorkspaceItemInfo info, boolean promiseStateChanged) {
applyIconAndLabel(info);
setTag(info);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 80ea78f19..d9af4da8e 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -244,7 +244,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
@Thunk boolean mWorkspaceLoading = true;
- private OnResumeCallback mOnResumeCallback;
+ private ArrayList<OnResumeCallback> mOnResumeCallbacks = new ArrayList<>();
private ViewOnDrawExecutor mPendingExecutor;
@@ -430,6 +430,10 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
super.onConfigurationChanged(newConfig);
}
+ public void reload() {
+ onIdpChanged(mDeviceProfile.inv);
+ }
+
private boolean supportsFakeLandscapeUI() {
return FeatureFlags.FAKE_LANDSCAPE_UI.get() && !mRotationHelper.homeScreenCanRotate();
}
@@ -865,6 +869,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
@Override
protected void onStop() {
super.onStop();
+
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onStop();
}
@@ -947,7 +952,10 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
mHandler.removeCallbacks(mHandleDeferredResume);
Utilities.postAsyncCallback(mHandler, mHandleDeferredResume);
- setOnResumeCallback(null);
+ for (OnResumeCallback cb : mOnResumeCallbacks) {
+ cb.onLauncherResume();
+ }
+ mOnResumeCallbacks.clear();
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onResume();
@@ -1801,6 +1809,16 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
android.util.Log.d(TestProtocol.NO_START_TAG,
"startActivitySafely outer");
}
+
+ if (!hasBeenResumed()) {
+ // Workaround an issue where the WM launch animation is clobbered when finishing the
+ // recents animation into launcher. Defer launching the activity until Launcher is
+ // next resumed.
+ addOnResumeCallback(() -> startActivitySafely(v, intent, item, sourceContainer));
+ UiFactory.clearSwipeSharedState(true /* finishAnimation */);
+ return true;
+ }
+
boolean success = super.startActivitySafely(v, intent, item, sourceContainer);
if (success && v instanceof BubbleTextView) {
// This is set to the view that launched the activity that navigated the user away
@@ -1809,7 +1827,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
// state when we return to launcher.
BubbleTextView btv = (BubbleTextView) v;
btv.setStayPressed(true);
- setOnResumeCallback(btv);
+ addOnResumeCallback(btv);
}
return success;
}
@@ -1857,11 +1875,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
return result;
}
- public void setOnResumeCallback(OnResumeCallback callback) {
- if (mOnResumeCallback != null) {
- mOnResumeCallback.onLauncherResume();
- }
- mOnResumeCallback = callback;
+ public void addOnResumeCallback(OnResumeCallback callback) {
+ mOnResumeCallbacks.add(callback);
}
/**
diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java
index 04f2b5276..74362ed5a 100644
--- a/src/com/android/launcher3/LauncherAnimUtils.java
+++ b/src/com/android/launcher3/LauncherAnimUtils.java
@@ -17,6 +17,7 @@
package com.android.launcher3;
import android.graphics.drawable.Drawable;
+import android.util.FloatProperty;
import android.util.Property;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
@@ -47,15 +48,15 @@ public class LauncherAnimUtils {
}
};
- public static final Property<View, Float> SCALE_PROPERTY =
- new Property<View, Float>(Float.class, "scale") {
+ public static final FloatProperty<View> SCALE_PROPERTY =
+ new FloatProperty<View>("scale") {
@Override
public Float get(View view) {
return view.getScaleX();
}
@Override
- public void set(View view, Float scale) {
+ public void setValue(View view, float scale) {
view.setScaleX(scale);
view.setScaleY(scale);
}
@@ -92,23 +93,31 @@ public class LauncherAnimUtils {
}
};
- public static class ViewProgressProperty implements ProgressInterface {
- View mView;
- Property<View, Float> mProperty;
-
- public ViewProgressProperty(View view, Property<View, Float> property) {
- mView = view;
- mProperty = property;
- }
-
- @Override
- public void setProgress(float progress) {
- mProperty.set(mView, progress);
- }
-
- @Override
- public float getProgress() {
- return mProperty.get(mView);
- }
- }
+ public static final FloatProperty<View> VIEW_TRANSLATE_X =
+ View.TRANSLATION_X instanceof FloatProperty ? (FloatProperty) View.TRANSLATION_X
+ : new FloatProperty<View>("translateX") {
+ @Override
+ public void setValue(View view, float v) {
+ view.setTranslationX(v);
+ }
+
+ @Override
+ public Float get(View view) {
+ return view.getTranslationX();
+ }
+ };
+
+ public static final FloatProperty<View> VIEW_TRANSLATE_Y =
+ View.TRANSLATION_Y instanceof FloatProperty ? (FloatProperty) View.TRANSLATION_Y
+ : new FloatProperty<View>("translateY") {
+ @Override
+ public void setValue(View view, float v) {
+ view.setTranslationY(v);
+ }
+
+ @Override
+ public Float get(View view) {
+ return view.getTranslationY();
+ }
+ };
}
diff --git a/src/com/android/launcher3/LauncherAppTransitionManager.java b/src/com/android/launcher3/LauncherAppTransitionManager.java
index 4bddc6a4e..c55c120a6 100644
--- a/src/com/android/launcher3/LauncherAppTransitionManager.java
+++ b/src/com/android/launcher3/LauncherAppTransitionManager.java
@@ -17,6 +17,7 @@
package com.android.launcher3;
+import android.animation.Animator;
import android.app.ActivityOptions;
import android.content.Context;
import android.graphics.Rect;
@@ -55,4 +56,15 @@ public class LauncherAppTransitionManager implements ResourceBasedOverride {
public boolean supportsAdaptiveIconAnimation() {
return false;
}
+
+ /**
+ * Number of animations which run on state properties.
+ */
+ public int getStateElementAnimationsCount() {
+ return 0;
+ }
+
+ public Animator createStateElementAnimation(int index, float... values) {
+ throw new RuntimeException("Unknown gesture animation " + index);
+ }
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index ac392a6e6..d79f5d5a9 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -301,7 +301,8 @@ public class LauncherModel extends BroadcastReceiver
}
}
} else if (IS_DOGFOOD_BUILD && ACTION_FORCE_ROLOAD.equals(action)) {
- forceReload();
+ Launcher l = (Launcher) getCallback();
+ l.reload();
}
}
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 148064889..dcfd272b4 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -17,7 +17,18 @@ package com.android.launcher3;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;
+import static android.view.View.VISIBLE;
import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
+
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_X;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
+import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.anim.Interpolators.DEACCEL;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
+import static com.android.launcher3.anim.Interpolators.clampToProgress;
import static com.android.launcher3.testing.TestProtocol.ALL_APPS_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.BACKGROUND_APP_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.NORMAL_STATE_ORDINAL;
@@ -30,11 +41,11 @@ import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
import android.view.animation.Interpolator;
+import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.states.SpringLoadedState;
import com.android.launcher3.uioverrides.UiFactory;
import com.android.launcher3.uioverrides.states.AllAppsState;
import com.android.launcher3.uioverrides.states.OverviewState;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import java.util.Arrays;
@@ -272,6 +283,46 @@ public class LauncherState {
}
}
+ /**
+ * Prepares for a non-user controlled animation from fromState to this state. Preparations
+ * include:
+ * - Setting interpolators for various animations included in the state transition.
+ * - Setting some start values (e.g. scale) for views that are hidden but about to be shown.
+ */
+ public void prepareForAtomicAnimation(Launcher launcher, LauncherState fromState,
+ AnimatorSetBuilder builder) {
+ if (this == NORMAL && fromState == OVERVIEW) {
+ builder.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
+ builder.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
+ builder.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
+ builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL);
+ builder.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7);
+ Workspace workspace = launcher.getWorkspace();
+
+ // Start from a higher workspace scale, but only if we're invisible so we don't jump.
+ boolean isWorkspaceVisible = workspace.getVisibility() == VISIBLE;
+ if (isWorkspaceVisible) {
+ CellLayout currentChild = (CellLayout) workspace.getChildAt(
+ workspace.getCurrentPage());
+ isWorkspaceVisible = currentChild.getVisibility() == VISIBLE
+ && currentChild.getShortcutsAndWidgets().getAlpha() > 0;
+ }
+ if (!isWorkspaceVisible) {
+ workspace.setScaleX(0.92f);
+ workspace.setScaleY(0.92f);
+ }
+ Hotseat hotseat = launcher.getHotseat();
+ boolean isHotseatVisible = hotseat.getVisibility() == VISIBLE && hotseat.getAlpha() > 0;
+ if (!isHotseatVisible) {
+ hotseat.setScaleX(0.92f);
+ hotseat.setScaleY(0.92f);
+ }
+ } else if (this == NORMAL && fromState == OVERVIEW_PEEK) {
+ // Keep fully visible until the very end (when overview is offscreen) to make invisible.
+ builder.setInterpolator(ANIM_OVERVIEW_FADE, t -> t < 1 ? 0 : 1);
+ }
+ }
+
protected static void dispatchWindowStateChanged(Launcher launcher) {
launcher.getWindow().getDecorView().sendAccessibilityEvent(TYPE_WINDOW_STATE_CHANGED);
}
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index 8b03691c8..2c8c20845 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -16,23 +16,7 @@
package com.android.launcher3;
-import static android.view.View.VISIBLE;
-
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.LauncherState.OVERVIEW_PEEK;
-import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
-import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
-import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATE_X;
-import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
-import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
-import static com.android.launcher3.anim.Interpolators.ACCEL;
-import static com.android.launcher3.anim.Interpolators.DEACCEL;
-import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
-import static com.android.launcher3.anim.Interpolators.INSTANT;
-import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
-import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7;
-import static com.android.launcher3.anim.Interpolators.clampToProgress;
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
import android.animation.Animator;
@@ -42,8 +26,6 @@ import android.os.Handler;
import android.os.Looper;
import android.util.Log;
-import androidx.annotation.IntDef;
-
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
@@ -58,6 +40,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import androidx.annotation.IntDef;
+
/**
* TODO: figure out what kind of tests we can write for this
*
@@ -127,6 +111,9 @@ public class LauncherStateManager {
private final Launcher mLauncher;
private final ArrayList<StateListener> mListeners = new ArrayList<>();
+ // Animators which are run on properties also controlled by state animations.
+ private Animator[] mStateElementAnimators;
+
private StateHandler[] mStateHandlers;
private LauncherState mState = NORMAL;
@@ -223,13 +210,18 @@ public class LauncherStateManager {
}
public void reapplyState(boolean cancelCurrentAnimation) {
+ boolean wasInAnimation = mConfig.mCurrentAnimation != null;
if (cancelCurrentAnimation) {
+ cancelAllStateElementAnimation();
cancelAnimation();
}
if (mConfig.mCurrentAnimation == null) {
for (StateHandler handler : getStateHandlers()) {
handler.setState(mState);
}
+ if (wasInAnimation) {
+ onStateTransitionEnd(mState);
+ }
}
}
@@ -262,6 +254,7 @@ public class LauncherStateManager {
mConfig.reset();
if (!animated) {
+ cancelAllStateElementAnimation();
onStateTransitionStart(state);
for (StateHandler handler : getStateHandlers()) {
handler.setState(state);
@@ -310,47 +303,7 @@ public class LauncherStateManager {
*/
public void prepareForAtomicAnimation(LauncherState fromState, LauncherState toState,
AnimatorSetBuilder builder) {
- if (fromState == NORMAL && toState == OVERVIEW) {
- builder.setInterpolator(ANIM_WORKSPACE_SCALE, OVERSHOOT_1_2);
- builder.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
- builder.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
- builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_7);
- builder.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2);
-
- // Start from a higher overview scale, but only if we're invisible so we don't jump.
- UiFactory.prepareToShowOverview(mLauncher);
- } else if (fromState == OVERVIEW && toState == NORMAL) {
- builder.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
- builder.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
- builder.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
- builder.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL);
- builder.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7);
- Workspace workspace = mLauncher.getWorkspace();
-
- // Start from a higher workspace scale, but only if we're invisible so we don't jump.
- boolean isWorkspaceVisible = workspace.getVisibility() == VISIBLE;
- if (isWorkspaceVisible) {
- CellLayout currentChild = (CellLayout) workspace.getChildAt(
- workspace.getCurrentPage());
- isWorkspaceVisible = currentChild.getVisibility() == VISIBLE
- && currentChild.getShortcutsAndWidgets().getAlpha() > 0;
- }
- if (!isWorkspaceVisible) {
- workspace.setScaleX(0.92f);
- workspace.setScaleY(0.92f);
- }
- Hotseat hotseat = workspace.getHotseat();
- boolean isHotseatVisible = hotseat.getVisibility() == VISIBLE && hotseat.getAlpha() > 0;
- if (!isHotseatVisible) {
- hotseat.setScaleX(0.92f);
- hotseat.setScaleY(0.92f);
- }
- } else if (fromState == NORMAL && toState == OVERVIEW_PEEK) {
- builder.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT);
- } else if (fromState == OVERVIEW_PEEK && toState == NORMAL) {
- // Keep fully visible until the very end (when overview is offscreen) to make invisible.
- builder.setInterpolator(ANIM_OVERVIEW_FADE, t -> t < 1 ? 0 : 1);
- }
+ toState.prepareForAtomicAnimation(mLauncher, fromState, builder);
}
public AnimatorSet createAtomicAnimation(LauncherState fromState, LauncherState toState,
@@ -573,6 +526,47 @@ public class LauncherStateManager {
mConfig.setAnimation(anim, null);
}
+ private void cancelAllStateElementAnimation() {
+ if (mStateElementAnimators == null) {
+ return;
+ }
+
+ for (Animator animator : mStateElementAnimators) {
+ if (animator != null) {
+ animator.cancel();
+ }
+ }
+ }
+
+ /**
+ * Cancels a currently running gesture animation
+ */
+ public void cancelStateElementAnimation(int index) {
+ if (mStateElementAnimators == null) {
+ return;
+ }
+ if (mStateElementAnimators[index] != null) {
+ mStateElementAnimators[index].cancel();
+ }
+ }
+
+ public Animator createStateElementAnimation(int index, float... values) {
+ cancelStateElementAnimation(index);
+ LauncherAppTransitionManager latm = mLauncher.getAppTransitionManager();
+ if (mStateElementAnimators == null) {
+ mStateElementAnimators = new Animator[latm.getStateElementAnimationsCount()];
+ }
+ Animator anim = latm.createStateElementAnimation(index, values);
+ mStateElementAnimators[index] = anim;
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mStateElementAnimators[index] = null;
+ }
+ });
+ return anim;
+ }
+
private void clearCurrentAnimation() {
if (mConfig.mCurrentAnimation != null) {
mConfig.mCurrentAnimation.removeListener(mConfig);
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 80e17c9ff..2eeb132bb 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -16,6 +16,7 @@
package com.android.launcher3;
+import static com.android.launcher3.Utilities.shouldDisableGestures;
import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
import static com.android.launcher3.compat.AccessibilityManagerCompat.isObservedEventType;
import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
@@ -844,10 +845,11 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
* If we return true, onTouchEvent will be called and we do the actual
* scrolling there.
*/
- acquireVelocityTrackerAndAddMovement(ev);
// Skip touch handling if there are no pages to swipe
- if (getChildCount() <= 0) return super.onInterceptTouchEvent(ev);
+ if (getChildCount() <= 0 || shouldDisableGestures(ev)) return false;
+
+ acquireVelocityTrackerAndAddMovement(ev);
/*
* Shortcut the most recurring case: the user is in the dragging
@@ -1093,7 +1095,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
@Override
public boolean onTouchEvent(MotionEvent ev) {
// Skip touch handling if there are no pages to swipe
- if (getChildCount() <= 0) return false;
+ if (getChildCount() <= 0 || shouldDisableGestures(ev)) return false;
acquireVelocityTrackerAndAddMovement(ev);
@@ -1204,6 +1206,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
if (((initialScrollX >= mMaxScrollX) && (isVelocityXLeft || !isFling)) ||
((initialScrollX <= mMinScrollX) && (!isVelocityXLeft || !isFling))) {
mScroller.springBack(getScrollX(), mMinScrollX, mMaxScrollX);
+ mNextPage = getPageNearestToCenterOfScreen();
} else {
mScroller.setInterpolator(mDefaultInterpolator);
mScroller.fling(initialScrollX, -velocityX,
diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java
index 0cf6e44c6..55cb6f214 100644
--- a/src/com/android/launcher3/SecondaryDropTarget.java
+++ b/src/com/android/launcher3/SecondaryDropTarget.java
@@ -179,7 +179,7 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
DeferredOnComplete deferred = (DeferredOnComplete) d.dragSource;
if (target != null) {
deferred.mPackageName = target.getPackageName();
- mLauncher.setOnResumeCallback(deferred);
+ mLauncher.addOnResumeCallback(deferred);
} else {
deferred.sendFailure();
}
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 7bdbb95f7..65aa3a775 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -128,6 +128,16 @@ public final class Utilities {
public static final int EDGE_NAV_BAR = 1 << 8;
/**
+ * Set on a motion event do disallow any gestures and only handle touch.
+ * See {@link MotionEvent#setEdgeFlags(int)}.
+ */
+ public static final int FLAG_NO_GESTURES = 1 << 9;
+
+ public static boolean shouldDisableGestures(MotionEvent ev) {
+ return (ev.getEdgeFlags() & FLAG_NO_GESTURES) == FLAG_NO_GESTURES;
+ }
+
+ /**
* Indicates if the device has a debug build. Should only be used to store additional info or
* add extra logging and not for changing the app behavior.
*/
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 065d06568..40c6b5f1b 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -19,6 +19,8 @@ package com.android.launcher3;
import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_SCALE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_HOTSEAT_TRANSLATE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE;
@@ -104,7 +106,10 @@ public class WorkspaceStateTransitionAnimation {
hotseat.setPivotY(workspacePivot[1]);
}
float hotseatScale = hotseatScaleAndTranslation.scale;
- propertySetter.setFloat(hotseat, SCALE_PROPERTY, hotseatScale, scaleInterpolator);
+ Interpolator hotseatScaleInterpolator = builder.getInterpolator(ANIM_HOTSEAT_SCALE,
+ scaleInterpolator);
+ propertySetter.setFloat(hotseat, SCALE_PROPERTY, hotseatScale,
+ hotseatScaleInterpolator);
float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, fadeInterpolator);
@@ -125,10 +130,12 @@ public class WorkspaceStateTransitionAnimation {
propertySetter.setFloat(mWorkspace, View.TRANSLATION_Y,
scaleAndTranslation.translationY, translationInterpolator);
+ Interpolator hotseatTranslationInterpolator = builder.getInterpolator(
+ ANIM_HOTSEAT_TRANSLATE, translationInterpolator);
propertySetter.setFloat(hotseat, View.TRANSLATION_Y,
- hotseatScaleAndTranslation.translationY, translationInterpolator);
+ hotseatScaleAndTranslation.translationY, hotseatTranslationInterpolator);
propertySetter.setFloat(mWorkspace.getPageIndicator(), View.TRANSLATION_Y,
- hotseatScaleAndTranslation.translationY, translationInterpolator);
+ hotseatScaleAndTranslation.translationY, hotseatTranslationInterpolator);
setScrim(propertySetter, state);
}
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index c62fc3d8f..4683893ea 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -2,6 +2,8 @@ package com.android.launcher3.allapps;
import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT;
import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA;
+import static com.android.launcher3.LauncherState.BACKGROUND_APP;
+import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.VERTICAL_SWIPE_INDICATOR;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE;
@@ -14,8 +16,8 @@ import static com.android.launcher3.util.SystemUiController.UI_STATE_ALL_APPS;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.util.FloatProperty;
import android.util.Log;
-import android.util.Property;
import android.view.animation.Interpolator;
import com.android.launcher3.DeviceProfile;
@@ -24,19 +26,15 @@ import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler;
-import com.android.launcher3.ProgressInterface;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorSetBuilder;
-import com.android.launcher3.anim.SpringObjectAnimator;
import com.android.launcher3.anim.PropertySetter;
+import com.android.launcher3.anim.SpringObjectAnimator;
import com.android.launcher3.testing.TestProtocol;
-import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ScrimView;
-import androidx.dynamicanimation.animation.FloatPropertyCompat;
-
/**
* Handles AllApps view transition.
* 1) Slides all apps view using direct manipulation
@@ -47,14 +45,13 @@ import androidx.dynamicanimation.animation.FloatPropertyCompat;
* If release velocity < THRES1, snap according to either top or bottom depending on whether it's
* closer to top or closer to the page indicator.
*/
-public class AllAppsTransitionController implements StateHandler, OnDeviceProfileChangeListener,
- ProgressInterface {
+public class AllAppsTransitionController implements StateHandler, OnDeviceProfileChangeListener {
- public static final float SPRING_DAMPING_RATIO = 0.9f;
- public static final float SPRING_STIFFNESS = 600f;
+ private static final float SPRING_DAMPING_RATIO = 0.9f;
+ private static final float SPRING_STIFFNESS = 600f;
- public static final Property<AllAppsTransitionController, Float> ALL_APPS_PROGRESS =
- new Property<AllAppsTransitionController, Float>(Float.class, "allAppsProgress") {
+ public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PROGRESS =
+ new FloatProperty<AllAppsTransitionController>("allAppsProgress") {
@Override
public Float get(AllAppsTransitionController controller) {
@@ -62,7 +59,7 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil
}
@Override
- public void set(AllAppsTransitionController controller, Float progress) {
+ public void setValue(AllAppsTransitionController controller, float progress) {
controller.setProgress(progress);
}
};
@@ -122,7 +119,6 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil
* @see #setState(LauncherState)
* @see #setStateWithAnimation(LauncherState, AnimatorSetBuilder, AnimationConfig)
*/
- @Override
public void setProgress(float progress) {
mProgress = progress;
mScrimView.setProgress(progress);
@@ -139,9 +135,17 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil
} else {
mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, 0);
}
+
+ if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
+ // Translate hotseat with the shelf until reaching overview.
+ float overviewProgress = OVERVIEW.getVerticalProgress(mLauncher);
+ if (progress >= overviewProgress || mLauncher.isInState(BACKGROUND_APP)) {
+ float hotseatShift = (progress - overviewProgress) * mShiftRange;
+ mLauncher.getHotseat().setTranslationY(hotseatShift);
+ }
+ }
}
- @Override
public float getProgress() {
return mProgress;
}
@@ -184,8 +188,7 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil
Interpolator interpolator = config.userControlled ? LINEAR : toState == OVERVIEW
? builder.getInterpolator(ANIM_OVERVIEW_SCALE, FAST_OUT_SLOW_IN)
: FAST_OUT_SLOW_IN;
- Animator anim = new SpringObjectAnimator<>(this, "allAppsSpringFromAATC", 1f / mShiftRange,
- SPRING_DAMPING_RATIO, SPRING_STIFFNESS, mProgress, targetProgress);
+ Animator anim = createSpringAnimation(mProgress, targetProgress);
anim.setDuration(config.duration);
anim.setInterpolator(builder.getInterpolator(ANIM_VERTICAL_PROGRESS, interpolator));
anim.addListener(getProgressAnimatorListener());
@@ -195,6 +198,11 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil
setAlphas(toState, config, builder);
}
+ public Animator createSpringAnimation(float... progressValues) {
+ return new SpringObjectAnimator<>(this, ALL_APPS_PROGRESS, 1f / mShiftRange,
+ SPRING_DAMPING_RATIO, SPRING_STIFFNESS, progressValues);
+ }
+
private void setAlphas(LauncherState toState, AnimationConfig config,
AnimatorSetBuilder builder) {
setAlphas(toState.getVisibleElements(mLauncher), config, builder);
diff --git a/src/com/android/launcher3/anim/AnimatorSetBuilder.java b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
index 5c498f8bb..52a896eda 100644
--- a/src/com/android/launcher3/anim/AnimatorSetBuilder.java
+++ b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
@@ -32,11 +32,13 @@ public class AnimatorSetBuilder {
public static final int ANIM_WORKSPACE_SCALE = 1;
public static final int ANIM_WORKSPACE_TRANSLATE = 2;
public static final int ANIM_WORKSPACE_FADE = 3;
- public static final int ANIM_OVERVIEW_SCALE = 4;
- public static final int ANIM_OVERVIEW_TRANSLATE_X = 5;
- public static final int ANIM_OVERVIEW_TRANSLATE_Y = 6;
- public static final int ANIM_OVERVIEW_FADE = 7;
- public static final int ANIM_ALL_APPS_FADE = 8;
+ public static final int ANIM_HOTSEAT_SCALE = 4;
+ public static final int ANIM_HOTSEAT_TRANSLATE = 5;
+ public static final int ANIM_OVERVIEW_SCALE = 6;
+ public static final int ANIM_OVERVIEW_TRANSLATE_X = 7;
+ public static final int ANIM_OVERVIEW_TRANSLATE_Y = 8;
+ public static final int ANIM_OVERVIEW_FADE = 9;
+ public static final int ANIM_ALL_APPS_FADE = 10;
public static final int FLAG_DONT_ANIMATE_OVERVIEW = 1 << 0;
diff --git a/src/com/android/launcher3/anim/SpringObjectAnimator.java b/src/com/android/launcher3/anim/SpringObjectAnimator.java
index b1395af89..395fed259 100644
--- a/src/com/android/launcher3/anim/SpringObjectAnimator.java
+++ b/src/com/android/launcher3/anim/SpringObjectAnimator.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.anim;
+import static androidx.dynamicanimation.animation.FloatPropertyCompat.createFloatPropertyCompat;
+
import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
import android.animation.Animator;
@@ -24,15 +26,12 @@ import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.os.Handler;
import android.os.Looper;
+import android.util.FloatProperty;
import android.util.Log;
-import android.util.Property;
-
-import com.android.launcher3.ProgressInterface;
import java.util.ArrayList;
import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener;
-import androidx.dynamicanimation.animation.FloatPropertyCompat;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
@@ -40,12 +39,11 @@ import androidx.dynamicanimation.animation.SpringForce;
* This animator allows for an object's property to be be controlled by an {@link ObjectAnimator} or
* a {@link SpringAnimation}. It extends ValueAnimator so it can be used in an AnimatorSet.
*/
-public class SpringObjectAnimator<T extends ProgressInterface> extends ValueAnimator {
+public class SpringObjectAnimator<T> extends ValueAnimator {
private static final String TAG = "SpringObjectAnimator";
private static boolean DEBUG = false;
- private T mObject;
private ObjectAnimator mObjectAnimator;
private float[] mValues;
@@ -57,29 +55,15 @@ public class SpringObjectAnimator<T extends ProgressInterface> extends ValueAnim
private boolean mAnimatorEnded = true;
private boolean mEnded = true;
- private static final FloatPropertyCompat<ProgressInterface> sFloatProperty =
- new FloatPropertyCompat<ProgressInterface>("springObjectAnimator") {
- @Override
- public float getValue(ProgressInterface object) {
- return object.getProgress();
- }
-
- @Override
- public void setValue(ProgressInterface object, float progress) {
- object.setProgress(progress);
- }
- };
-
- public SpringObjectAnimator(T object, String name, float minimumVisibleChange, float damping,
- float stiffness, float... values) {
- mObject = object;
- mSpring = new SpringAnimation(object, sFloatProperty);
+ public SpringObjectAnimator(T object, FloatProperty<T> property, float minimumVisibleChange,
+ float damping, float stiffness, float... values) {
+ mSpring = new SpringAnimation(object, createFloatPropertyCompat(property));
mSpring.setMinimumVisibleChange(minimumVisibleChange);
mSpring.setSpring(new SpringForce(0)
.setDampingRatio(damping)
.setStiffness(stiffness));
mSpring.setStartVelocity(0.01f);
- mProperty = new SpringProperty<T>(name, mSpring);
+ mProperty = new SpringProperty<>(property, mSpring);
mObjectAnimator = ObjectAnimator.ofFloat(object, mProperty, values);
mValues = values;
mListeners = new ArrayList<>();
@@ -285,13 +269,15 @@ public class SpringObjectAnimator<T extends ProgressInterface> extends ValueAnim
mObjectAnimator.setCurrentPlayTime(playTime);
}
- public static class SpringProperty<T extends ProgressInterface> extends Property<T, Float> {
+ public static class SpringProperty<T> extends FloatProperty<T> {
boolean useSpring = false;
+ final FloatProperty<T> mProperty;
final SpringAnimation mSpring;
- public SpringProperty(String name, SpringAnimation spring) {
- super(Float.class, name);
+ public SpringProperty(FloatProperty<T> property, SpringAnimation spring) {
+ super(property.getName());
+ mProperty = property;
mSpring = spring;
}
@@ -301,15 +287,15 @@ public class SpringObjectAnimator<T extends ProgressInterface> extends ValueAnim
@Override
public Float get(T object) {
- return object.getProgress();
+ return mProperty.get(object);
}
@Override
- public void set(T object, Float progress) {
+ public void setValue(T object, float progress) {
if (useSpring) {
mSpring.animateToFinalPosition(progress);
} else {
- object.setProgress(progress);
+ mProperty.setValue(object, progress);
}
}
}
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index 54d0db100..54efcb786 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -109,7 +109,7 @@ abstract class BaseFlags {
"Show chip hints and gleams on the overview screen");
public static final TogglableFlag FAKE_LANDSCAPE_UI = new TogglableFlag(
- "FAKE_LANDSCAPE_UI", true,
+ "FAKE_LANDSCAPE_UI", false,
"Rotate launcher UI instead of using transposed layout");
public static void initialize(Context context) {
diff --git a/src/com/android/launcher3/touch/TouchEventTranslator.java b/src/com/android/launcher3/touch/TouchEventTranslator.java
deleted file mode 100644
index 3fcda9084..000000000
--- a/src/com/android/launcher3/touch/TouchEventTranslator.java
+++ /dev/null
@@ -1,283 +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.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);
- }
-}
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index ac152dbff..c1ba78050 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -21,6 +21,7 @@ import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;
import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
+import static com.android.launcher3.Utilities.shouldDisableGestures;
import android.annotation.TargetApi;
import android.content.Context;
@@ -116,11 +117,25 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
mMultiValueAlpha = new MultiValueAlpha(this, alphaChannelCount);
}
+ /**
+ * Same as {@link #isEventOverView(View, MotionEvent, View)} where evView == this drag layer.
+ */
public boolean isEventOverView(View view, MotionEvent ev) {
getDescendantRectRelativeToSelf(view, mHitRect);
return mHitRect.contains((int) ev.getX(), (int) ev.getY());
}
+ /**
+ * Given a motion event in evView's coordinates, return whether the event is within another
+ * view's bounds.
+ */
+ public boolean isEventOverView(View view, MotionEvent ev, View evView) {
+ int[] xy = new int[] {(int) ev.getX(), (int) ev.getY()};
+ getDescendantCoordRelativeToSelf(evView, xy);
+ getDescendantRectRelativeToSelf(view, mHitRect);
+ return mHitRect.contains(xy[0], xy[1]);
+ }
+
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
@@ -137,6 +152,8 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
}
private TouchController findControllerToHandleTouch(MotionEvent ev) {
+ if (shouldDisableGestures(ev)) return null;
+
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
if (topView != null && topView.onControllerInterceptTouchEvent(ev)) {
return topView;
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
index e41916cf4..5cc64dc9a 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
@@ -69,8 +69,6 @@ public class UiFactory {
return false;
}
- public static void prepareToShowOverview(Launcher launcher) { }
-
public static void setBackButtonAlpha(Launcher launcher, float alpha, boolean animate) { }
@@ -95,4 +93,6 @@ public class UiFactory {
public static void resetPendingActivityResults(Launcher launcher, int requestCode) { }
+ public static void clearSwipeSharedState(boolean finishAnimation) {}
+
}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index abc93cd4b..4a0ca5c24 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -35,7 +35,6 @@ import android.content.pm.PackageManager;
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
-import android.view.Surface;
import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.By;
@@ -67,7 +66,6 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
-import org.junit.runners.model.Statement;
import java.io.IOException;
import java.lang.annotation.ElementType;
@@ -124,46 +122,10 @@ public abstract class AbstractLauncherUiTest {
protected @interface PortraitLandscape {
}
- @Rule
- public TestRule mPortraitLandscapeExecutor =
- (base, description) -> false && description.getAnnotation(PortraitLandscape.class)
- != null ? new Statement() {
- @Override
- public void evaluate() throws Throwable {
- try {
- // Create launcher activity if necessary and bring it to the front.
- mLauncher.pressHome();
- waitForLauncherCondition("Launcher activity wasn't created",
- launcher -> launcher != null);
-
- executeOnLauncher(launcher ->
- launcher.getRotationHelper().forceAllowRotationForTesting(true));
-
- evaluateInPortrait();
- evaluateInLandscape();
- } finally {
- mDevice.setOrientationNatural();
- executeOnLauncher(launcher ->
- launcher.getRotationHelper().forceAllowRotationForTesting(false));
- mLauncher.setExpectedRotation(Surface.ROTATION_0);
- }
- }
-
- private void evaluateInPortrait() throws Throwable {
- mDevice.setOrientationNatural();
- mLauncher.setExpectedRotation(Surface.ROTATION_0);
- base.evaluate();
- }
-
- private void evaluateInLandscape() throws Throwable {
- mDevice.setOrientationLeft();
- mLauncher.setExpectedRotation(Surface.ROTATION_90);
- base.evaluate();
- }
- } : base;
-
protected TestRule getRulesInsideActivityMonitor() {
- return new FailureWatcher(this);
+ return RuleChain.
+ outerRule(new PortraitLandscapeRunner(this)).
+ around(new FailureWatcher(mDevice));
}
@Rule
diff --git a/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java b/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java
index 48335a602..58c74cef1 100644
--- a/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java
+++ b/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java
@@ -25,26 +25,23 @@ import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.testcomponent.TestCommandReceiver;
import com.android.launcher3.util.LauncherLayoutBuilder;
import com.android.launcher3.util.rule.ShellCommandRule;
-import com.android.launcher3.widget.LauncherAppWidgetHostView;
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.OutputStreamWriter;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
-import androidx.test.uiautomator.UiSelector;
-
@MediumTest
@RunWith(AndroidJUnit4.class)
public class DefaultLayoutProviderTest extends AbstractLauncherUiTest {
@@ -71,7 +68,6 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest {
}
@Test
- // Convert test to TAPL; b/131116002
public void testCustomProfileLoaded_with_icon_on_hotseat() throws Exception {
writeLayout(new LauncherLayoutBuilder().atHotseat(0).putApp(SETTINGS_APP, SETTINGS_APP));
@@ -79,14 +75,10 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest {
mActivityMonitor.startLauncher();
waitForModelLoaded();
- // Verify widget present
- UiSelector selector = new UiSelector().packageName(mTargetContext.getPackageName())
- .description(getSettingsApp().getLabel().toString());
- assertTrue(mDevice.findObject(selector).waitForExists(DEFAULT_UI_TIMEOUT));
+ mLauncher.getWorkspace().getHotseatAppIcon(getSettingsApp().getLabel().toString());
}
@Test
- // Convert test to TAPL; b/131116002
public void testCustomProfileLoaded_with_widget() throws Exception {
// A non-restored widget with no config screen gets restored automatically.
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, false);
@@ -100,13 +92,11 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest {
waitForModelLoaded();
// Verify widget present
- UiSelector selector = new UiSelector().packageName(mTargetContext.getPackageName())
- .className(LauncherAppWidgetHostView.class).description(info.label);
- assertTrue(mDevice.findObject(selector).waitForExists(DEFAULT_UI_TIMEOUT));
+ assertTrue("Widget is not present",
+ mLauncher.getWorkspace().tryGetWidget(info.label, DEFAULT_UI_TIMEOUT) != null);
}
@Test
- // Convert test to TAPL; b/131116002
public void testCustomProfileLoaded_with_folder() throws Exception {
writeLayout(new LauncherLayoutBuilder().atHotseat(0).putFolder(android.R.string.copy)
.addApp(SETTINGS_APP, SETTINGS_APP)
@@ -118,10 +108,7 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest {
mActivityMonitor.startLauncher();
waitForModelLoaded();
- // Verify widget present
- UiSelector selector = new UiSelector().packageName(mTargetContext.getPackageName())
- .descriptionContains(mTargetContext.getString(android.R.string.copy));
- assertTrue(mDevice.findObject(selector).waitForExists(DEFAULT_UI_TIMEOUT));
+ mLauncher.getWorkspace().getHotseatFolder("Folder: Copy");
}
@After
diff --git a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
new file mode 100644
index 000000000..0f36292f9
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
@@ -0,0 +1,63 @@
+package com.android.launcher3.ui;
+
+import android.view.Surface;
+
+import com.android.launcher3.tapl.TestHelpers;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+class PortraitLandscapeRunner implements TestRule {
+ private AbstractLauncherUiTest mTest;
+
+ public PortraitLandscapeRunner(AbstractLauncherUiTest test) {
+ mTest = test;
+ }
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ if (!TestHelpers.isInLauncherProcess() ||
+ description.getAnnotation(AbstractLauncherUiTest.PortraitLandscape.class) == null) {
+ return base;
+ }
+
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ try {
+ mTest.mDevice.pressHome();
+ mTest.waitForLauncherCondition("Launcher activity wasn't created",
+ launcher -> launcher != null);
+
+ mTest.executeOnLauncher(launcher ->
+ launcher.getRotationHelper().forceAllowRotationForTesting(
+ true));
+
+ evaluateInPortrait();
+ evaluateInLandscape();
+ } finally {
+ mTest.mDevice.setOrientationNatural();
+ mTest.executeOnLauncher(launcher ->
+ launcher.getRotationHelper().forceAllowRotationForTesting(
+ false));
+ mTest.mLauncher.setExpectedRotation(Surface.ROTATION_0);
+ }
+ }
+
+ private void evaluateInPortrait() throws Throwable {
+ mTest.mDevice.setOrientationNatural();
+ mTest.mLauncher.setExpectedRotation(Surface.ROTATION_0);
+ base.evaluate();
+ mTest.getDevice().pressHome();
+ }
+
+ private void evaluateInLandscape() throws Throwable {
+ mTest.mDevice.setOrientationLeft();
+ mTest.mLauncher.setExpectedRotation(Surface.ROTATION_90);
+ base.evaluate();
+ mTest.getDevice().pressHome();
+ }
+ };
+ }
+}
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index d171004fc..c3168f812 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -59,11 +59,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
public static void initialize(AbstractLauncherUiTest test) throws Exception {
test.clearLauncherData();
- if (TestHelpers.isInLauncherProcess()) {
- test.mActivityMonitor.returnToHome();
- } else {
- test.mDevice.pressHome();
- }
+ test.mDevice.pressHome();
test.waitForLauncherCondition("Launcher didn't start", launcher -> launcher != null);
test.waitForState("Launcher internal state didn't switch to Home", LauncherState.NORMAL);
test.waitForResumed("Launcher internal state is still Background");
@@ -279,8 +275,6 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
@Test
@PortraitLandscape
public void testLaunchMenuItem() throws Exception {
- if (!TestHelpers.isInLauncherProcess()) return;
-
final AllApps allApps = mLauncher.
getWorkspace().
switchToAllApps();
@@ -327,8 +321,6 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
@Test
@PortraitLandscape
public void testDragShortcut() throws Throwable {
- if (!TestHelpers.isInLauncherProcess()) return;
-
// 1. Open all apps and wait for load complete.
// 2. Find the app and long press it to show shortcuts.
// 3. Press icon center until shortcuts appear
diff --git a/tests/src/com/android/launcher3/ui/TestViewHelpers.java b/tests/src/com/android/launcher3/ui/TestViewHelpers.java
index a73bde011..d13d31952 100644
--- a/tests/src/com/android/launcher3/ui/TestViewHelpers.java
+++ b/tests/src/com/android/launcher3/ui/TestViewHelpers.java
@@ -54,21 +54,6 @@ public class TestViewHelpers {
return UiDevice.getInstance(getInstrumentation());
}
- /**
- * Opens all apps and returns the recycler view
- */
- public static UiObject2 openAllApps() {
- final UiDevice device = getDevice();
- device.waitForIdle();
- UiObject2 hotseat = device.wait(
- Until.findObject(getSelectorForId(R.id.hotseat)), 2500);
- Point start = hotseat.getVisibleCenter();
- int endY = (int) (device.getDisplayHeight() * 0.1f);
- // 100 px/step
- device.swipe(start.x, start.y, start.x, endY, (start.y - endY) / 100);
- return findViewById(R.id.apps_list_view);
- }
-
public static UiObject2 findViewById(int id) {
return getDevice().wait(Until.findObject(getSelectorForId(id)),
AbstractLauncherUiTest.DEFAULT_UI_TIMEOUT);
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index 874ff1995..d36126bb1 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -15,8 +15,9 @@
*/
package com.android.launcher3.ui.widget;
+import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID;
+
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -24,43 +25,37 @@ import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.ContentResolver;
-import android.content.ContentValues;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.launcher3.LauncherAppWidgetHost;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.Workspace;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.PackageInstallerCompat;
+import com.android.launcher3.tapl.Workspace;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.TestViewHelpers;
import com.android.launcher3.util.ContentWriter;
import com.android.launcher3.util.rule.ShellCommandRule;
-import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.launcher3.widget.PendingAddWidgetInfo;
-import com.android.launcher3.widget.PendingAppWidgetHostView;
import com.android.launcher3.widget.WidgetHostViewLoader;
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Set;
-import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
-import androidx.test.uiautomator.UiSelector;
-import java.util.concurrent.Callable;
-
/**
* Tests for bind widget flow.
*
@@ -131,16 +126,14 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
setupContents(item);
- // Since there is no widget to verify, just wait until the workspace is ready.
- // TODO: fix LauncherInstrumentation#LAUNCHER_PKG
- mLauncher.getWorkspace();
+ final Workspace workspace = mLauncher.getWorkspace();
// Item deleted from db
mCursor = mResolver.query(LauncherSettings.Favorites.getContentUri(item.id),
null, null, null, null, null);
assertEquals(0, mCursor.getCount());
// The view does not exist
- assertFalse(mDevice.findObject(new UiSelector().description(info.label)).exists());
+ assertTrue("Widget exists", workspace.tryGetWidget(info.label, 0) == null);
}
@Test
@@ -189,12 +182,8 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
setupContents(item);
- // Since there is no widget to verify, just wait until the workspace is ready.
- // TODO: fix LauncherInstrumentation#LAUNCHER_PKG
- mLauncher.getWorkspace();
- // The view does not exist
- assertFalse(mDevice.findObject(
- new UiSelector().className(PendingAppWidgetHostView.class)).exists());
+ assertTrue("Pending widget exists",
+ mLauncher.getWorkspace().tryGetPendingWidget(0) == null);
// Item deleted from db
mCursor = mResolver.query(LauncherSettings.Favorites.getContentUri(item.id),
null, null, null, null, null);
@@ -258,12 +247,12 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
* widget class is displayed on the homescreen.
*/
private void setupContents(LauncherAppWidgetInfo item) {
- int screenId = Workspace.FIRST_SCREEN_ID;
+ int screenId = FIRST_SCREEN_ID;
// Update the screen id counter for the provider.
LauncherSettings.Settings.call(mResolver, LauncherSettings.Settings.METHOD_NEW_SCREEN_ID);
- if (screenId > Workspace.FIRST_SCREEN_ID) {
- screenId = Workspace.FIRST_SCREEN_ID;
+ if (screenId > FIRST_SCREEN_ID) {
+ screenId = FIRST_SCREEN_ID;
}
// Insert the item
@@ -283,15 +272,13 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
}
private void verifyWidgetPresent(LauncherAppWidgetProviderInfo info) {
- UiSelector selector = new UiSelector().packageName(mTargetContext.getPackageName())
- .className(LauncherAppWidgetHostView.class).description(info.label);
- assertTrue(mDevice.findObject(selector).waitForExists(DEFAULT_UI_TIMEOUT));
+ assertTrue("Widget is not present",
+ mLauncher.getWorkspace().tryGetWidget(info.label, DEFAULT_UI_TIMEOUT) != null);
}
private void verifyPendingWidgetPresent() {
- UiSelector selector = new UiSelector().packageName(mTargetContext.getPackageName())
- .className(PendingAppWidgetHostView.class);
- assertTrue(mDevice.findObject(selector).waitForExists(DEFAULT_UI_TIMEOUT));
+ assertTrue("Pending widget is not present",
+ mLauncher.getWorkspace().tryGetPendingWidget(DEFAULT_UI_TIMEOUT) != null);
}
/**
diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
index a57d7bab8..6122daec2 100644
--- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.ui.widget;
+import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
+
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
@@ -26,9 +28,6 @@ import android.view.View;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.UiObject2;
-import androidx.test.uiautomator.Until;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppWidgetInfo;
@@ -37,15 +36,14 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace.ItemOperator;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.tapl.AddToHomeScreenPrompt;
import com.android.launcher3.testcomponent.AppWidgetNoConfig;
import com.android.launcher3.testcomponent.AppWidgetWithConfig;
import com.android.launcher3.testcomponent.RequestPinItemActivity;
import com.android.launcher3.ui.AbstractLauncherUiTest;
-import com.android.launcher3.ui.TestViewHelpers;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.rule.ShellCommandRule;
-import com.android.launcher3.widget.WidgetCell;
import org.junit.Before;
import org.junit.Rule;
@@ -80,15 +78,10 @@ public class RequestPinItemTest extends AbstractLauncherUiTest {
@Test
public void testPinWidgetNoConfig() throws Throwable {
- runTest("pinWidgetNoConfig", true, new ItemOperator() {
- @Override
- public boolean evaluate(ItemInfo info, View view) {
- return info instanceof LauncherAppWidgetInfo &&
- ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId &&
- ((LauncherAppWidgetInfo) info).providerName.getClassName()
- .equals(AppWidgetNoConfig.class.getName());
- }
- });
+ runTest("pinWidgetNoConfig", true, (info, view) -> info instanceof LauncherAppWidgetInfo &&
+ ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId &&
+ ((LauncherAppWidgetInfo) info).providerName.getClassName()
+ .equals(AppWidgetNoConfig.class.getName()));
}
@Test
@@ -98,28 +91,19 @@ public class RequestPinItemTest extends AbstractLauncherUiTest {
RequestPinItemActivity.class, "setRemoteViewColor").putExtra(
RequestPinItemActivity.EXTRA_PARAM + "0", Color.RED);
- runTest("pinWidgetNoConfig", true, new ItemOperator() {
- @Override
- public boolean evaluate(ItemInfo info, View view) {
- return info instanceof LauncherAppWidgetInfo &&
- ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId &&
- ((LauncherAppWidgetInfo) info).providerName.getClassName()
- .equals(AppWidgetNoConfig.class.getName());
- }
- }, command);
+ runTest("pinWidgetNoConfig", true, (info, view) -> info instanceof LauncherAppWidgetInfo &&
+ ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId &&
+ ((LauncherAppWidgetInfo) info).providerName.getClassName()
+ .equals(AppWidgetNoConfig.class.getName()), command);
}
@Test
public void testPinWidgetWithConfig() throws Throwable {
- runTest("pinWidgetWithConfig", true, new ItemOperator() {
- @Override
- public boolean evaluate(ItemInfo info, View view) {
- return info instanceof LauncherAppWidgetInfo &&
+ runTest("pinWidgetWithConfig", true,
+ (info, view) -> info instanceof LauncherAppWidgetInfo &&
((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId &&
((LauncherAppWidgetInfo) info).providerName.getClassName()
- .equals(AppWidgetWithConfig.class.getName());
- }
- });
+ .equals(AppWidgetWithConfig.class.getName()));
}
@Test
@@ -149,14 +133,14 @@ public class RequestPinItemTest extends AbstractLauncherUiTest {
clearHomescreen();
mActivityMonitor.startLauncher();
- // Open all apps and wait for load complete
- final UiObject2 appsContainer = TestViewHelpers.openAllApps();
- Wait.atMost(null, Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT);
-
// Open Pin item activity
BlockingBroadcastReceiver openMonitor = new BlockingBroadcastReceiver(
RequestPinItemActivity.class.getName());
- scrollAndFind(appsContainer, By.text("Test Pin Item")).click();
+ mLauncher.
+ getWorkspace().
+ switchToAllApps().
+ getAppIcon("Test Pin Item").
+ launch(getAppPackageName());
assertNotNull(openMonitor.blockingGetExtraIntent());
// Set callback
@@ -173,15 +157,11 @@ public class RequestPinItemTest extends AbstractLauncherUiTest {
// call the requested method to start the flow
mTargetContext.sendBroadcast(RequestPinItemActivity.getCommandIntent(
RequestPinItemActivity.class, activityMethod));
- UiObject2 widgetCell = mDevice.wait(
- Until.findObject(By.clazz(WidgetCell.class)), DEFAULT_ACTIVITY_TIMEOUT);
- assertNotNull(widgetCell);
+ final AddToHomeScreenPrompt addToHomeScreenPrompt = mLauncher.getAddToHomeScreenPrompt();
// Accept confirmation:
BlockingBroadcastReceiver resultReceiver = new BlockingBroadcastReceiver(mCallbackAction);
- mDevice.wait(Until.findObject(
- By.text(mLauncher.isAvd() ? "ADD AUTOMATICALLY" : "Add automatically")),
- DEFAULT_UI_TIMEOUT).click();
+ addToHomeScreenPrompt.addAutomatically();
Intent result = resultReceiver.blockingGetIntent();
assertNotNull(result);
mAppWidgetId = result.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
@@ -190,7 +170,7 @@ public class RequestPinItemTest extends AbstractLauncherUiTest {
}
// Go back to home
- mActivityMonitor.returnToHome();
+ mLauncher.pressHome();
Wait.atMost(null, new ItemSearchCondition(itemMatcher), DEFAULT_ACTIVITY_TIMEOUT);
}
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
index 09cc98de0..eef2f24ba 100644
--- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -4,7 +4,7 @@ import static androidx.test.InstrumentationRegistry.getInstrumentation;
import android.util.Log;
-import com.android.launcher3.ui.AbstractLauncherUiTest;
+import androidx.test.uiautomator.UiDevice;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
@@ -16,16 +16,16 @@ import java.io.IOException;
public class FailureWatcher extends TestWatcher {
private static final String TAG = "FailureWatcher";
private static int sScreenshotCount = 0;
- private AbstractLauncherUiTest mAbstractLauncherUiTest;
+ final private UiDevice mDevice;
- public FailureWatcher(AbstractLauncherUiTest abstractLauncherUiTest) {
- mAbstractLauncherUiTest = abstractLauncherUiTest;
+ public FailureWatcher(UiDevice device) {
+ mDevice = device;
}
private void dumpViewHierarchy() {
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
try {
- mAbstractLauncherUiTest.getDevice().dumpWindowHierarchy(stream);
+ mDevice.dumpWindowHierarchy(stream);
stream.flush();
stream.close();
for (String line : stream.toString().split("\\r?\\n")) {
@@ -38,7 +38,7 @@ public class FailureWatcher extends TestWatcher {
@Override
protected void failed(Throwable e, Description description) {
- if (mAbstractLauncherUiTest.getDevice() == null) return;
+ if (mDevice == null) return;
final String pathname = getInstrumentation().getTargetContext().
getFilesDir().getPath() + "/TaplTestScreenshot" + sScreenshotCount++ + ".png";
Log.e(TAG, "Failed test " + description.getMethodName() +
@@ -48,12 +48,12 @@ public class FailureWatcher extends TestWatcher {
dumpViewHierarchy();
try {
- final String dumpsysResult = mAbstractLauncherUiTest.getDevice().executeShellCommand(
+ final String dumpsysResult = mDevice.executeShellCommand(
"dumpsys activity service TouchInteractionService");
Log.d(TAG, "TouchInteractionService: " + dumpsysResult);
} catch (IOException ex) {
}
- mAbstractLauncherUiTest.getDevice().takeScreenshot(new File(pathname));
+ mDevice.takeScreenshot(new File(pathname));
}
}
diff --git a/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java b/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java
index 145c3c89e..2aba7a56d 100644
--- a/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java
+++ b/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java
@@ -72,11 +72,6 @@ public class LauncherActivityRule implements TestRule {
getInstrumentation().startActivitySync(getHomeIntentInPackage(getTargetContext()));
}
- public void returnToHome() {
- getTargetContext().startActivity(getHomeIntentInPackage(getTargetContext()));
- getInstrumentation().waitForIdleSync();
- }
-
private class MyStatement extends Statement implements ActivityLifecycleCallbacks {
private final Statement mBase;
diff --git a/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java b/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java
new file mode 100644
index 000000000..7f561a2af
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java
@@ -0,0 +1,41 @@
+/*
+ * 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.launcher3.tapl;
+
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiObject2;
+
+public class AddToHomeScreenPrompt {
+ private final LauncherInstrumentation mLauncher;
+ private final UiObject2 mWidgetCell;
+
+ AddToHomeScreenPrompt(LauncherInstrumentation launcher) {
+ mLauncher = launcher;
+ mWidgetCell = launcher.waitForLauncherObject(By.clazz(
+ "com.android.launcher3.widget.WidgetCell"));
+ mLauncher.assertNotNull("Can't find widget cell object", mWidgetCell);
+ }
+
+ public void addAutomatically() {
+ mLauncher.waitForObjectInContainer(
+ mWidgetCell.getParent().getParent().getParent().getParent(),
+ By.text(LauncherInstrumentation.isAvd()
+ ? "ADD AUTOMATICALLY"
+ : "Add automatically")).
+ click();
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index 6c4619235..c9eaf276d 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -87,16 +87,24 @@ public class Background extends LauncherInstrumentation.VisibleContainer {
}
case TWO_BUTTON: {
- final int centerX = mLauncher.getDevice().getDisplayWidth() / 2;
- final int startY = getSwipeStartY();
- final int swipeHeight = mLauncher.getTestInfo(getSwipeHeightRequestName()).
- getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
-
- mLauncher.swipeToState(
- centerX, startY, centerX,
- startY - swipeHeight - mLauncher.getTouchSlop(),
- 10,
- expectedState);
+ final int startX;
+ final int startY;
+ final int endX;
+ final int endY;
+ final int swipeLength = mLauncher.getTestInfo(getSwipeHeightRequestName()).
+ getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD) + mLauncher.getTouchSlop();
+
+ if (mLauncher.getDevice().isNaturalOrientation()) {
+ startX = endX = mLauncher.getDevice().getDisplayWidth() / 2;
+ startY = getSwipeStartY();
+ endY = startY - swipeLength;
+ } else {
+ startX = getSwipeStartX();
+ endX = startX - swipeLength;
+ startY = endY = mLauncher.getDevice().getDisplayHeight() / 2;
+ }
+
+ mLauncher.swipeToState(startX, startY, endX, endY, 10, expectedState);
break;
}
@@ -111,6 +119,10 @@ public class Background extends LauncherInstrumentation.VisibleContainer {
return TestProtocol.REQUEST_BACKGROUND_TO_OVERVIEW_SWIPE_HEIGHT;
}
+ protected int getSwipeStartX() {
+ return mLauncher.getRealDisplaySize().x - 1;
+ }
+
protected int getSwipeStartY() {
return mLauncher.getRealDisplaySize().y - 1;
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Folder.java b/tests/tapl/com/android/launcher3/tapl/Folder.java
new file mode 100644
index 000000000..6e6734d81
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/Folder.java
@@ -0,0 +1,35 @@
+/*
+ * 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.launcher3.tapl;
+
+import android.widget.FrameLayout;
+
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiObject2;
+
+/**
+ * App folder in workspace/
+ */
+public final class Folder {
+ Folder(LauncherInstrumentation launcher, UiObject2 icon) {
+ }
+
+ static BySelector getSelector(String folderName, LauncherInstrumentation launcher) {
+ return By.clazz(FrameLayout.class).desc(folderName).pkg(launcher.getLauncherPackageName());
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 2db9d0826..a7e633619 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -122,7 +122,7 @@ public final class LauncherInstrumentation {
private static final String APPS_RES_ID = "apps_view";
private static final String OVERVIEW_RES_ID = "overview_panel";
private static final String WIDGETS_RES_ID = "widgets_list_view";
- public static final int WAIT_TIME_MS = 10000;
+ public static final int WAIT_TIME_MS = 60000;
private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
private static WeakReference<VisibleContainer> sActiveContainer = new WeakReference<>(null);
@@ -315,25 +315,37 @@ public final class LauncherInstrumentation {
mExpectedRotation = expectedRotation;
}
- private UiObject2 verifyContainerType(ContainerType containerType) {
- assertEquals("Unexpected display rotation",
- mExpectedRotation, mDevice.getDisplayRotation());
+ public String getNavigationModeMismatchError() {
final NavigationModel navigationModel = getNavigationModel();
final boolean hasRecentsButton = hasSystemUiObject("recent_apps");
final boolean hasHomeButton = hasSystemUiObject("home");
- assertTrue("Presence of recents button doesn't match the interaction mode, mode="
- + navigationModel.name() + ", hasRecents=" + hasRecentsButton,
- (navigationModel == NavigationModel.THREE_BUTTON) == hasRecentsButton);
- assertTrue("Presence of home button doesn't match the interaction mode, mode="
- + navigationModel.name() + ", hasHome=" + hasHomeButton,
- (navigationModel != NavigationModel.ZERO_BUTTON) == hasHomeButton);
+ if ((navigationModel == NavigationModel.THREE_BUTTON) != hasRecentsButton) {
+ return "Presence of recents button doesn't match the interaction mode, mode="
+ + navigationModel.name() + ", hasRecents=" + hasRecentsButton;
+ }
+ if ((navigationModel != NavigationModel.ZERO_BUTTON) != hasHomeButton) {
+ return "Presence of home button doesn't match the interaction mode, mode="
+ + navigationModel.name() + ", hasHome=" + hasHomeButton;
+ }
+ return null;
+ }
+
+ private UiObject2 verifyContainerType(ContainerType containerType) {
+ assertEquals("Unexpected display rotation",
+ mExpectedRotation, mDevice.getDisplayRotation());
+ final String error = getNavigationModeMismatchError();
+ assertTrue(error, error == null);
log("verifyContainerType: " + containerType);
try (Closable c = addContextLayer(
"but the current state is not " + containerType.name())) {
switch (containerType) {
case WORKSPACE: {
- waitForLauncherObject(APPS_RES_ID);
+ if (mDevice.isNaturalOrientation()) {
+ waitForLauncherObject(APPS_RES_ID);
+ } else {
+ waitUntilGone(APPS_RES_ID);
+ }
waitUntilGone(OVERVIEW_RES_ID);
waitUntilGone(WIDGETS_RES_ID);
return waitForLauncherObject(WORKSPACE_RES_ID);
@@ -490,6 +502,13 @@ public final class LauncherInstrumentation {
}
}
+ @NonNull
+ public AddToHomeScreenPrompt getAddToHomeScreenPrompt() {
+ try (LauncherInstrumentation.Closable c = addContextLayer("want to get widget cell")) {
+ return new AddToHomeScreenPrompt(this);
+ }
+ }
+
/**
* Gets the Overview object if the current state is showing the overview panel. Fails if the
* launcher is not in that state.
@@ -504,17 +523,6 @@ public final class LauncherInstrumentation {
}
/**
- * Gets the Base overview object if either Launcher is in overview state or the fallback
- * overview activity is showing. Fails otherwise.
- *
- * @return BaseOverview object.
- */
- @NonNull
- public BaseOverview getBaseOverview() {
- return new BaseOverview(this);
- }
-
- /**
* Gets the All Apps object if the current state is showing the all apps panel opened by swiping
* from workspace. Fails if the launcher is not in that state. Please don't call this method if
* App Apps was opened by swiping up from Overview, as it won't fail and will return an
@@ -605,6 +613,16 @@ public final class LauncherInstrumentation {
}
@NonNull
+ UiObject2 waitForLauncherObject(BySelector selector) {
+ return waitForObjectBySelector(selector.pkg(getLauncherPackageName()));
+ }
+
+ @NonNull
+ UiObject2 tryWaitForLauncherObject(BySelector selector, long timeout) {
+ return tryWaitForObjectBySelector(selector.pkg(getLauncherPackageName()), timeout);
+ }
+
+ @NonNull
UiObject2 waitForFallbackLauncherObject(String resName) {
return waitForObjectBySelector(getFallbackLauncherObjectSelector(resName));
}
@@ -615,6 +633,10 @@ public final class LauncherInstrumentation {
return object;
}
+ private UiObject2 tryWaitForObjectBySelector(BySelector selector, long timeout) {
+ return mDevice.wait(Until.findObject(selector), timeout);
+ }
+
BySelector getLauncherObjectSelector(String resName) {
return By.res(getLauncherPackageName(), resName);
}
@@ -688,7 +710,7 @@ public final class LauncherInstrumentation {
// Inject a swipe gesture. Inject exactly 'steps' motion points, incrementing event time by a
// fixed interval each time.
- private void linearGesture(int startX, int startY, int endX, int endY, int steps) {
+ void linearGesture(int startX, int startY, int endX, int endY, int steps) {
final long downTime = SystemClock.uptimeMillis();
final Point start = new Point(startX, startY);
final Point end = new Point(endX, endY);
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 8b124641f..641c41353 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -16,7 +16,8 @@
package com.android.launcher3.tapl;
-import androidx.test.uiautomator.Direction;
+import android.graphics.Rect;
+
import androidx.test.uiautomator.UiObject2;
import androidx.test.uiautomator.Until;
@@ -26,7 +27,6 @@ import com.android.launcher3.testing.TestProtocol;
* A recent task in the overview panel carousel.
*/
public final class OverviewTask {
- static final int FLING_SPEED = 3000;
private static final long WAIT_TIME_MS = 60000;
private final LauncherInstrumentation mLauncher;
private final UiObject2 mTask;
@@ -51,7 +51,10 @@ public final class OverviewTask {
"want to dismiss a task")) {
verifyActiveContainer();
// Dismiss the task via flinging it up.
- mTask.fling(Direction.DOWN, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
+ final Rect taskBounds = mTask.getVisibleBounds();
+ final int centerX = taskBounds.centerX();
+ final int centerY = taskBounds.centerY();
+ mLauncher.linearGesture(centerX, centerY, centerX, 0, 10);
mLauncher.waitForIdle();
}
}
diff --git a/src/com/android/launcher3/ProgressInterface.java b/tests/tapl/com/android/launcher3/tapl/Widget.java
index 663d8ba5e..128789dbc 100644
--- a/src/com/android/launcher3/ProgressInterface.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widget.java
@@ -14,13 +14,11 @@
* limitations under the License.
*/
-package com.android.launcher3;
+package com.android.launcher3.tapl;
-/**
- * Progress is defined as a value with range [0, 1], and is specific to each implementor.
- * It is used when there is a transition from one state of the UI to another.
- */
-public interface ProgressInterface {
- void setProgress(float progress);
- float getProgress();
-} \ No newline at end of file
+import androidx.test.uiautomator.UiObject2;
+
+public class Widget {
+ Widget(LauncherInstrumentation launcher, UiObject2 widget) {
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 33754c125..b01b6f363 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -27,6 +27,7 @@ import android.view.MotionEvent;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.test.uiautomator.By;
import androidx.test.uiautomator.Direction;
import androidx.test.uiautomator.UiObject2;
@@ -142,11 +143,17 @@ public final class Workspace extends Home {
}
@NonNull
- private AppIcon getHotseatAppIcon(String appName) {
+ public AppIcon getHotseatAppIcon(String appName) {
return new AppIcon(mLauncher, mLauncher.getObjectInContainer(
mHotseat, AppIcon.getAppIconSelector(appName, mLauncher)));
}
+ @NonNull
+ public Folder getHotseatFolder(String appName) {
+ return new Folder(mLauncher, mLauncher.getObjectInContainer(
+ mHotseat, Folder.getSelector(appName, mLauncher)));
+ }
+
static void dragIconToWorkspace(
LauncherInstrumentation launcher, Launchable launchable, Point dest,
String longPressIndicator) {
@@ -213,6 +220,21 @@ public final class Workspace extends Home {
@Override
protected int getSwipeStartY() {
- return mLauncher.waitForLauncherObject("hotseat").getVisibleBounds().top;
+ return mLauncher.getRealDisplaySize().y - 1;
+ }
+
+ @Nullable
+ public Widget tryGetWidget(String label, long timeout) {
+ final UiObject2 widget = mLauncher.tryWaitForLauncherObject(
+ By.clazz("com.android.launcher3.widget.LauncherAppWidgetHostView").desc(label),
+ timeout);
+ return widget != null ? new Widget(mLauncher, widget) : null;
+ }
+
+ @Nullable
+ public Widget tryGetPendingWidget(long timeout) {
+ final UiObject2 widget = mLauncher.tryWaitForLauncherObject(
+ By.clazz("com.android.launcher3.widget.PendingAppWidgetHostView"), timeout);
+ return widget != null ? new Widget(mLauncher, widget) : null;
}
} \ No newline at end of file