Merge "Import translations. DO NOT MERGE" into ub-launcher3-rvc-dev
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index f1b71e8..f1db144 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -48,12 +48,16 @@
HotseatContainer hotseat = 2;
FolderContainer folder = 3;
AllAppsContainer all_apps_container = 4;
+ WidgetsContainer widgets_container = 5;
}
}
message AllAppsContainer {
}
+message WidgetsContainer {
+}
+
enum Origin {
UNKNOWN = 0;
DEFAULT_LAYOUT = 1; // icon automatically placed in workspace, folder, hotseat
diff --git a/quickstep/recents_ui_overrides/res/drawable/all_apps_edu_circle.xml b/quickstep/recents_ui_overrides/res/drawable/all_apps_edu_circle.xml
new file mode 100644
index 0000000..df7cd8e
--- /dev/null
+++ b/quickstep/recents_ui_overrides/res/drawable/all_apps_edu_circle.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+ <solid android:color="?android:colorAccent"/>
+ <size android:height="@dimen/swipe_edu_circle_size"
+ android:width="@dimen/swipe_edu_circle_size" />
+</shape>
\ No newline at end of file
diff --git a/quickstep/recents_ui_overrides/res/layout/all_apps_edu_view.xml b/quickstep/recents_ui_overrides/res/layout/all_apps_edu_view.xml
new file mode 100644
index 0000000..e7ef6e6
--- /dev/null
+++ b/quickstep/recents_ui_overrides/res/layout/all_apps_edu_view.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.android.quickstep.views.AllAppsEduView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="@dimen/swipe_edu_width"
+ android:layout_height="@dimen/swipe_edu_max_height"/>
diff --git a/quickstep/recents_ui_overrides/res/layout/fallback_recents_activity.xml b/quickstep/recents_ui_overrides/res/layout/fallback_recents_activity.xml
index ffe906c..7b3e378 100644
--- a/quickstep/recents_ui_overrides/res/layout/fallback_recents_activity.xml
+++ b/quickstep/recents_ui_overrides/res/layout/fallback_recents_activity.xml
@@ -18,6 +18,7 @@
android:id="@+id/drag_layer"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:clipChildren="false"
android:fitsSystemWindows="true">
<com.android.quickstep.fallback.FallbackRecentsView
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 fa0d3f3..8ff05f2 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
@@ -45,8 +45,10 @@
if (launcher.getDeviceProfile().isVerticalBarLayout()) {
return super.getVerticalProgress(launcher);
}
+ RecentsView recentsView = launcher.getOverviewPanel();
int transitionLength = LayoutUtils.getShelfTrackingDistance(launcher,
- launcher.getDeviceProfile());
+ launcher.getDeviceProfile(),
+ recentsView.getPagedOrientationHandler());
AllAppsTransitionController controller = launcher.getAllAppsController();
float scrollRange = Math.max(controller.getShiftRange(), 1);
float progressDelta = (transitionLength / scrollRange);
@@ -73,9 +75,11 @@
public ScaleAndTranslation getHotseatScaleAndTranslation(Launcher launcher) {
if ((getVisibleElements(launcher) & HOTSEAT_ICONS) != 0) {
// Translate hotseat offscreen if we show it in overview.
+ RecentsView recentsView = launcher.getOverviewPanel();
ScaleAndTranslation scaleAndTranslation = super.getHotseatScaleAndTranslation(launcher);
scaleAndTranslation.translationY += LayoutUtils.getShelfTrackingDistance(launcher,
- launcher.getDeviceProfile());
+ launcher.getDeviceProfile(),
+ recentsView.getPagedOrientationHandler());
return scaleAndTranslation;
}
return super.getHotseatScaleAndTranslation(launcher);
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 9b4e890..d174bfd 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
@@ -19,8 +19,7 @@
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
-import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
-import static com.android.quickstep.SysUINavigationMode.getMode;
+import static com.android.quickstep.SysUINavigationMode.hideShelfInTwoButtonLandscape;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import android.content.Context;
@@ -130,10 +129,8 @@
@Override
public int getVisibleElements(Launcher launcher) {
RecentsView recentsView = launcher.getOverviewPanel();
- boolean hideShelfTwoButtonLandscape = getMode(launcher) == TWO_BUTTONS &&
- !recentsView.getPagedOrientationHandler().isLayoutNaturalToLauncher();
if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(launcher) ||
- hideShelfTwoButtonLandscape) {
+ hideShelfInTwoButtonLandscape(launcher, recentsView.getPagedOrientationHandler())) {
return OVERVIEW_BUTTONS;
} else if (launcher.getDeviceProfile().isVerticalBarLayout()) {
return VERTICAL_SWIPE_INDICATOR | OVERVIEW_BUTTONS;
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index 11593a1..94c7771 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -49,64 +49,62 @@
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
-import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import android.animation.Animator;
import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.view.View;
import android.view.animation.Interpolator;
import com.android.launcher3.CellLayout;
import com.android.launcher3.Hotseat;
+import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherState.ScaleAndTranslation;
import com.android.launcher3.Workspace;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsTransitionController;
-import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.launcher3.statemanager.StateManager;
-import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.quickstep.SysUINavigationMode;
+import com.android.quickstep.util.RecentsAtomicAnimationFactory;
import com.android.quickstep.views.RecentsView;
/**
* Animation factory for quickstep specific transitions
*/
-public class QuickstepAtomicAnimationFactory extends AtomicAnimationFactory<LauncherState> {
+public class QuickstepAtomicAnimationFactory extends
+ RecentsAtomicAnimationFactory<Launcher, LauncherState> {
// Scale recents takes before animating in
private static final float RECENTS_PREPARE_SCALE = 1.33f;
- 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 static final int INDEX_PAUSE_TO_OVERVIEW_ANIM = 3;
- private static final int ANIM_COUNT = 4;
+ public static final int INDEX_SHELF_ANIM = RecentsAtomicAnimationFactory.NEXT_INDEX + 0;
+ public static final int INDEX_PAUSE_TO_OVERVIEW_ANIM =
+ RecentsAtomicAnimationFactory.NEXT_INDEX + 1;
+
+ private static final int MY_ANIM_COUNT = 2;
+ protected static final int NEXT_INDEX = RecentsAtomicAnimationFactory.NEXT_INDEX
+ + MY_ANIM_COUNT;
public static final long ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW = 300;
- private final QuickstepLauncher mLauncher;
-
- public QuickstepAtomicAnimationFactory(QuickstepLauncher launcher) {
- super(ANIM_COUNT);
- mLauncher = launcher;
+ public QuickstepAtomicAnimationFactory(QuickstepLauncher activity) {
+ super(activity, MY_ANIM_COUNT);
}
@Override
public Animator createStateElementAnimation(int index, float... values) {
switch (index) {
case INDEX_SHELF_ANIM: {
- AllAppsTransitionController aatc = mLauncher.getAllAppsController();
+ AllAppsTransitionController aatc = mActivity.getAllAppsController();
Animator springAnim = aatc.createSpringAnimation(values);
- if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
+ if ((OVERVIEW.getVisibleElements(mActivity) & HOTSEAT_ICONS) != 0) {
// Translate hotseat with the shelf until reaching overview.
- float overviewProgress = OVERVIEW.getVerticalProgress(mLauncher);
- ScaleAndTranslation sat = OVERVIEW.getHotseatScaleAndTranslation(mLauncher);
+ float overviewProgress = OVERVIEW.getVerticalProgress(mActivity);
+ ScaleAndTranslation sat = OVERVIEW.getHotseatScaleAndTranslation(mActivity);
float shiftRange = aatc.getShiftRange();
if (values.length == 1) {
values = new float[] {aatc.getProgress(), values[0]};
@@ -114,9 +112,9 @@
ValueAnimator hotseatAnim = ValueAnimator.ofFloat(values);
hotseatAnim.addUpdateListener(anim -> {
float progress = (Float) anim.getAnimatedValue();
- if (progress >= overviewProgress || mLauncher.isInState(BACKGROUND_APP)) {
+ if (progress >= overviewProgress || mActivity.isInState(BACKGROUND_APP)) {
float hotseatShift = (progress - overviewProgress) * shiftRange;
- mLauncher.getHotseat().setTranslationY(hotseatShift + sat.translationY);
+ mActivity.getHotseat().setTranslationY(hotseatShift + sat.translationY);
}
});
hotseatAnim.setInterpolator(LINEAR);
@@ -130,34 +128,21 @@
return springAnim;
}
- case INDEX_RECENTS_FADE_ANIM:
- return ObjectAnimator.ofFloat(mLauncher.getOverviewPanel(),
- RecentsView.CONTENT_ALPHA, values);
- case INDEX_RECENTS_TRANSLATE_X_ANIM: {
- RecentsView rv = mLauncher.getOverviewPanel();
- return new SpringAnimationBuilder(mLauncher)
- .setMinimumVisibleChange(1f / rv.getPageOffsetScale())
- .setDampingRatio(0.8f)
- .setStiffness(250)
- .setValues(values)
- .build(rv, ADJACENT_PAGE_OFFSET);
- }
case INDEX_PAUSE_TO_OVERVIEW_ANIM: {
StateAnimationConfig config = new StateAnimationConfig();
config.duration = ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW;
config.setInterpolator(ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2);
config.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_3);
- if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
+ if ((OVERVIEW.getVisibleElements(mActivity) & HOTSEAT_ICONS) != 0) {
config.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2);
config.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2);
}
- StateManager<LauncherState> stateManager = mLauncher.getStateManager();
+ StateManager<LauncherState> stateManager = mActivity.getStateManager();
return stateManager.createAtomicAnimation(
stateManager.getCurrentStableState(), OVERVIEW, config);
}
-
default:
return super.createStateElementAnimation(index, values);
}
@@ -172,7 +157,7 @@
config.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL);
config.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7);
- Workspace workspace = mLauncher.getWorkspace();
+ Workspace workspace = mActivity.getWorkspace();
// Start from a higher workspace scale, but only if we're invisible so we don't jump.
boolean isWorkspaceVisible = workspace.getVisibility() == VISIBLE;
@@ -186,13 +171,13 @@
workspace.setScaleX(0.92f);
workspace.setScaleY(0.92f);
}
- Hotseat hotseat = mLauncher.getHotseat();
+ Hotseat hotseat = mActivity.getHotseat();
boolean isHotseatVisible = hotseat.getVisibility() == VISIBLE && hotseat.getAlpha() > 0;
if (!isHotseatVisible) {
hotseat.setScaleX(0.92f);
hotseat.setScaleY(0.92f);
if (ENABLE_OVERVIEW_ACTIONS.get()) {
- AllAppsContainerView qsbContainer = mLauncher.getAppsView();
+ AllAppsContainerView qsbContainer = mActivity.getAppsView();
View qsb = qsbContainer.getSearchView();
boolean qsbVisible = qsb.getVisibility() == VISIBLE && qsb.getAlpha() > 0;
if (!qsbVisible) {
@@ -209,7 +194,7 @@
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_7);
config.setInterpolator(ANIM_OVERVIEW_SCRIM_FADE, FAST_OUT_SLOW_IN);
} else if ((fromState == NORMAL || fromState == HINT_STATE) && toState == OVERVIEW) {
- if (SysUINavigationMode.getMode(mLauncher) == NO_BUTTON) {
+ if (SysUINavigationMode.getMode(mActivity) == NO_BUTTON) {
config.setInterpolator(ANIM_WORKSPACE_SCALE,
fromState == NORMAL ? ACCEL : OVERSHOOT_1_2);
config.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL);
@@ -217,7 +202,7 @@
config.setInterpolator(ANIM_WORKSPACE_SCALE, OVERSHOOT_1_2);
// Scale up the recents, if it is not coming from the side
- RecentsView overview = mLauncher.getOverviewPanel();
+ RecentsView overview = mActivity.getOverviewPanel();
if (overview.getVisibility() != VISIBLE || overview.getContentAlpha() == 0) {
SCALE_PROPERTY.set(overview, RECENTS_PREPARE_SCALE);
}
@@ -225,7 +210,7 @@
config.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
config.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
Interpolator translationInterpolator = ENABLE_OVERVIEW_ACTIONS.get()
- && removeShelfFromOverview(mLauncher)
+ && removeShelfFromOverview(mActivity)
? OVERSHOOT_1_2
: OVERSHOOT_1_7;
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, translationInterpolator);
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 7385658..c1b68ab 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -116,7 +116,7 @@
mRecentsView = mLauncher.getOverviewPanel();
mXRange = mLauncher.getDeviceProfile().widthPx / 2f;
mYRange = LayoutUtils.getShelfTrackingDistance(
- mLauncher, mLauncher.getDeviceProfile());
+ mLauncher, mLauncher.getDeviceProfile(), mRecentsView.getPagedOrientationHandler());
mMotionPauseDetector = new MotionPauseDetector(mLauncher);
mMotionPauseMinDisplacement = mLauncher.getResources().getDimension(
R.dimen.motion_pause_detector_min_displacement_from_app);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
index dc8fb9e..f4d1629 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
@@ -77,7 +77,6 @@
controller.dispatchOnStart();
controller.getAnimationPlayer().end();
});
- factory.onRemoteAnimationReceived(null);
factory.createActivityInterface(RECENTS_LAUNCH_DURATION);
factory.setRecentsAttachedToAppWindow(true, false);
mActivity = activity;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
index 614ba46..66f6d02 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
@@ -55,7 +55,6 @@
import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.ActivityInitListener;
-import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
@@ -234,7 +233,6 @@
}
mCanceled = false;
}
- ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true);
}
/**
@@ -329,6 +327,7 @@
mRecentsAnimationController.finish(false /* toRecents */,
null /* onFinishComplete */);
mActivityInterface.onLaunchTaskSuccess();
+ ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false);
}
}
}
@@ -357,12 +356,13 @@
protected void initTransitionEndpoints(DeviceProfile dp) {
mDp = dp;
- mTransitionDragLength = mActivityInterface.getSwipeUpDestinationAndLength(
- dp, mContext, TEMP_RECT);
mTaskViewSimulator.setDp(dp);
mTaskViewSimulator.setLayoutRotation(
mDeviceState.getCurrentActiveRotation(),
mDeviceState.getDisplayRotation());
+ mTransitionDragLength = mActivityInterface.getSwipeUpDestinationAndLength(
+ dp, mContext, TEMP_RECT,
+ mTaskViewSimulator.getOrientationState().getOrientationHandler());
if (mDeviceState.isFullyGesturalNavMode()) {
// We can drag all the way to the top of the screen.
@@ -510,8 +510,8 @@
public interface Factory {
- BaseSwipeUpHandler newHandler(GestureState gestureState, long touchTimeMs,
- boolean continuingLastGesture, boolean isLikelyToStartNewTask);
+ BaseSwipeUpHandler newHandler(
+ GestureState gestureState, long touchTimeMs, boolean continuingLastGesture);
}
protected interface RunningWindowAnim {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
similarity index 91%
rename from quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
rename to quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
index a8fa630..23cc6d5 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
@@ -17,7 +17,6 @@
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
-import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
@@ -38,29 +37,24 @@
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import android.animation.Animator;
-import android.animation.AnimatorSet;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.graphics.PointF;
-import android.graphics.RectF;
import android.os.Build;
import android.os.SystemClock;
-import android.os.UserHandle;
import android.view.View;
import android.view.View.OnApplyWindowInsetsListener;
import android.view.ViewTreeObserver.OnDrawListener;
import android.view.WindowInsets;
import android.view.animation.Interpolator;
-import androidx.annotation.NonNull;
import androidx.annotation.UiThread;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
@@ -72,7 +66,6 @@
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.TraceHelper;
-import com.android.launcher3.views.FloatingIconView;
import com.android.quickstep.BaseActivityInterface.AnimationFactory;
import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.inputconsumers.OverviewInputConsumer;
@@ -80,7 +73,6 @@
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.ShelfPeekAnim;
import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
-import com.android.quickstep.util.StaggeredWorkspaceAnim;
import com.android.quickstep.util.TransformParams.TargetAlphaProvider;
import com.android.quickstep.views.LiveTileOverlay;
import com.android.quickstep.views.RecentsView;
@@ -92,11 +84,12 @@
/**
* Handles the navigation gestures when Launcher is the default home activity.
+ * TODO: Merge this with BaseSwipeUpHandler
*/
@TargetApi(Build.VERSION_CODES.O)
-public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsView>
- implements OnApplyWindowInsetsListener {
- private static final String TAG = LauncherSwipeHandler.class.getSimpleName();
+public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q extends RecentsView>
+ extends BaseSwipeUpHandler<T, Q> implements OnApplyWindowInsetsListener {
+ private static final String TAG = BaseSwipeUpHandlerV2.class.getSimpleName();
private static final String[] STATE_NAMES = DEBUG_STATES ? new String[16] : null;
@@ -108,9 +101,11 @@
}
// Launcher UI related states
- private static final int STATE_LAUNCHER_PRESENT = getFlagForIndex(0, "STATE_LAUNCHER_PRESENT");
- private static final int STATE_LAUNCHER_STARTED = getFlagForIndex(1, "STATE_LAUNCHER_STARTED");
- private static final int STATE_LAUNCHER_DRAWN = getFlagForIndex(2, "STATE_LAUNCHER_DRAWN");
+ protected static final int STATE_LAUNCHER_PRESENT =
+ getFlagForIndex(0, "STATE_LAUNCHER_PRESENT");
+ protected static final int STATE_LAUNCHER_STARTED =
+ getFlagForIndex(1, "STATE_LAUNCHER_STARTED");
+ protected static final int STATE_LAUNCHER_DRAWN = getFlagForIndex(2, "STATE_LAUNCHER_DRAWN");
// Internal initialization states
private static final int STATE_APP_CONTROLLER_RECEIVED =
@@ -122,7 +117,7 @@
private static final int STATE_SCALED_CONTROLLER_RECENTS =
getFlagForIndex(5, "STATE_SCALED_CONTROLLER_RECENTS");
- private static final int STATE_HANDLER_INVALIDATED =
+ protected static final int STATE_HANDLER_INVALIDATED =
getFlagForIndex(6, "STATE_HANDLER_INVALIDATED");
private static final int STATE_GESTURE_STARTED =
getFlagForIndex(7, "STATE_GESTURE_STARTED");
@@ -163,7 +158,7 @@
*/
private static final int LOG_NO_OP_PAGE_INDEX = -1;
- private final TaskAnimationManager mTaskAnimationManager;
+ protected final TaskAnimationManager mTaskAnimationManager;
// Either RectFSpringAnim (if animating home) or ObjectAnimator (from mCurrentShift) otherwise
private RunningWindowAnim mRunningWindowAnim;
@@ -193,7 +188,7 @@
private final Runnable mOnDeferredActivityLaunch = this::onDeferredActivityLaunch;
- public LauncherSwipeHandler(Context context, RecentsAnimationDeviceState deviceState,
+ public BaseSwipeUpHandlerV2(Context context, RecentsAnimationDeviceState deviceState,
TaskAnimationManager taskAnimationManager, GestureState gestureState,
long touchTimeMs, boolean continuingLastGesture,
InputConsumerController inputConsumer) {
@@ -222,9 +217,6 @@
| STATE_GESTURE_CANCELLED,
this::resetStateForAnimationCancel);
- mStateCallback.runOnceAtState(STATE_LAUNCHER_STARTED | STATE_APP_CONTROLLER_RECEIVED,
- this::sendRemoteAnimationsToAnimationFactory);
-
mStateCallback.runOnceAtState(STATE_RESUME_LAST_TASK | STATE_APP_CONTROLLER_RECEIVED,
this::resumeLastTask);
mStateCallback.runOnceAtState(STATE_START_NEW_TASK | STATE_SCREENSHOT_CAPTURED,
@@ -272,7 +264,7 @@
@Override
protected boolean onActivityInit(Boolean alreadyOnHome) {
super.onActivityInit(alreadyOnHome);
- final Launcher activity = mActivityInterface.getCreatedActivity();
+ final T activity = mActivityInterface.getCreatedActivity();
if (mActivity == activity) {
return true;
}
@@ -323,7 +315,7 @@
}
private void onLauncherStart() {
- final Launcher activity = mActivityInterface.getCreatedActivity();
+ final T activity = mActivityInterface.getCreatedActivity();
if (mActivity != activity) {
return;
}
@@ -411,6 +403,10 @@
updateSysUiFlags(mCurrentShift.value);
return;
}
+ notifyGestureAnimationStartToRecents();
+ }
+
+ protected void notifyGestureAnimationStartToRecents() {
mRecentsView.onGestureAnimationStart(mGestureState.getRunningTaskId());
}
@@ -418,10 +414,6 @@
mLauncherFrameDrawnTime = SystemClock.uptimeMillis();
}
- private void sendRemoteAnimationsToAnimationFactory() {
- mAnimationFactory.onRemoteAnimationReceived(mRecentsAnimationTargets);
- }
-
private void initializeLauncherAnimationController() {
buildAnimationController();
@@ -633,7 +625,7 @@
*/
@UiThread
private void notifyGestureStartedAsync() {
- final Launcher curActivity = mActivity;
+ final T curActivity = mActivity;
if (curActivity != null) {
// Once the gesture starts, we can no longer transition home through the button, so
// reset the force override of the activity visibility
@@ -681,7 +673,7 @@
endLauncherTransitionController();
if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) {
// Hide the task view, if not already hidden
- setTargetAlphaProvider(LauncherSwipeHandler::getHiddenTargetAlpha);
+ setTargetAlphaProvider(BaseSwipeUpHandlerV2::getHiddenTargetAlpha);
}
StatefulActivity activity = mActivityInterface.getCreatedActivity();
@@ -717,6 +709,7 @@
mStateCallback.setState(STATE_RESUME_LAST_TASK);
break;
}
+ ActiveGestureLog.INSTANCE.addLog("onSettledOnEndTarget " + mGestureState.getEndTarget());
}
@Override
@@ -787,12 +780,6 @@
}
}
- if (endTarget == RECENTS || endTarget == HOME) {
- // Since we're now done quickStepping, we want to only listen for touch events
- // for the main orientation's nav bar, instead of multiple
- mDeviceState.enableMultipleRegions(false);
- }
-
if (mDeviceState.isOverviewDisabled() && (endTarget == RECENTS || endTarget == LAST_TASK)) {
return LAST_TASK;
}
@@ -911,6 +898,8 @@
interpolator, target, velocityPxPerMs));
}
+ protected abstract HomeAnimationFactory createHomeAnimationFactory(long duration);
+
@UiThread
private void animateToProgressInternal(float start, float end, long duration,
Interpolator interpolator, GestureEndTarget target, PointF velocityPxPerMs) {
@@ -919,67 +908,7 @@
maybeUpdateRecentsAttachedState();
if (mGestureState.getEndTarget() == HOME) {
- HomeAnimationFactory homeAnimFactory;
- if (mActivity != null) {
- final TaskView runningTaskView = mRecentsView.getRunningTaskView();
- final View workspaceView;
- if (runningTaskView != null
- && runningTaskView.getTask().key.getComponent() != null) {
- workspaceView = mActivity.getWorkspace().getFirstMatchForAppClose(
- runningTaskView.getTask().key.getComponent().getPackageName(),
- UserHandle.of(runningTaskView.getTask().key.userId));
- } else {
- workspaceView = null;
- }
- final RectF iconLocation = new RectF();
- boolean canUseWorkspaceView =
- workspaceView != null && workspaceView.isAttachedToWindow();
- FloatingIconView floatingIconView = canUseWorkspaceView
- ? FloatingIconView.getFloatingIconView(mActivity, workspaceView,
- true /* hideOriginal */, iconLocation, false /* isOpening */)
- : null;
-
- mActivity.getRootView().setForceHideBackArrow(true);
- mActivityInterface.setHintUserWillBeActive();
-
- homeAnimFactory = new HomeAnimationFactory(floatingIconView) {
-
- @Override
- public RectF getWindowTargetRect() {
- if (canUseWorkspaceView) {
- return iconLocation;
- } else {
- return super.getWindowTargetRect();
- }
- }
-
- @NonNull
- @Override
- public AnimatorPlaybackController createActivityAnimationToHome() {
- // Return an empty APC here since we have an non-user controlled animation
- // to home.
- long accuracy = 2 * Math.max(mDp.widthPx, mDp.heightPx);
- return mActivity.getStateManager().createAnimationToNewWorkspace(
- NORMAL, accuracy, 0 /* animComponents */);
- }
-
- @Override
- public void playAtomicAnimation(float velocity) {
- new StaggeredWorkspaceAnim(mActivity, velocity,
- true /* animateOverviewScrim */).start();
- }
- };
-
- } else {
- homeAnimFactory = new HomeAnimationFactory(null) {
- @Override
- public AnimatorPlaybackController createActivityAnimationToHome() {
- return AnimatorPlaybackController.wrap(new AnimatorSet(), duration);
- }
- };
- mStateCallback.addChangeListener(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
- isPresent -> mRecentsView.startHome());
- }
+ HomeAnimationFactory homeAnimFactory = createHomeAnimationFactory(duration);
RectFSpringAnim windowAnim = createWindowAnimationToHome(start, homeAnimFactory);
windowAnim.addAnimatorListener(new AnimationSuccessListener() {
@Override
@@ -1303,14 +1232,16 @@
// If there are no targets or the animation not started, then there is nothing to finish
mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
} else {
- mRecentsAnimationController.finish(true /* toRecents */,
- () -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED),
- true /* sendUserLeaveHint */);
+ finishRecentsControllerToHome(
+ () -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
}
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true);
doLogGesture(HOME);
+ mDeviceState.enableMultipleRegions(false);
}
+ protected abstract void finishRecentsControllerToHome(Runnable callback);
+
private void setupLauncherUiAfterSwipeUpToRecentsAnimation() {
endLauncherTransitionController();
mActivityInterface.onSwipeUpToRecentsComplete();
@@ -1322,6 +1253,7 @@
SystemUiProxy.INSTANCE.get(mContext).onOverviewShown(false, TAG);
doLogGesture(RECENTS);
+ mDeviceState.onSwipeUpToOverview(mActivityInterface);
reset();
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
index 4b3af31..c9ff884 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
@@ -15,26 +15,21 @@
*/
package com.android.quickstep;
-import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.fallback.RecentsState.BACKGROUND_APP;
import static com.android.quickstep.fallback.RecentsState.DEFAULT;
-import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
-import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import android.content.Context;
-import android.graphics.PointF;
import android.graphics.Rect;
+import android.view.MotionEvent;
import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.userevent.nano.LauncherLogProto;
-import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsState;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.views.RecentsView;
@@ -54,12 +49,14 @@
public static final FallbackActivityInterface INSTANCE = new FallbackActivityInterface();
private FallbackActivityInterface() {
- super(false);
+ super(false, DEFAULT, BACKGROUND_APP);
}
+ /** 2 */
@Override
- public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
- calculateTaskSize(context, dp, outRect);
+ public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect,
+ PagedOrientationHandler orientationHandler) {
+ calculateTaskSize(context, dp, outRect, orientationHandler);
if (dp.isVerticalBarLayout()
&& SysUINavigationMode.INSTANCE.get(context).getMode() != NO_BUTTON) {
Rect targetInsets = dp.getInsets();
@@ -70,6 +67,13 @@
}
}
+ /** 4 */
+ @Override
+ public void onSwipeUpToHomeComplete() {
+ onSwipeUpToRecentsComplete();
+ }
+
+ /** 5 */
@Override
public void onAssistantVisibilityChanged(float visibility) {
// This class becomes active when the screen is locked.
@@ -77,50 +81,13 @@
// set to zero prior to this class becoming active.
}
+ /** 6 */
@Override
public AnimationFactory prepareRecentsUI(
boolean activityVisible, Consumer<AnimatorPlaybackController> callback) {
- RecentsActivity activity = getCreatedActivity();
- if (activity == null) {
- return (transitionLength) -> { };
- }
-
- activity.getStateManager().goToState(BACKGROUND_APP);
- FallbackRecentsView rv = activity.getOverviewPanel();
- rv.setContentAlpha(0);
-
- return new AnimationFactory() {
-
- boolean isAnimatingToRecents = false;
-
- @Override
- public void onRemoteAnimationReceived(RemoteAnimationTargets targets) {
- isAnimatingToRecents = targets != null && targets.isAnimatingHome();
- if (!isAnimatingToRecents) {
- rv.setContentAlpha(1);
- }
- createActivityInterface(getSwipeUpDestinationAndLength(
- activity.getDeviceProfile(), activity, new Rect()));
- }
-
- @Override
- public void createActivityInterface(long transitionLength) {
- PendingAnimation pa = new PendingAnimation(transitionLength * 2);
-
- if (isAnimatingToRecents) {
- pa.addFloat(rv, CONTENT_ALPHA, 0, 1, LINEAR);
- }
-
- pa.addFloat(rv, SCALE_PROPERTY, rv.getMaxScaleForFullScreen(), 1, LINEAR);
- pa.addFloat(rv, FULLSCREEN_PROGRESS, 1, 0, LINEAR);
- AnimatorPlaybackController controller = pa.createPlaybackController();
-
- // Since we are changing the start position of the UI, reapply the state, at the end
- controller.setEndAction(() -> activity.getStateManager().goToState(
- controller.getInterpolatedProgress() > 0.5 ? DEFAULT : BACKGROUND_APP));
- callback.accept(controller);
- }
- };
+ DefaultAnimationFactory factory = new DefaultAnimationFactory(callback);
+ factory.initUI();
+ return factory;
}
@Override
@@ -164,6 +131,20 @@
}
@Override
+ public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) {
+ // In non-gesture mode, user might be clicking on the home button which would directly
+ // start the home activity instead of going through recents. In that case, defer starting
+ // recents until we are sure it is a gesture.
+ return !deviceState.isFullyGesturalNavMode()
+ || super.deferStartingActivity(deviceState, ev);
+ }
+
+ @Override
+ public void onExitOverview(RecentsAnimationDeviceState deviceState, Runnable exitRunnable) {
+ // no-op, fake landscape not supported for 3P
+ }
+
+ @Override
public int getContainerType() {
RecentsActivity activity = getCreatedActivity();
boolean visible = activity != null && activity.isStarted() && activity.hasWindowFocus();
@@ -188,12 +169,8 @@
}
@Override
- public void getMultiWindowSize(Context context, DeviceProfile dp, PointF out) {
- out.set(dp.widthPx, dp.heightPx);
- }
-
- @Override
- protected float getExtraSpace(Context context, DeviceProfile dp) {
+ protected float getExtraSpace(Context context, DeviceProfile dp,
+ PagedOrientationHandler orientationHandler) {
return showOverviewActions(context)
? context.getResources().getDimensionPixelSize(R.dimen.overview_actions_height)
: 0;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
index db41bd6..7b614c2 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -15,537 +15,117 @@
*/
package com.android.quickstep;
-import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
-import static com.android.launcher3.anim.Interpolators.ACCEL_2;
-import static com.android.quickstep.GestureState.GestureEndTarget.HOME;
-import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
-import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK;
-import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
-import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
-import static com.android.quickstep.RecentsActivity.EXTRA_TASK_ID;
-import static com.android.quickstep.RecentsActivity.EXTRA_THUMBNAIL;
-import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
-import android.animation.Animator;
-import android.animation.AnimatorSet;
import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
-import android.graphics.PointF;
-import android.os.Bundle;
-import android.util.ArrayMap;
-import android.view.MotionEvent;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
-import com.android.launcher3.anim.AnimationSuccessListener;
+import androidx.annotation.NonNull;
+
import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.util.ObjectWrapper;
-import com.android.quickstep.BaseActivityInterface.AnimationFactory;
-import com.android.quickstep.GestureState.GestureEndTarget;
+import com.android.launcher3.anim.PendingAnimation;
import com.android.quickstep.fallback.FallbackRecentsView;
-import com.android.quickstep.util.RectFSpringAnim;
-import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.quickstep.util.TransformParams;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder;
/**
* Handles the navigation gestures when a 3rd party launcher is the default home activity.
*/
-public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, FallbackRecentsView> {
+public class FallbackSwipeHandler extends
+ BaseSwipeUpHandlerV2<RecentsActivity, FallbackRecentsView> {
- private static final String[] STATE_NAMES = DEBUG_STATES ? new String[5] : null;
-
- private static int getFlagForIndex(int index, String name) {
- if (DEBUG_STATES) {
- STATE_NAMES[index] = name;
- }
- return 1 << index;
- }
-
- private static final int STATE_RECENTS_PRESENT =
- getFlagForIndex(0, "STATE_RECENTS_PRESENT");
- private static final int STATE_HANDLER_INVALIDATED =
- getFlagForIndex(1, "STATE_HANDLER_INVALIDATED");
-
- private static final int STATE_GESTURE_CANCELLED =
- getFlagForIndex(2, "STATE_GESTURE_CANCELLED");
- private static final int STATE_GESTURE_COMPLETED =
- getFlagForIndex(3, "STATE_GESTURE_COMPLETED");
- private static final int STATE_APP_CONTROLLER_RECEIVED =
- getFlagForIndex(4, "STATE_APP_CONTROLLER_RECEIVED");
-
- public static class EndTargetAnimationParams {
- private final float mEndProgress;
- private final long mDurationMultiplier;
- private final float mLauncherAlpha;
-
- EndTargetAnimationParams(float endProgress, long durationMultiplier, float launcherAlpha) {
- mEndProgress = endProgress;
- mDurationMultiplier = durationMultiplier;
- mLauncherAlpha = launcherAlpha;
- }
- }
- private final ArrayMap<GestureEndTarget, EndTargetAnimationParams>
- mEndTargetAnimationParams = new ArrayMap();
-
- private final AnimatedFloat mLauncherAlpha = new AnimatedFloat(this::onLauncherAlphaChanged);
-
- private boolean mOverviewThresholdPassed = false;
-
- private final boolean mInQuickSwitchMode;
- private final boolean mContinuingLastGesture;
+ private FallbackHomeAnimationFactory mActiveAnimationFactory;
private final boolean mRunningOverHome;
- private final boolean mSwipeUpOverHome;
- private boolean mTouchedHomeDuringTransition;
-
- private final PointF mEndVelocityPxPerMs = new PointF(0, 0.5f);
- private RunningWindowAnim mFinishAnimation;
-
- // Used to control Recents components throughout the swipe gesture.
- private AnimatorPlaybackController mLauncherTransitionController;
- private boolean mHasLauncherTransitionControllerStarted;
-
- private AnimationFactory mAnimationFactory = (t) -> { };
public FallbackSwipeHandler(Context context, RecentsAnimationDeviceState deviceState,
- GestureState gestureState, InputConsumerController inputConsumer,
- boolean isLikelyToStartNewTask, boolean continuingLastGesture) {
- super(context, deviceState, gestureState, inputConsumer);
+ TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs,
+ boolean continuingLastGesture, InputConsumerController inputConsumer) {
+ super(context, deviceState, taskAnimationManager, gestureState, touchTimeMs,
+ continuingLastGesture, inputConsumer);
- mInQuickSwitchMode = isLikelyToStartNewTask || continuingLastGesture;
- mContinuingLastGesture = continuingLastGesture;
mRunningOverHome = ActivityManagerWrapper.isHomeTask(mGestureState.getRunningTask());
- mSwipeUpOverHome = mRunningOverHome && !mInQuickSwitchMode;
-
- // Keep the home launcher invisible until we decide to land there.
- mLauncherAlpha.value = mRunningOverHome ? 1 : 0;
- if (mSwipeUpOverHome) {
- mTransformParams.setBaseAlphaCallback((t, a) -> 1 - mLauncherAlpha.value);
- } else {
- mTransformParams.setBaseAlphaCallback((t, a) -> mLauncherAlpha.value);
- }
-
- // Going home has an extra long progress to ensure that it animates into the screen
- mEndTargetAnimationParams.put(HOME, new EndTargetAnimationParams(3, 100, 1));
- mEndTargetAnimationParams.put(RECENTS, new EndTargetAnimationParams(1, 300, 0));
- mEndTargetAnimationParams.put(LAST_TASK, new EndTargetAnimationParams(0, 150, 1));
- mEndTargetAnimationParams.put(NEW_TASK, new EndTargetAnimationParams(0, 150, 1));
-
- initAfterSubclassConstructor();
- initStateCallbacks();
- }
-
- private void initStateCallbacks() {
- mStateCallback = new MultiStateCallback(STATE_NAMES);
-
- mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED,
- this::onHandlerInvalidated);
- mStateCallback.runOnceAtState(STATE_RECENTS_PRESENT | STATE_HANDLER_INVALIDATED,
- this::onHandlerInvalidatedWithRecents);
-
- mStateCallback.runOnceAtState(STATE_GESTURE_CANCELLED | STATE_APP_CONTROLLER_RECEIVED,
- this::finishAnimationTargetSetAnimationComplete);
-
- if (mInQuickSwitchMode) {
- mStateCallback.runOnceAtState(STATE_GESTURE_COMPLETED | STATE_APP_CONTROLLER_RECEIVED
- | STATE_RECENTS_PRESENT,
- this::finishAnimationTargetSet);
- } else {
- mStateCallback.runOnceAtState(STATE_GESTURE_COMPLETED | STATE_APP_CONTROLLER_RECEIVED,
- this::finishAnimationTargetSet);
- }
- }
-
- private void onLauncherAlphaChanged() {
- if (mRecentsAnimationTargets != null && mGestureState.getEndTarget() == null) {
- applyWindowTransform();
- }
}
@Override
- protected boolean onActivityInit(Boolean alreadyOnHome) {
- super.onActivityInit(alreadyOnHome);
- mActivity = mActivityInterface.getCreatedActivity();
- mRecentsView = mActivity.getOverviewPanel();
- mRecentsView.setOnPageTransitionEndCallback(null);
- linkRecentsViewScroll();
- if (!mContinuingLastGesture) {
- if (mRunningOverHome) {
- mRecentsView.onGestureAnimationStart(mGestureState.getRunningTask());
- } else {
- mRecentsView.onGestureAnimationStart(mGestureState.getRunningTaskId());
- }
- }
- mStateCallback.setStateOnUiThread(STATE_RECENTS_PRESENT);
- mDeviceState.enableMultipleRegions(false);
-
- mAnimationFactory = mActivityInterface.prepareRecentsUI(alreadyOnHome,
- this::onAnimatorPlaybackControllerCreated);
- mAnimationFactory.createActivityInterface(mTransitionDragLength);
- return true;
- }
-
- @Override
- protected void initTransitionEndpoints(DeviceProfile dp) {
- super.initTransitionEndpoints(dp);
- if (canCreateNewOrUpdateExistingLauncherTransitionController()) {
- mAnimationFactory.createActivityInterface(mTransitionDragLength);
- }
- }
-
- private void onAnimatorPlaybackControllerCreated(AnimatorPlaybackController anim) {
- mLauncherTransitionController = anim;
- mLauncherTransitionController.dispatchSetInterpolator(t -> t * mDragLengthFactor);
- mLauncherTransitionController.dispatchOnStart();
- updateLauncherTransitionProgress();
- }
-
- private void updateLauncherTransitionProgress() {
- if (mLauncherTransitionController == null
- || !canCreateNewOrUpdateExistingLauncherTransitionController()) {
- return;
- }
- // Normalize the progress to 0 to 1, as the animation controller will clamp it to that
- // anyway. The controller mimics the drag length factor by applying it to its interpolators.
- float progress = mCurrentShift.value / mDragLengthFactor;
- mLauncherTransitionController.setPlayFraction(progress);
- }
-
- /**
- * We don't want to change mLauncherTransitionController if mGestureState.getEndTarget() == HOME
- * (it has its own animation) or if we're already animating the current controller.
- * @return Whether we can create the launcher controller or update its progress.
- */
- private boolean canCreateNewOrUpdateExistingLauncherTransitionController() {
- return mGestureState.getEndTarget() != HOME && !mHasLauncherTransitionControllerStarted;
- }
-
- @Override
- protected boolean moveWindowWithRecentsScroll() {
- return mInQuickSwitchMode;
- }
-
- @Override
- public void initWhenReady(Intent intent) {
- if (mInQuickSwitchMode) {
- // Only init if we are in quickswitch mode
- super.initWhenReady(intent);
- }
- }
-
- @Override
- public void updateDisplacement(float displacement) {
- if (!mInQuickSwitchMode) {
- super.updateDisplacement(displacement);
- }
- }
-
- @Override
- protected InputConsumer createNewInputProxyHandler() {
- // Just consume all input on the active task
- return new InputConsumer() {
- @Override
- public int getType() {
- return InputConsumer.TYPE_NO_OP;
- }
-
- @Override
- public void onMotionEvent(MotionEvent ev) {
- mTouchedHomeDuringTransition = true;
- }
- };
- }
-
- @Override
- public void onMotionPauseChanged(boolean isPaused) {
- if (!mInQuickSwitchMode && mDeviceState.isFullyGesturalNavMode()) {
- updateOverviewThresholdPassed(isPaused);
- }
- }
-
- private void updateOverviewThresholdPassed(boolean passed) {
- if (passed != mOverviewThresholdPassed) {
- mOverviewThresholdPassed = passed;
- if (mSwipeUpOverHome) {
- mLauncherAlpha.animateToValue(mLauncherAlpha.value, passed ? 0 : 1)
- .setDuration(150).start();
- }
- performHapticFeedback();
- }
- }
-
- @Override
- public Intent getLaunchIntent() {
- if (mInQuickSwitchMode || mSwipeUpOverHome || !mDeviceState.isFullyGesturalNavMode()) {
- return mGestureState.getOverviewIntent();
- } else {
- return mGestureState.getHomeIntent();
- }
- }
-
- @Override
- public void updateFinalShift() {
- mTransformParams.setProgress(mCurrentShift.value);
- if (mRecentsAnimationController != null) {
- boolean swipeUpThresholdPassed = mCurrentShift.value > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD;
- mRecentsAnimationController.setUseLauncherSystemBarFlags(mInQuickSwitchMode
- || swipeUpThresholdPassed);
- mRecentsAnimationController.setSplitScreenMinimized(!mInQuickSwitchMode
- && swipeUpThresholdPassed);
- }
-
- if (!mInQuickSwitchMode && !mDeviceState.isFullyGesturalNavMode()) {
- updateOverviewThresholdPassed(mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW);
- }
-
- applyWindowTransform();
- updateLauncherTransitionProgress();
- }
-
- @Override
- public void onGestureCancelled() {
- updateDisplacement(0);
- mGestureState.setEndTarget(LAST_TASK);
- mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED);
- }
-
- @Override
- public void onGestureEnded(float endVelocity, PointF velocity, PointF downPos) {
- mEndVelocityPxPerMs.set(0, velocity.y / 1000);
- if (mInQuickSwitchMode) {
- // For now set it to non-null, it will be reset before starting the animation
- mGestureState.setEndTarget(LAST_TASK);
- } else {
- float flingThreshold = mContext.getResources()
- .getDimension(R.dimen.quickstep_fling_threshold_velocity);
- boolean isFling = Math.abs(endVelocity) > flingThreshold;
-
- if (mDeviceState.isFullyGesturalNavMode()) {
- if (isFling) {
- mGestureState.setEndTarget(endVelocity < 0 ? HOME : LAST_TASK);
- } else if (mOverviewThresholdPassed) {
- mGestureState.setEndTarget(RECENTS);
- } else {
- mGestureState.setEndTarget(mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW
- ? HOME
- : LAST_TASK);
- }
- } else {
- GestureEndTarget startState = mSwipeUpOverHome ? HOME : LAST_TASK;
- if (isFling) {
- mGestureState.setEndTarget(endVelocity < 0 ? RECENTS : startState);
- } else {
- mGestureState.setEndTarget(mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW
- ? RECENTS
- : startState);
- }
- }
- }
- mStateCallback.setStateOnUiThread(STATE_GESTURE_COMPLETED);
- }
-
- @Override
- public void onConsumerAboutToBeSwitched() {
- if (mInQuickSwitchMode && mGestureState.getEndTarget() != null) {
- mGestureState.setEndTarget(NEW_TASK);
-
- mCanceled = true;
- mCurrentShift.cancelAnimation();
- if (mFinishAnimation != null) {
- mFinishAnimation.cancel();
- }
-
- if (mRecentsView != null) {
- mRecentsView.setOnScrollChangeListener(null);
- }
- } else {
- mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
- }
- }
-
- private void onHandlerInvalidated() {
- mActivityInitListener.unregister();
- if (mGestureEndCallback != null) {
- mGestureEndCallback.run();
- }
- if (mFinishAnimation != null) {
- mFinishAnimation.end();
- }
- }
-
- private void onHandlerInvalidatedWithRecents() {
- mRecentsView.onGestureAnimationEnd();
- mRecentsView.setDisallowScrollToClearAll(false);
- mRecentsView.getClearAllButton().setVisibilityAlpha(1);
- }
-
- private void finishAnimationTargetSetAnimationComplete() {
- switch (mGestureState.getEndTarget()) {
- case HOME: {
- if (mSwipeUpOverHome) {
- mRecentsAnimationController.finish(false, null, false);
- // Send a home intent to clear the task stack
- mContext.startActivity(mGestureState.getHomeIntent());
- } else {
- // Notify swipe-to-home (recents animation) is finished
- SystemUiProxy.INSTANCE.get(mContext).notifySwipeToHomeFinished();
- mRecentsAnimationController.finish(true, () -> {
- if (!mTouchedHomeDuringTransition) {
- // If the user hasn't interacted with the screen during the transition,
- // send a home intent so launcher can go to the default home screen.
- // (If they are trying to touch something, we don't want to interfere.)
- mContext.startActivity(mGestureState.getHomeIntent());
- }
- }, true);
- }
- break;
- }
- case LAST_TASK:
- mRecentsAnimationController.finish(false, null, false);
- break;
- case RECENTS: {
- if (mSwipeUpOverHome || !mDeviceState.isFullyGesturalNavMode()) {
- mRecentsAnimationController.finish(true, null, true);
- break;
- }
-
- final int runningTaskId = mGestureState.getRunningTaskId();
- ThumbnailData thumbnail = mRecentsAnimationController.screenshotTask(runningTaskId);
- mRecentsAnimationController.setDeferCancelUntilNextTransition(true /* defer */,
- false /* screenshot */);
-
- ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
- ActivityOptionsCompat.setFreezeRecentTasksList(options);
-
- Bundle extras = new Bundle();
- extras.putBinder(EXTRA_THUMBNAIL, new ObjectWrapper<>(thumbnail));
- extras.putInt(EXTRA_TASK_ID, runningTaskId);
-
- Intent intent = new Intent(mGestureState.getOverviewIntent())
- .putExtras(extras);
- mContext.startActivity(intent, options.toBundle());
- mRecentsAnimationController.cleanupScreenshot();
- break;
- }
- case NEW_TASK: {
- startNewTask(success -> { });
- break;
- }
- }
-
- mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
- }
-
- private void finishAnimationTargetSet() {
- if (mInQuickSwitchMode) {
- // Recalculate the end target, some views might have been initialized after
- // gesture has ended.
- if (mRecentsView == null || !hasTargets()) {
- mGestureState.setEndTarget(LAST_TASK);
- } else {
- final int runningTaskIndex = getLastAppearedTaskIndex();
- final int taskToLaunch = mRecentsView.getNextPage();
- mGestureState.setEndTarget(
- (runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex)
- ? NEW_TASK
- : LAST_TASK);
- }
- }
-
- EndTargetAnimationParams params = mEndTargetAnimationParams.get(mGestureState.getEndTarget());
- float endProgress = params.mEndProgress;
- long duration = (long) (params.mDurationMultiplier *
- Math.abs(endProgress - mCurrentShift.value));
- if (mRecentsView != null) {
- duration = Math.max(duration, mRecentsView.getScroller().getDuration());
- }
- if (mCurrentShift.value != endProgress || mInQuickSwitchMode) {
- AnimationSuccessListener endListener = new AnimationSuccessListener() {
-
- @Override
- public void onAnimationSuccess(Animator animator) {
- if (mRecentsView != null) {
- mRecentsView.setOnPageTransitionEndCallback(FallbackSwipeHandler.this
- ::finishAnimationTargetSetAnimationComplete);
- } else {
- finishAnimationTargetSetAnimationComplete();
- }
- mFinishAnimation = null;
- }
- };
-
- if (mGestureState.getEndTarget() == HOME && !mRunningOverHome) {
- mRecentsAnimationController.enableInputProxy(mInputConsumer,
- this::createNewInputProxyHandler);
- RectFSpringAnim anim = createWindowAnimationToHome(mCurrentShift.value, duration);
- anim.addAnimatorListener(endListener);
- anim.start(mContext, mEndVelocityPxPerMs);
- mFinishAnimation = RunningWindowAnim.wrap(anim);
- } else {
-
- AnimatorSet anim = new AnimatorSet();
- anim.play(mLauncherAlpha.animateToValue(
- mLauncherAlpha.value, params.mLauncherAlpha));
- anim.play(mCurrentShift.animateToValue(mCurrentShift.value, endProgress));
-
- anim.setDuration(duration);
- anim.addListener(endListener);
- anim.start();
- mFinishAnimation = RunningWindowAnim.wrap(anim);
- }
-
- } else {
- finishAnimationTargetSetAnimationComplete();
- }
- }
-
- @Override
- public void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets) {
- super.onRecentsAnimationStart(controller, targets);
- mRecentsAnimationController.enableInputConsumer();
- applyWindowTransform();
-
- mStateCallback.setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
- }
-
- @Override
- public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
- mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
-
- // Defer clearing the controller and the targets until after we've updated the state
- super.onRecentsAnimationCanceled(thumbnailData);
+ protected HomeAnimationFactory createHomeAnimationFactory(long duration) {
+ mActiveAnimationFactory = new FallbackHomeAnimationFactory(duration);
+ ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
+ mContext.startActivity(new Intent(mGestureState.getHomeIntent()), options.toBundle());
+ return mActiveAnimationFactory;
}
@Override
protected boolean handleTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
- return true;
- }
+ if (mActiveAnimationFactory != null
+ && mActiveAnimationFactory.handleHomeTaskAppeared(appearedTaskTarget)) {
+ mActiveAnimationFactory = null;
+ return false;
+ }
- /**
- * Creates an animation that transforms the current app window into the home app.
- * @param startProgress The progress of {@link #mCurrentShift} to start the window from.
- */
- private RectFSpringAnim createWindowAnimationToHome(float startProgress, long duration) {
- HomeAnimationFactory factory = new HomeAnimationFactory(null) {
- @Override
- public AnimatorPlaybackController createActivityAnimationToHome() {
- AnimatorSet anim = new AnimatorSet();
- Animator fadeInLauncher = mLauncherAlpha.animateToValue(mLauncherAlpha.value, 1);
- fadeInLauncher.setInterpolator(ACCEL_2);
- anim.play(fadeInLauncher);
- anim.setDuration(duration);
- return AnimatorPlaybackController.wrap(anim, duration);
- }
- };
- return createWindowAnimationToHome(startProgress, factory);
+ return super.handleTaskAppeared(appearedTaskTarget);
}
@Override
- protected float getWindowAlpha(float progress) {
- return 1 - ACCEL_1_5.getInterpolation(progress);
+ protected void finishRecentsControllerToHome(Runnable callback) {
+ mRecentsAnimationController.finish(
+ false /* toRecents */, callback, true /* sendUserLeaveHint */);
+ }
+
+ @Override
+ protected void notifyGestureAnimationStartToRecents() {
+ if (mRunningOverHome) {
+ mRecentsView.onGestureAnimationStartOnHome(mGestureState.getRunningTask());
+ } else {
+ super.notifyGestureAnimationStartToRecents();
+ }
+ }
+
+ private class FallbackHomeAnimationFactory extends HomeAnimationFactory
+ implements TransformParams.BuilderProxy {
+
+ private final TransformParams mHomeAlphaParams = new TransformParams();
+ private final AnimatedFloat mHomeAlpha = new AnimatedFloat(this::updateHomeAlpha);
+
+ private final long mDuration;
+ FallbackHomeAnimationFactory(long duration) {
+ super(null);
+ mDuration = duration;
+ }
+
+ @NonNull
+ @Override
+ public AnimatorPlaybackController createActivityAnimationToHome() {
+ PendingAnimation pa = new PendingAnimation(mDuration);
+ pa.setFloat(mHomeAlpha, AnimatedFloat.VALUE, 1, LINEAR);
+ return pa.createPlaybackController();
+ }
+
+ private void updateHomeAlpha() {
+ mHomeAlphaParams.setProgress(mHomeAlpha.value);
+ if (mHomeAlphaParams.getTargetSet() != null) {
+ mHomeAlphaParams.applySurfaceParams(mHomeAlphaParams.createSurfaceParams(this));
+ }
+ }
+
+ public boolean handleHomeTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
+ if (appearedTaskTarget.activityType == ACTIVITY_TYPE_HOME) {
+ RemoteAnimationTargets targets = new RemoteAnimationTargets(
+ new RemoteAnimationTargetCompat[] {appearedTaskTarget},
+ new RemoteAnimationTargetCompat[0], appearedTaskTarget.mode);
+ mHomeAlphaParams.setTargetSet(targets);
+ updateHomeAlpha();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onBuildParams(Builder builder, RemoteAnimationTargetCompat app, int targetMode,
+ TransformParams params) { }
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
index 5dbf199..13b84e0 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
@@ -15,30 +15,18 @@
*/
package com.android.quickstep;
-import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.anim.Interpolators.ACCEL_2;
-import static com.android.launcher3.anim.Interpolators.INSTANT;
import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
-import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM;
-import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_RECENTS_TRANSLATE_X_ANIM;
import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_SHELF_ANIM;
-import static com.android.quickstep.LauncherSwipeHandler.RECENTS_ATTACH_DURATION;
import static com.android.quickstep.SysUINavigationMode.getMode;
-import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
+import static com.android.quickstep.SysUINavigationMode.hideShelfInTwoButtonLandscape;
import static com.android.quickstep.util.LayoutUtils.getDefaultSwipeHeight;
-import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
-import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
-import android.animation.Animator;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.PointF;
import android.graphics.Rect;
import android.util.Log;
-import android.view.MotionEvent;
import android.view.animation.Interpolator;
import androidx.annotation.Nullable;
@@ -56,14 +44,14 @@
import com.android.launcher3.appprediction.PredictionUiStateManager;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statehandlers.DepthController.ClampedDepthProperty;
+import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.testing.TestProtocol;
+import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.LayoutUtils;
-import com.android.quickstep.util.ShelfPeekAnim;
import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
-import com.android.quickstep.views.LauncherRecentsView;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.plugins.shared.LauncherOverlayManager;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -75,23 +63,24 @@
* {@link BaseActivityInterface} for the in-launcher recents.
*/
public final class LauncherActivityInterface extends
- BaseActivityInterface<LauncherState, Launcher> {
+ BaseActivityInterface<LauncherState, BaseQuickstepLauncher> {
public static final LauncherActivityInterface INSTANCE = new LauncherActivityInterface();
private LauncherActivityInterface() {
- super(true);
+ super(true, OVERVIEW, BACKGROUND_APP);
}
@Override
- public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
- calculateTaskSize(context, dp, outRect);
+ public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect,
+ PagedOrientationHandler orientationHandler) {
+ calculateTaskSize(context, dp, outRect, orientationHandler);
if (dp.isVerticalBarLayout() && SysUINavigationMode.getMode(context) != Mode.NO_BUTTON) {
Rect targetInsets = dp.getInsets();
int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
return dp.hotseatBarSizePx + hotseatInset;
} else {
- return LayoutUtils.getShelfTrackingDistance(context, dp);
+ return LayoutUtils.getShelfTrackingDistance(context, dp, orientationHandler);
}
}
@@ -130,119 +119,43 @@
@Override
public AnimationFactory prepareRecentsUI(
boolean activityVisible, Consumer<AnimatorPlaybackController> callback) {
- BaseQuickstepLauncher launcher = getCreatedActivity();
- final LauncherState startState = launcher.getStateManager().getState();
-
- LauncherState resetState = startState;
- if (startState.shouldDisableRestore()) {
- resetState = launcher.getStateManager().getRestState();
- }
- launcher.getStateManager().setRestState(resetState);
-
- launcher.getStateManager().goToState(BACKGROUND_APP, false);
- // Since all apps is not visible, we can safely reset the scroll position.
- // This ensures then the next swipe up to all-apps starts from scroll 0.
- launcher.getAppsView().reset(false /* animate */);
-
- return new AnimationFactory() {
- private final ShelfPeekAnim mShelfAnim = launcher.getShelfPeekAnim();
- private boolean mIsAttachedToWindow;
-
- @Override
- public void createActivityInterface(long transitionLength) {
- callback.accept(createBackgroundToOverviewAnim(launcher, transitionLength));
- // Creating the activity controller animation sometimes reapplies the launcher state
- // (because we set the animation as the current state animation), so we reapply the
- // attached state here as well to ensure recents is shown/hidden appropriately.
- if (SysUINavigationMode.getMode(launcher) == Mode.NO_BUTTON) {
- setRecentsAttachedToAppWindow(mIsAttachedToWindow, false);
- }
- }
-
- @Override
- public void onTransitionCancelled() {
- launcher.getStateManager().goToState(startState, false /* animate */);
- }
-
+ DefaultAnimationFactory factory = new DefaultAnimationFactory(callback) {
@Override
public void setShelfState(ShelfAnimState shelfState, Interpolator interpolator,
long duration) {
- mShelfAnim.setShelfState(shelfState, interpolator, duration);
+ mActivity.getShelfPeekAnim().setShelfState(shelfState, interpolator, duration);
}
@Override
- public void setRecentsAttachedToAppWindow(boolean attached, boolean animate) {
- if (mIsAttachedToWindow == attached && animate) {
- return;
- }
- mIsAttachedToWindow = attached;
- LauncherRecentsView recentsView = launcher.getOverviewPanel();
- Animator fadeAnim = launcher.getStateManager()
- .createStateElementAnimation(
- INDEX_RECENTS_FADE_ANIM, attached ? 1 : 0);
+ protected void createBackgroundToOverviewAnim(BaseQuickstepLauncher activity,
+ PendingAnimation pa) {
+ super.createBackgroundToOverviewAnim(activity, pa);
- float fromTranslation = attached ? 1 : 0;
- float toTranslation = attached ? 0 : 1;
- launcher.getStateManager()
- .cancelStateElementAnimation(INDEX_RECENTS_TRANSLATE_X_ANIM);
- if (!recentsView.isShown() && animate) {
- ADJACENT_PAGE_OFFSET.set(recentsView, fromTranslation);
- } else {
- fromTranslation = ADJACENT_PAGE_OFFSET.get(recentsView);
- }
- if (!animate) {
- ADJACENT_PAGE_OFFSET.set(recentsView, toTranslation);
- } else {
- launcher.getStateManager().createStateElementAnimation(
- INDEX_RECENTS_TRANSLATE_X_ANIM,
- fromTranslation, toTranslation).start();
+ 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.
+ pa.add(activity.getStateManager().createStateElementAnimation(
+ INDEX_SHELF_ANIM,
+ BACKGROUND_APP.getVerticalProgress(activity),
+ OVERVIEW.getVerticalProgress(activity)));
}
- fadeAnim.setInterpolator(attached ? INSTANT : ACCEL_2);
- fadeAnim.setDuration(animate ? RECENTS_ATTACH_DURATION : 0).start();
+ // Animate the blur and wallpaper zoom
+ float fromDepthRatio = BACKGROUND_APP.getDepth(activity);
+ float toDepthRatio = OVERVIEW.getDepth(activity);
+ pa.addFloat(getDepthController(),
+ new ClampedDepthProperty(fromDepthRatio, toDepthRatio),
+ fromDepthRatio, toDepthRatio, LINEAR);
+
}
};
- }
- private AnimatorPlaybackController createBackgroundToOverviewAnim(
- Launcher activity, long transitionLength) {
-
- PendingAnimation pa = new PendingAnimation(transitionLength * 2);
-
- 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.
- pa.add(activity.getStateManager().createStateElementAnimation(
- INDEX_SHELF_ANIM,
- BACKGROUND_APP.getVerticalProgress(activity),
- OVERVIEW.getVerticalProgress(activity)));
- }
-
- // Animate the blur and wallpaper zoom
- float fromDepthRatio = BACKGROUND_APP.getDepth(activity);
- float toDepthRatio = OVERVIEW.getDepth(activity);
- pa.addFloat(getDepthController(), new ClampedDepthProperty(fromDepthRatio, toDepthRatio),
- fromDepthRatio, toDepthRatio, LINEAR);
-
-
- // Scale down recents from being full screen to being in overview.
- RecentsView recentsView = activity.getOverviewPanel();
- pa.addFloat(recentsView, SCALE_PROPERTY,
- BACKGROUND_APP.getOverviewScaleAndOffset(activity)[0],
- OVERVIEW.getOverviewScaleAndOffset(activity)[0],
- LINEAR);
- pa.addFloat(recentsView, FULLSCREEN_PROGRESS,
- BACKGROUND_APP.getOverviewFullscreenProgress(),
- OVERVIEW.getOverviewFullscreenProgress(),
- LINEAR);
-
- AnimatorPlaybackController controller = pa.createPlaybackController();
- activity.getStateManager().setCurrentUserControlledAnimation(controller);
-
- // Since we are changing the start position of the UI, reapply the state, at the end
- controller.setEndAction(() -> activity.getStateManager().goToState(
- controller.getInterpolatedProgress() > 0.5 ? OVERVIEW : BACKGROUND_APP, false));
- return controller;
+ BaseQuickstepLauncher launcher = factory.initUI();
+ // Since all apps is not visible, we can safely reset the scroll position.
+ // This ensures then the next swipe up to all-apps starts from scroll 0.
+ launcher.getAppsView().reset(false /* animate */);
+ return factory;
}
@Override
@@ -251,6 +164,15 @@
onInitListener.test(alreadyOnHome));
}
+ @Override
+ public void setOnDeferredActivityLaunchCallback(Runnable r) {
+ Launcher launcher = getCreatedActivity();
+ if (launcher == null) {
+ return;
+ }
+ launcher.setOnDeferredActivityLaunchCallback(r);
+ }
+
@Nullable
@Override
public BaseQuickstepLauncher getCreatedActivity() {
@@ -258,11 +180,13 @@
}
@Nullable
- @UiThread
- private Launcher getVisibleLauncher() {
- Launcher launcher = getCreatedActivity();
- return (launcher != null) && launcher.isStarted() && launcher.hasWindowFocus() ?
- launcher : null;
+ @Override
+ public DepthController getDepthController() {
+ BaseQuickstepLauncher launcher = getCreatedActivity();
+ if (launcher == null) {
+ return null;
+ }
+ return launcher.getDepthController();
}
@Nullable
@@ -273,6 +197,14 @@
? launcher.getOverviewPanel() : null;
}
+ @Nullable
+ @UiThread
+ private Launcher getVisibleLauncher() {
+ Launcher launcher = getCreatedActivity();
+ return (launcher != null) && launcher.isStarted() && launcher.hasWindowFocus()
+ ? launcher : null;
+ }
+
@Override
public boolean switchToRecentsIfVisible(Runnable onCompleteCallback) {
if (TestProtocol.sDebugTracing) {
@@ -292,14 +224,26 @@
return true;
}
- @Override
- public void setHintUserWillBeActive() {
- getCreatedActivity().setHintUserWillBeActive();
- }
@Override
- public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) {
- return deviceState.isInDeferredGestureRegion(ev);
+ public void onExitOverview(RecentsAnimationDeviceState deviceState, Runnable exitRunnable) {
+ final StateManager<LauncherState> stateManager = getCreatedActivity().getStateManager();
+ stateManager.addStateListener(
+ new StateManager.StateListener<LauncherState>() {
+ @Override
+ public void onStateTransitionComplete(LauncherState toState) {
+ // Are we going from Recents to Workspace?
+ if (toState == LauncherState.NORMAL) {
+ exitRunnable.run();
+
+ // reset layout on swipe to home
+ RecentsView recentsView = getCreatedActivity().getOverviewPanel();
+ recentsView.setLayoutRotation(deviceState.getCurrentActiveRotation(),
+ deviceState.getDisplayRotation());
+ stateManager.removeStateListener(this);
+ }
+ }
+ });
}
@Override
@@ -313,6 +257,16 @@
}
@Override
+ public void updateOverviewPredictionState() {
+ Launcher launcher = getCreatedActivity();
+ if (launcher == null) {
+ return;
+ }
+ PredictionUiStateManager.INSTANCE.get(launcher).switchClient(
+ PredictionUiStateManager.Client.OVERVIEW);
+ }
+
+ @Override
public int getContainerType() {
final Launcher launcher = getVisibleLauncher();
return launcher != null ? launcher.getStateManager().getState().containerType
@@ -350,54 +304,11 @@
}
@Override
- public void setOnDeferredActivityLaunchCallback(Runnable r) {
- Launcher launcher = getCreatedActivity();
- if (launcher == null) {
- return;
- }
- launcher.setOnDeferredActivityLaunchCallback(r);
- }
-
- @Override
- public void updateOverviewPredictionState() {
- Launcher launcher = getCreatedActivity();
- if (launcher == null) {
- return;
- }
- PredictionUiStateManager.INSTANCE.get(launcher).switchClient(
- PredictionUiStateManager.Client.OVERVIEW);
- }
-
- @Nullable
- @Override
- public DepthController getDepthController() {
- BaseQuickstepLauncher launcher = getCreatedActivity();
- if (launcher == null) {
- return null;
- }
- return launcher.getDepthController();
- }
-
- @Override
- public void getMultiWindowSize(Context context, DeviceProfile dp, PointF out) {
- DeviceProfile fullDp = dp.getFullScreenProfile();
- // Use availableWidthPx and availableHeightPx instead of widthPx and heightPx to
- // account for system insets
- out.set(fullDp.availableWidthPx, fullDp.availableHeightPx);
- float halfDividerSize = context.getResources()
- .getDimension(R.dimen.multi_window_task_divider_size) / 2;
-
- if (fullDp.isLandscape) {
- out.x = out.x / 2 - halfDividerSize;
- } else {
- out.y = out.y / 2 - halfDividerSize;
- }
- }
-
- @Override
- protected float getExtraSpace(Context context, DeviceProfile dp) {
- if (dp.isVerticalBarLayout()) {
- return 0;
+ protected float getExtraSpace(Context context, DeviceProfile dp,
+ PagedOrientationHandler orientationHandler) {
+ if (dp.isVerticalBarLayout() ||
+ hideShelfInTwoButtonLandscape(context, orientationHandler)) {
+ return 0;
} else {
Resources res = context.getResources();
if (showOverviewActions(context)) {
@@ -423,4 +334,5 @@
}
}
}
+
}
\ No newline at end of file
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandlerV2.java
new file mode 100644
index 0000000..fa7d268
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import static com.android.launcher3.LauncherState.NORMAL;
+
+import android.animation.AnimatorSet;
+import android.content.Context;
+import android.graphics.RectF;
+import android.os.UserHandle;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.BaseQuickstepLauncher;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.views.FloatingIconView;
+import com.android.quickstep.util.StaggeredWorkspaceAnim;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
+import com.android.systemui.shared.system.InputConsumerController;
+
+/**
+ * Temporary class to allow easier refactoring
+ */
+public class LauncherSwipeHandlerV2 extends
+ BaseSwipeUpHandlerV2<BaseQuickstepLauncher, RecentsView> {
+
+ public LauncherSwipeHandlerV2(Context context, RecentsAnimationDeviceState deviceState,
+ TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs,
+ boolean continuingLastGesture, InputConsumerController inputConsumer) {
+ super(context, deviceState, taskAnimationManager, gestureState, touchTimeMs,
+ continuingLastGesture, inputConsumer);
+ }
+
+
+ @Override
+ protected HomeAnimationFactory createHomeAnimationFactory(long duration) {
+ HomeAnimationFactory homeAnimFactory;
+ if (mActivity != null) {
+ final TaskView runningTaskView = mRecentsView.getRunningTaskView();
+ final View workspaceView;
+ if (runningTaskView != null
+ && runningTaskView.getTask().key.getComponent() != null) {
+ workspaceView = mActivity.getWorkspace().getFirstMatchForAppClose(
+ runningTaskView.getTask().key.getComponent().getPackageName(),
+ UserHandle.of(runningTaskView.getTask().key.userId));
+ } else {
+ workspaceView = null;
+ }
+ final RectF iconLocation = new RectF();
+ boolean canUseWorkspaceView =
+ workspaceView != null && workspaceView.isAttachedToWindow();
+ FloatingIconView floatingIconView = canUseWorkspaceView
+ ? FloatingIconView.getFloatingIconView(mActivity, workspaceView,
+ true /* hideOriginal */, iconLocation, false /* isOpening */)
+ : null;
+
+ mActivity.getRootView().setForceHideBackArrow(true);
+ mActivity.setHintUserWillBeActive();
+
+ homeAnimFactory = new HomeAnimationFactory(floatingIconView) {
+
+ @Override
+ public RectF getWindowTargetRect() {
+ if (canUseWorkspaceView) {
+ return iconLocation;
+ } else {
+ return super.getWindowTargetRect();
+ }
+ }
+
+ @NonNull
+ @Override
+ public AnimatorPlaybackController createActivityAnimationToHome() {
+ // Return an empty APC here since we have an non-user controlled animation
+ // to home.
+ long accuracy = 2 * Math.max(mDp.widthPx, mDp.heightPx);
+ return mActivity.getStateManager().createAnimationToNewWorkspace(
+ NORMAL, accuracy, 0 /* animComponents */);
+ }
+
+ @Override
+ public void playAtomicAnimation(float velocity) {
+ new StaggeredWorkspaceAnim(mActivity, velocity,
+ true /* animateOverviewScrim */).start();
+ }
+ };
+
+ } else {
+ homeAnimFactory = new HomeAnimationFactory(null) {
+ @Override
+ public AnimatorPlaybackController createActivityAnimationToHome() {
+ return AnimatorPlaybackController.wrap(new AnimatorSet(), duration);
+ }
+ };
+ mStateCallback.addChangeListener(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
+ isPresent -> mRecentsView.startHome());
+ }
+ return homeAnimFactory;
+ }
+
+ @Override
+ protected void finishRecentsControllerToHome(Runnable callback) {
+ mRecentsAnimationController.finish(
+ true /* toRecents */, callback, true /* sendUserLeaveHint */);
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
index d4c746f..0d49b2b 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -7,6 +7,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.testing.TestInformationHandler;
import com.android.launcher3.testing.TestProtocol;
+import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController;
import com.android.quickstep.util.LayoutUtils;
import com.android.systemui.shared.recents.model.Task;
@@ -35,7 +36,8 @@
case TestProtocol.REQUEST_BACKGROUND_TO_OVERVIEW_SWIPE_HEIGHT: {
final float swipeHeight =
- LayoutUtils.getShelfTrackingDistance(mContext, mDeviceProfile);
+ LayoutUtils.getShelfTrackingDistance(mContext, mDeviceProfile,
+ PagedOrientationHandler.HOME_ROTATED);
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) swipeHeight);
return response;
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
index a4670fd..33b7f12 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
@@ -46,6 +46,7 @@
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.util.ActivityTracker;
@@ -57,6 +58,7 @@
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsRootView;
import com.android.quickstep.fallback.RecentsState;
+import com.android.quickstep.util.RecentsAtomicAnimationFactory;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -345,6 +347,11 @@
dumpMisc(prefix + "\t", writer);
}
+ @Override
+ public AtomicAnimationFactory<RecentsState> createAtomicAnimationFactory() {
+ return new RecentsAtomicAnimationFactory<>(this, 0);
+ }
+
private AnimatorListenerAdapter resetStateListener() {
return new AnimatorListenerAdapter() {
@Override
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 8bffc78..ef3d174 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -85,7 +85,6 @@
import com.android.quickstep.util.AssistantUtilities;
import com.android.quickstep.util.ProtoTracer;
import com.android.quickstep.util.SplitScreenBounds;
-import com.android.quickstep.views.RecentsView;
import com.android.systemui.plugins.OverscrollPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.shared.recents.IOverviewProxy;
@@ -555,7 +554,6 @@
|| previousGestureState.isRecentsAnimationRunning()
? newBaseConsumer(previousGestureState, newGestureState, event)
: mResetGestureInputConsumer;
- // TODO(b/149880412): 2 button landscape mode is wrecked. Fixit!
if (mDeviceState.isGesturalNavMode()) {
handleOrientationSetup(base);
}
@@ -833,16 +831,16 @@
}
}
- private BaseSwipeUpHandler createLauncherSwipeHandler(GestureState gestureState,
- long touchTimeMs, boolean continuingLastGesture, boolean isLikelyToStartNewTask) {
- return new LauncherSwipeHandler(this, mDeviceState, mTaskAnimationManager,
+ private BaseSwipeUpHandler createLauncherSwipeHandler(
+ GestureState gestureState, long touchTimeMs, boolean continuingLastGesture) {
+ return new LauncherSwipeHandlerV2(this, mDeviceState, mTaskAnimationManager,
gestureState, touchTimeMs, continuingLastGesture, mInputConsumer);
}
- private BaseSwipeUpHandler createFallbackSwipeHandler(GestureState gestureState,
- long touchTimeMs, boolean continuingLastGesture, boolean isLikelyToStartNewTask) {
- return new FallbackSwipeHandler(this, mDeviceState, gestureState,
- mInputConsumer, isLikelyToStartNewTask, continuingLastGesture);
+ private BaseSwipeUpHandler createFallbackSwipeHandler(
+ GestureState gestureState, long touchTimeMs, boolean continuingLastGesture) {
+ return new FallbackSwipeHandler(this, mDeviceState, mTaskAnimationManager,
+ gestureState, touchTimeMs, continuingLastGesture, mInputConsumer);
}
protected boolean shouldNotifyBackGesture() {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java
index f958e6d..9242771 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -24,11 +24,13 @@
import android.os.Build;
import android.util.AttributeSet;
+import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.quickstep.FallbackActivityInterface;
import com.android.quickstep.RecentsActivity;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskKey;
@@ -38,7 +40,7 @@
public class FallbackRecentsView extends RecentsView<RecentsActivity>
implements StateListener<RecentsState> {
- private RunningTaskInfo mRunningTaskInfo;
+ private RunningTaskInfo mHomeTaskInfo;
public FallbackRecentsView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -67,16 +69,40 @@
return false;
}
- public void onGestureAnimationStart(RunningTaskInfo runningTaskInfo) {
- mRunningTaskInfo = runningTaskInfo;
- onGestureAnimationStart(runningTaskInfo == null ? -1 : runningTaskInfo.taskId);
+ /**
+ * When starting gesture interaction from home, we add a temporary invisible tile corresponding
+ * to the home task. This allows us to handle quick-switch similarly to a quick-switching
+ * from a foreground task.
+ */
+ public void onGestureAnimationStartOnHome(RunningTaskInfo homeTaskInfo) {
+ mHomeTaskInfo = homeTaskInfo;
+ onGestureAnimationStart(homeTaskInfo == null ? -1 : homeTaskInfo.taskId);
+ }
+
+ /**
+ * When the gesture ends and recents view become interactive, we also remove the temporary
+ * invisible tile added for the home task. This also pushes the remaining tiles back
+ * to the center.
+ */
+ @Override
+ public void onGestureAnimationEnd() {
+ super.onGestureAnimationEnd();
+ if (mHomeTaskInfo != null) {
+ TaskView tv = getTaskView(mHomeTaskInfo.taskId);
+ if (tv != null) {
+ PendingAnimation pa = createTaskDismissAnimation(tv, true, false, 150);
+ pa.addEndListener(e -> setCurrentTask(-1));
+ runDismissAnimation(pa);
+ }
+ }
}
@Override
public void setCurrentTask(int runningTaskId) {
super.setCurrentTask(runningTaskId);
- if (mRunningTaskInfo != null && mRunningTaskInfo.taskId != runningTaskId) {
- mRunningTaskInfo = null;
+ if (mHomeTaskInfo != null && mHomeTaskInfo.taskId != runningTaskId) {
+ mHomeTaskInfo = null;
+ setRunningTaskHidden(false);
}
}
@@ -85,7 +111,7 @@
// When quick-switching on 3p-launcher, we add a "dummy" tile corresponding to Launcher
// as well. This tile is never shown as we have setCurrentTaskHidden, but allows use to
// track the index of the next task appropriately, as if we are switching on any other app.
- if (mRunningTaskInfo != null && mRunningTaskInfo.taskId == mRunningTaskId) {
+ if (mHomeTaskInfo != null && mHomeTaskInfo.taskId == mRunningTaskId) {
// Check if the task list has running task
boolean found = false;
for (Task t : tasks) {
@@ -97,7 +123,7 @@
if (!found) {
ArrayList<Task> newList = new ArrayList<>(tasks.size() + 1);
newList.addAll(tasks);
- newList.add(Task.from(new TaskKey(mRunningTaskInfo), mRunningTaskInfo, false));
+ newList.add(Task.from(new TaskKey(mHomeTaskInfo), mHomeTaskInfo, false));
tasks = newList;
}
}
@@ -105,6 +131,15 @@
}
@Override
+ public void setRunningTaskHidden(boolean isHidden) {
+ if (mHomeTaskInfo != null) {
+ // Always keep the home task hidden
+ isHidden = true;
+ }
+ super.setRunningTaskHidden(isHidden);
+ }
+
+ @Override
public void setModalStateEnabled(boolean isModalState) {
super.setModalStateEnabled(isModalState);
if (isModalState) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index abe4af4..3a97216 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -21,7 +21,7 @@
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.Utilities.squaredTouchSlop;
-import static com.android.quickstep.LauncherSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW;
+import static com.android.quickstep.BaseSwipeUpHandlerV2.MIN_PROGRESS_FOR_OVERVIEW;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
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 6b0d7a3..ab9ec21 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
@@ -207,7 +207,7 @@
// Start the window animation on down to give more time for launcher to draw if the
// user didn't start the gesture over the back button
if (!mIsDeferredDownTarget) {
- startTouchTrackingForWindowAnimation(ev.getEventTime(), false);
+ startTouchTrackingForWindowAnimation(ev.getEventTime());
}
TraceHelper.INSTANCE.endSection(traceToken);
@@ -275,8 +275,7 @@
if (mIsDeferredDownTarget) {
// Deferred gesture, start the animation and gesture tracking once
// we pass the actual touch slop
- startTouchTrackingForWindowAnimation(
- ev.getEventTime(), isLikelyToStartNewTask);
+ startTouchTrackingForWindowAnimation(ev.getEventTime());
}
if (!mPassedWindowMoveSlop) {
mPassedWindowMoveSlop = true;
@@ -326,12 +325,11 @@
mInteractionHandler.onGestureStarted();
}
- private void startTouchTrackingForWindowAnimation(
- long touchTimeMs, boolean isLikelyToStartNewTask) {
+ private void startTouchTrackingForWindowAnimation(long touchTimeMs) {
ActiveGestureLog.INSTANCE.addLog("startRecentsAnimation");
mInteractionHandler = mHandlerFactory.newHandler(mGestureState, touchTimeMs,
- mTaskAnimationManager.isRecentsAnimationRunning(), isLikelyToStartNewTask);
+ mTaskAnimationManager.isRecentsAnimationRunning());
mInteractionHandler.setGestureEndCallback(this::onInteractionGestureFinished);
mMotionPauseDetector.setOnMotionPauseListener(mInteractionHandler::onMotionPauseChanged);
Intent intent = new Intent(mInteractionHandler.getLaunchIntent());
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java
index d22755e..b743d3f 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java
@@ -99,9 +99,6 @@
private void updateSourceStack(RemoteAnimationTargetCompat target) {
mSourceInsets.set(target.contentInsets);
mSourceStackBounds.set(target.screenSpaceBounds);
-
- // TODO: Should sourceContainerBounds already have this offset?
- mSourceStackBounds.offsetTo(target.position.x, target.position.y);
}
public void updateTargetRect(Rect targetRect) {
@@ -169,14 +166,14 @@
crop.offsetTo(0, 0);
float cornerRadius = 0f;
float scale = Math.max(mCurrentRect.width(), mTargetRect.width()) / crop.width();
+ mTmpMatrix.setTranslate(0, 0);
+ if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
+ mTmpMatrix.setTranslate(app.localBounds.left, app.localBounds.top);
+ }
if (app.mode == targetMode
&& app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
mTmpMatrix.setRectToRect(mSourceRect, mCurrentRect, ScaleToFit.FILL);
- if (app.localBounds != null) {
- mTmpMatrix.postTranslate(app.localBounds.left, app.localBounds.top);
- } else {
- mTmpMatrix.postTranslate(app.position.x, app.position.y);
- }
+ mTmpMatrix.postTranslate(app.localBounds.left, app.localBounds.top);
mCurrentClipRectF.roundOut(crop);
if (mSupportsRoundedCornersOnWindows) {
if (params.getCornerRadius() > -1) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
new file mode 100644
index 0000000..5b0d503
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 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.util;
+
+import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+
+import com.android.launcher3.anim.SpringAnimationBuilder;
+import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
+import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.quickstep.views.RecentsView;
+
+public class RecentsAtomicAnimationFactory<ACTIVITY_TYPE extends StatefulActivity, STATE_TYPE>
+ extends AtomicAnimationFactory<STATE_TYPE> {
+
+ public static final int INDEX_RECENTS_FADE_ANIM = AtomicAnimationFactory.NEXT_INDEX + 0;
+ public static final int INDEX_RECENTS_TRANSLATE_X_ANIM = AtomicAnimationFactory.NEXT_INDEX + 1;
+
+ private static final int MY_ANIM_COUNT = 2;
+ protected static final int NEXT_INDEX = AtomicAnimationFactory.NEXT_INDEX + MY_ANIM_COUNT;
+
+ protected final ACTIVITY_TYPE mActivity;
+
+ /**
+ * @param extraAnims number of animations supported by the subclass. This should not include
+ * the 2 animations supported by this class.
+ */
+ public RecentsAtomicAnimationFactory(ACTIVITY_TYPE activity, int extraAnims) {
+ super(MY_ANIM_COUNT + extraAnims);
+ mActivity = activity;
+ }
+
+ @Override
+ public Animator createStateElementAnimation(int index, float... values) {
+ switch (index) {
+ case INDEX_RECENTS_FADE_ANIM:
+ return ObjectAnimator.ofFloat(mActivity.getOverviewPanel(),
+ RecentsView.CONTENT_ALPHA, values);
+ case INDEX_RECENTS_TRANSLATE_X_ANIM: {
+ RecentsView rv = mActivity.getOverviewPanel();
+ return new SpringAnimationBuilder(mActivity)
+ .setMinimumVisibleChange(1f / rv.getPageOffsetScale())
+ .setDampingRatio(0.8f)
+ .setStiffness(250)
+ .setValues(values)
+ .build(rv, ADJACENT_PAGE_OFFSET);
+ }
+ default:
+ return super.createStateElementAnimation(index, values);
+ }
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java
index f4f7e9c..348c22d 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -116,7 +116,8 @@
if (mDp == null) {
return 1;
}
- mSizeStrategy.calculateTaskSize(mContext, mDp, mTaskRect);
+ mSizeStrategy.calculateTaskSize(mContext, mDp, mTaskRect,
+ mOrientationState.getOrientationHandler());
return mOrientationState.getFullScreenScaleAndPivot(mTaskRect, mDp, mPivot);
}
@@ -131,8 +132,6 @@
mThumbnailData.windowingMode = WINDOWING_MODE_FULLSCREEN;
mThumbnailPosition.set(runningTarget.screenSpaceBounds);
- // TODO: Should sourceContainerBounds already have this offset?
- mThumbnailPosition.offset(-mRunningTarget.position.x, -mRunningTarget.position.y);
mLayoutValid = false;
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/AllAppsEduView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/AllAppsEduView.java
new file mode 100644
index 0000000..df89f74
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/AllAppsEduView.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2020 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.views;
+
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.GradientDrawable;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.ViewGroup;
+
+import androidx.core.graphics.ColorUtils;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.util.Themes;
+import com.android.quickstep.util.MultiValueUpdateListener;
+
+/**
+ * View used to educate the user on how to access All Apps when in No Nav Button navigation mode.
+ */
+public class AllAppsEduView extends AbstractFloatingView {
+
+ private Launcher mLauncher;
+
+ private AnimatorSet mAnimation;
+
+ private GradientDrawable mCircle;
+ private GradientDrawable mGradient;
+
+ private int mCircleSizePx;
+ private int mPaddingPx;
+ private int mWidthPx;
+ private int mMaxHeightPx;
+
+ public AllAppsEduView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mCircle = (GradientDrawable) context.getDrawable(R.drawable.all_apps_edu_circle);
+ mCircleSizePx = getResources().getDimensionPixelSize(R.dimen.swipe_edu_circle_size);
+ mPaddingPx = getResources().getDimensionPixelSize(R.dimen.swipe_edu_padding);
+ mWidthPx = getResources().getDimensionPixelSize(R.dimen.swipe_edu_width);
+ mMaxHeightPx = getResources().getDimensionPixelSize(R.dimen.swipe_edu_max_height);
+ setWillNotDraw(false);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ mGradient.draw(canvas);
+ mCircle.draw(canvas);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mIsOpen = true;
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mIsOpen = false;
+ }
+
+ @Override
+ protected void handleClose(boolean animate) {
+ mLauncher.getDragLayer().removeView(this);
+ }
+
+ @Override
+ public void logActionCommand(int command) {
+ // TODO
+ }
+
+ @Override
+ protected boolean isOfType(int type) {
+ return (type & TYPE_ALL_APPS_EDU) != 0;
+ }
+
+ @Override
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ return mAnimation != null && mAnimation.isRunning();
+ }
+
+ private void playAnimation() {
+ if (mAnimation != null) {
+ return;
+ }
+ mAnimation = new AnimatorSet();
+
+ final Rect circleBoundsOg = new Rect(mCircle.getBounds());
+ final Rect gradientBoundsOg = new Rect(mGradient.getBounds());
+ final Rect temp = new Rect();
+ final float transY = mMaxHeightPx - mCircleSizePx - mPaddingPx;
+
+ // 1st: Circle alpha/scale
+ int firstPart = 600;
+ // 2nd: Circle animates upwards, Gradient alpha fades in, Gradient grows, All Apps hint
+ int secondPart = 1200;
+ int introDuration = firstPart + secondPart;
+
+ StateAnimationConfig config = new StateAnimationConfig();
+ config.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(ACCEL,
+ 0, 0.08f));
+ config.duration = secondPart;
+ config.userControlled = false;
+ AnimatorPlaybackController stateAnimationController =
+ mLauncher.getStateManager().createAnimationToNewWorkspace(ALL_APPS, config);
+ float maxAllAppsProgress = 0.15f;
+
+ ValueAnimator intro = ValueAnimator.ofFloat(0, 1f);
+ intro.setInterpolator(LINEAR);
+ intro.setDuration(introDuration);
+ intro.addUpdateListener((new MultiValueUpdateListener() {
+ FloatProp mCircleAlpha = new FloatProp(0, 255, 0, firstPart, LINEAR);
+ FloatProp mCircleScale = new FloatProp(2f, 1f, 0, firstPart, OVERSHOOT_1_7);
+ FloatProp mDeltaY = new FloatProp(0, transY, firstPart, secondPart, FAST_OUT_SLOW_IN);
+ FloatProp mGradientAlpha = new FloatProp(0, 255, firstPart, secondPart * 0.3f, LINEAR);
+
+ @Override
+ public void onUpdate(float progress) {
+ temp.set(circleBoundsOg);
+ temp.offset(0, (int) -mDeltaY.value);
+ Utilities.scaleRectAboutCenter(temp, mCircleScale.value);
+ mCircle.setBounds(temp);
+ mCircle.setAlpha((int) mCircleAlpha.value);
+ mGradient.setAlpha((int) mGradientAlpha.value);
+
+ temp.set(gradientBoundsOg);
+ temp.top -= mDeltaY.value;
+ mGradient.setBounds(temp);
+ invalidate();
+
+ float stateProgress = Utilities.mapToRange(mDeltaY.value, 0, transY, 0,
+ maxAllAppsProgress, LINEAR);
+ stateAnimationController.setPlayFraction(stateProgress);
+ }
+ }));
+ intro.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mCircle.setAlpha(0);
+ mGradient.setAlpha(0);
+ }
+ });
+ mAnimation.play(intro);
+
+ ValueAnimator closeAllApps = ValueAnimator.ofFloat(maxAllAppsProgress, 0f);
+ closeAllApps.addUpdateListener(valueAnimator -> {
+ stateAnimationController.setPlayFraction((float) valueAnimator.getAnimatedValue());
+ });
+ closeAllApps.setInterpolator(FAST_OUT_SLOW_IN);
+ closeAllApps.setStartDelay(introDuration);
+ closeAllApps.setDuration(250);
+ mAnimation.play(closeAllApps);
+
+ mAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAnimation = null;
+ stateAnimationController.dispatchOnCancel();
+ handleClose(false);
+ }
+ });
+ mAnimation.start();
+ }
+
+ private void init(Launcher launcher) {
+ mLauncher = launcher;
+
+ int accentColor = Themes.getColorAccent(launcher);
+ mGradient = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM,
+ Themes.getAttrBoolean(launcher, R.attr.isMainColorDark)
+ ? new int[] {0xB3FFFFFF, 0x00FFFFFF}
+ : new int[] {ColorUtils.setAlphaComponent(accentColor, 127),
+ ColorUtils.setAlphaComponent(accentColor, 0)});
+ float r = mWidthPx / 2f;
+ mGradient.setCornerRadii(new float[] {r, r, r, r, 0, 0, 0, 0});
+
+ int top = mMaxHeightPx - mCircleSizePx + mPaddingPx;
+ mCircle.setBounds(mPaddingPx, top, mPaddingPx + mCircleSizePx, top + mCircleSizePx);
+ mGradient.setBounds(0, mMaxHeightPx - mCircleSizePx, mWidthPx, mMaxHeightPx);
+
+ DeviceProfile grid = launcher.getDeviceProfile();
+ DragLayer.LayoutParams lp = new DragLayer.LayoutParams(mWidthPx, mMaxHeightPx);
+ lp.ignoreInsets = true;
+ lp.leftMargin = (grid.widthPx - mWidthPx) / 2;
+ lp.topMargin = grid.heightPx - grid.hotseatBarSizePx - mMaxHeightPx;
+ setLayoutParams(lp);
+ }
+
+ /**
+ * Shows the All Apps education view and plays the animation.
+ */
+ public static void show(Launcher launcher) {
+ final DragLayer dragLayer = launcher.getDragLayer();
+ ViewGroup parent = (ViewGroup) dragLayer.getParent();
+ AllAppsEduView view = launcher.getViewCache().getView(R.layout.all_apps_edu_view,
+ launcher, parent);
+ view.init(launcher);
+ launcher.getDragLayer().addView(view);
+ view.requestLayout();
+ view.playAnimation();
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/ClearAllButton.java
index 2c85618..fd74357 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/ClearAllButton.java
@@ -47,24 +47,21 @@
private boolean mIsRtl;
private int mScrollOffset;
- private RecentsView mParent;
public ClearAllButton(Context context, AttributeSet attrs) {
super(context, attrs);
+ mIsRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- PagedOrientationHandler orientationHandler = mParent.getPagedOrientationHandler();
- mScrollOffset = orientationHandler.getClearAllScrollOffset(mParent, mIsRtl);
+ PagedOrientationHandler orientationHandler = getRecentsView().getPagedOrientationHandler();
+ mScrollOffset = orientationHandler.getClearAllScrollOffset(getRecentsView(), mIsRtl);
}
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- mParent = (RecentsView) getParent();
- mIsRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ private RecentsView getRecentsView() {
+ return (RecentsView) getParent();
}
@Override
@@ -94,7 +91,7 @@
@Override
public void onPageScroll(ScrollState scrollState) {
- PagedOrientationHandler orientationHandler = mParent.getPagedOrientationHandler();
+ PagedOrientationHandler orientationHandler = getRecentsView().getPagedOrientationHandler();
float orientationSize = orientationHandler.getPrimaryValue(getWidth(), getHeight());
if (orientationSize == 0) {
return;
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 3fc235c..3273e85 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
@@ -17,6 +17,8 @@
package com.android.quickstep.views;
import static android.view.Surface.ROTATION_0;
+import static android.view.View.MeasureSpec.EXACTLY;
+import static android.view.View.MeasureSpec.makeMeasureSpec;
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS;
@@ -827,6 +829,10 @@
@Override
public void setInsets(Rect insets) {
mInsets.set(insets);
+ resetPaddingFromTaskSize();
+ }
+
+ private void resetPaddingFromTaskSize() {
DeviceProfile dp = mActivity.getDeviceProfile();
mOrientationState.setMultiWindowMode(dp.isMultiWindowMode);
getTaskSize(mTempRect);
@@ -840,7 +846,8 @@
}
public void getTaskSize(Rect outRect) {
- mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(), outRect);
+ mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(), outRect,
+ mOrientationHandler);
}
/** Gets the task size for modal state. */
@@ -1075,9 +1082,9 @@
* Called when a gesture from an app has finished.
*/
public void onGestureAnimationEnd() {
+ setOnScrollChangeListener(null);
setEnableFreeScroll(true);
setEnableDrawingLiveTile(true);
- setOnScrollChangeListener(null);
if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) {
setRunningTaskViewShowScreenshot(true);
}
@@ -1108,6 +1115,12 @@
false, true, false, false, new ActivityManager.TaskDescription(), 0,
new ComponentName("", ""), false);
taskView.bind(mTmpRunningTask, mOrientationState);
+
+ // Measure and layout immediately so that the scroll values is updated instantly
+ // as the user might be quick-switching
+ measure(makeMeasureSpec(getMeasuredWidth(), EXACTLY),
+ makeMeasureSpec(getMeasuredHeight(), EXACTLY));
+ layout(getLeft(), getTop(), getRight(), getBottom());
}
boolean runningTaskTileHidden = mRunningTaskTileHidden;
@@ -1484,7 +1497,7 @@
return true;
}
- private void runDismissAnimation(PendingAnimation pendingAnim) {
+ protected void runDismissAnimation(PendingAnimation pendingAnim) {
AnimatorPlaybackController controller = pendingAnim.createPlaybackController();
controller.dispatchOnStart();
controller.setEndAction(() -> pendingAnim.finish(true, Touch.SWIPE));
@@ -1618,6 +1631,7 @@
mActivity.getDragLayer().recreateControllers();
mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION,
touchRotation != 0 || mOrientationState.getLauncherRotation() != ROTATION_0);
+ resetPaddingFromTaskSize();
requestLayout();
}
}
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 a3e360f..e3c1b42 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
@@ -472,7 +472,6 @@
} else {
setThumbnailRotation(deltaRotate, thumbnailInsets, scale, thumbnailPosition);
}
- mMatrix.postTranslate(-thumbnailPosition.left, -thumbnailPosition.top);
final float widthWithInsets;
final float heightWithInsets;
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index f1ea6bb..9d70316 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -92,4 +92,10 @@
<dimen name="gesture_tutorial_subtitle_margin_start_end">16dp</dimen>
<dimen name="gesture_tutorial_feedback_margin_start_end">24dp</dimen>
<dimen name="gesture_tutorial_button_margin_start_end">18dp</dimen>
+
+ <!-- All Apps Education tutorial -->
+ <dimen name="swipe_edu_padding">8dp</dimen>
+ <dimen name="swipe_edu_circle_size">64dp</dimen>
+ <dimen name="swipe_edu_width">80dp</dimen>
+ <dimen name="swipe_edu_max_height">184dp</dimen>
</resources>
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index e5c9fc9..8745814 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -32,6 +32,7 @@
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.animation.Interpolator;
@@ -43,6 +44,7 @@
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.AbstractStateChangeTouchController;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.uioverrides.states.OverviewState;
@@ -51,6 +53,7 @@
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TouchInteractionService;
import com.android.quickstep.util.LayoutUtils;
+import com.android.quickstep.views.RecentsView;
/**
* Touch controller for handling various state transitions in portrait UI.
@@ -129,11 +132,22 @@
@Override
protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS, "PortraitStatesTouchController.getTargetState");
+ }
if (fromState == ALL_APPS && !isDragTowardPositive) {
// Should swipe down go to OVERVIEW instead?
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS,
+ "PortraitStatesTouchController.getTargetState 1");
+ }
return TouchInteractionService.isConnected() ?
mLauncher.getStateManager().getLastState() : NORMAL;
} else if (fromState == OVERVIEW) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS,
+ "PortraitStatesTouchController.getTargetState 2");
+ }
LauncherState positiveDragTarget = ALL_APPS;
if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(mLauncher)) {
// Don't allow swiping up to all apps.
@@ -141,6 +155,10 @@
}
return isDragTowardPositive ? positiveDragTarget : NORMAL;
} else if (fromState == NORMAL && isDragTowardPositive) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS,
+ "PortraitStatesTouchController.getTargetState 3");
+ }
int stateFlags = SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags();
return mAllowDragToOverview && TouchInteractionService.isConnected()
&& (stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0
@@ -244,8 +262,9 @@
mCurrentAnimation = mPendingAnimation.createPlaybackController()
.setOnCancelRunnable(onCancelRunnable);
mLauncher.getStateManager().setCurrentUserControlledAnimation(mCurrentAnimation);
+ RecentsView recentsView = mLauncher.getOverviewPanel();
totalShift = LayoutUtils.getShelfTrackingDistance(mLauncher,
- mLauncher.getDeviceProfile());
+ mLauncher.getDeviceProfile(), recentsView.getPagedOrientationHandler());
} else {
mCurrentAnimation = mLauncher.getStateManager()
.createAnimationToNewWorkspace(mToState, config)
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index f29f0ff..9124925 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -15,14 +15,24 @@
*/
package com.android.quickstep;
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.anim.Interpolators.ACCEL_2;
+import static com.android.launcher3.anim.Interpolators.INSTANT;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
+import static com.android.quickstep.BaseSwipeUpHandlerV2.RECENTS_ATTACH_DURATION;
import static com.android.quickstep.SysUINavigationMode.getMode;
+import static com.android.quickstep.SysUINavigationMode.hideShelfInTwoButtonLandscape;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
+import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM;
+import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_TRANSLATE_X_ANIM;
+import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
+import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
+import android.animation.Animator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Build;
import android.view.MotionEvent;
@@ -34,9 +44,11 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.WindowBounds;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.util.ActivityInitListener;
@@ -56,11 +68,15 @@
public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_TYPE>,
ACTIVITY_TYPE extends StatefulActivity<STATE_TYPE>> {
- private final PointF mTempPoint = new PointF();
public final boolean rotationSupportedByActivity;
- protected BaseActivityInterface(boolean rotationSupportedByActivity) {
+ private final STATE_TYPE mOverviewState, mBackgroundState;
+
+ protected BaseActivityInterface(boolean rotationSupportedByActivity,
+ STATE_TYPE overviewState, STATE_TYPE backgroundState) {
this.rotationSupportedByActivity = rotationSupportedByActivity;
+ mOverviewState = overviewState;
+ mBackgroundState = backgroundState;
}
public void onTransitionCancelled(boolean activityVisible) {
@@ -73,7 +89,8 @@
}
public abstract int getSwipeUpDestinationAndLength(
- DeviceProfile dp, Context context, Rect outRect);
+ DeviceProfile dp, Context context, Rect outRect,
+ PagedOrientationHandler orientationHandler);
public void onSwipeUpToRecentsComplete() {
// Re apply state in case we did something funky during the transition.
@@ -84,7 +101,7 @@
activity.getStateManager().reapplyState();
}
- public void onSwipeUpToHomeComplete() { }
+ public abstract void onSwipeUpToHomeComplete();
public abstract void onAssistantVisibilityChanged(float visibility);
@@ -130,9 +147,12 @@
public abstract boolean allowMinimizeSplitScreen();
public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) {
- return true;
+ return deviceState.isInDeferredGestureRegion(ev);
}
+ public abstract void onExitOverview(RecentsAnimationDeviceState deviceState,
+ Runnable exitRunnable);
+
/**
* Updates the prediction state to the overview state.
*/
@@ -174,26 +194,24 @@
recentsView.switchToScreenshot(thumbnailData, runnable);
}
- public void setHintUserWillBeActive() {}
-
- /**
- * Sets the expected window size in multi-window mode
- */
- public abstract void getMultiWindowSize(Context context, DeviceProfile dp, PointF out);
-
/**
* Calculates the taskView size for the provided device configuration
*/
- public final void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect) {
- calculateTaskSize(context, dp, getExtraSpace(context, dp), outRect);
+ public final void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect,
+ PagedOrientationHandler orientedState) {
+ calculateTaskSize(context, dp, getExtraSpace(context, dp, orientedState),
+ outRect, orientedState);
}
- protected abstract float getExtraSpace(Context context, DeviceProfile dp);
+ protected abstract float getExtraSpace(Context context, DeviceProfile dp,
+ PagedOrientationHandler orientedState);
private void calculateTaskSize(
- Context context, DeviceProfile dp, float extraVerticalSpace, Rect outRect) {
+ Context context, DeviceProfile dp, float extraVerticalSpace, Rect outRect,
+ PagedOrientationHandler orientationHandler) {
Resources res = context.getResources();
- final boolean showLargeTaskSize = showOverviewActions(context);
+ final boolean showLargeTaskSize = showOverviewActions(context) ||
+ hideShelfInTwoButtonLandscape(context, orientationHandler);
final int paddingResId;
if (dp.isMultiWindowMode) {
@@ -251,7 +269,7 @@
/**
* Calculates the modal taskView size for the provided device configuration
*/
- public void calculateModalTaskSize(Context context, DeviceProfile dp, Rect outRect) {
+ public final void calculateModalTaskSize(Context context, DeviceProfile dp, Rect outRect) {
float paddingHorz = context.getResources().getDimension(dp.isMultiWindowMode
? R.dimen.multi_window_task_card_horz_space
: dp.isVerticalBarLayout()
@@ -265,7 +283,7 @@
}
/** Gets the space that the overview actions will take, including margins. */
- public float getOverviewActionsHeight(Context context) {
+ public final float getOverviewActionsHeight(Context context) {
Resources res = context.getResources();
float actionsBottomMargin = 0;
if (getMode(context) == Mode.THREE_BUTTONS) {
@@ -282,8 +300,6 @@
public interface AnimationFactory {
- default void onRemoteAnimationReceived(RemoteAnimationTargets targets) { }
-
void createActivityInterface(long transitionLength);
default void onTransitionCancelled() { }
@@ -299,6 +315,97 @@
default void setRecentsAttachedToAppWindow(boolean attached, boolean animate) { }
}
+ class DefaultAnimationFactory implements AnimationFactory {
+
+ protected final ACTIVITY_TYPE mActivity;
+ private final STATE_TYPE mStartState;
+ private final Consumer<AnimatorPlaybackController> mCallback;
+
+ private boolean mIsAttachedToWindow;
+
+ DefaultAnimationFactory(Consumer<AnimatorPlaybackController> callback) {
+ mCallback = callback;
+
+ mActivity = getCreatedActivity();
+ mStartState = mActivity.getStateManager().getState();
+ }
+
+ protected ACTIVITY_TYPE initUI() {
+ STATE_TYPE resetState = mStartState;
+ if (mStartState.shouldDisableRestore()) {
+ resetState = mActivity.getStateManager().getRestState();
+ }
+ mActivity.getStateManager().setRestState(resetState);
+ mActivity.getStateManager().goToState(mBackgroundState, false);
+ return mActivity;
+ }
+
+ @Override
+ public void createActivityInterface(long transitionLength) {
+ PendingAnimation pa = new PendingAnimation(transitionLength * 2);
+ createBackgroundToOverviewAnim(mActivity, pa);
+ AnimatorPlaybackController controller = pa.createPlaybackController();
+ mActivity.getStateManager().setCurrentUserControlledAnimation(controller);
+
+ // Since we are changing the start position of the UI, reapply the state, at the end
+ controller.setEndAction(() -> mActivity.getStateManager().goToState(
+ controller.getInterpolatedProgress() > 0.5 ? mOverviewState : mBackgroundState,
+ false));
+ mCallback.accept(controller);
+
+ // Creating the activity controller animation sometimes reapplies the launcher state
+ // (because we set the animation as the current state animation), so we reapply the
+ // attached state here as well to ensure recents is shown/hidden appropriately.
+ if (SysUINavigationMode.getMode(mActivity) == Mode.NO_BUTTON) {
+ setRecentsAttachedToAppWindow(mIsAttachedToWindow, false);
+ }
+ }
+
+ @Override
+ public void onTransitionCancelled() {
+ mActivity.getStateManager().goToState(mStartState, false /* animate */);
+ }
+
+ @Override
+ public void setRecentsAttachedToAppWindow(boolean attached, boolean animate) {
+ if (mIsAttachedToWindow == attached && animate) {
+ return;
+ }
+ mIsAttachedToWindow = attached;
+ RecentsView recentsView = mActivity.getOverviewPanel();
+ Animator fadeAnim = mActivity.getStateManager()
+ .createStateElementAnimation(INDEX_RECENTS_FADE_ANIM, attached ? 1 : 0);
+
+ float fromTranslation = attached ? 1 : 0;
+ float toTranslation = attached ? 0 : 1;
+ mActivity.getStateManager()
+ .cancelStateElementAnimation(INDEX_RECENTS_TRANSLATE_X_ANIM);
+ if (!recentsView.isShown() && animate) {
+ ADJACENT_PAGE_OFFSET.set(recentsView, fromTranslation);
+ } else {
+ fromTranslation = ADJACENT_PAGE_OFFSET.get(recentsView);
+ }
+ if (!animate) {
+ ADJACENT_PAGE_OFFSET.set(recentsView, toTranslation);
+ } else {
+ mActivity.getStateManager().createStateElementAnimation(
+ INDEX_RECENTS_TRANSLATE_X_ANIM,
+ fromTranslation, toTranslation).start();
+ }
+
+ fadeAnim.setInterpolator(attached ? INSTANT : ACCEL_2);
+ fadeAnim.setDuration(animate ? RECENTS_ATTACH_DURATION : 0).start();
+ }
+
+ protected void createBackgroundToOverviewAnim(ACTIVITY_TYPE activity, PendingAnimation pa) {
+ // Scale down recents from being full screen to being in overview.
+ RecentsView recentsView = activity.getOverviewPanel();
+ pa.addFloat(recentsView, SCALE_PROPERTY,
+ recentsView.getMaxScaleForFullScreen(), 1, LINEAR);
+ pa.addFloat(recentsView, FULLSCREEN_PROGRESS, 1, 0, LINEAR);
+ }
+ }
+
protected static boolean showOverviewActions(Context context) {
return ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context);
}
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index 016ffea..ffa41fd 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -24,6 +24,7 @@
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.quickstep.util.ActiveGestureLog;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -278,6 +279,7 @@
public void setEndTarget(GestureEndTarget target, boolean isAtomic) {
mEndTarget = target;
mStateCallback.setState(STATE_END_TARGET_SET);
+ ActiveGestureLog.INSTANCE.addLog("setEndTarget " + mEndTarget);
if (isAtomic) {
mStateCallback.setState(STATE_END_TARGET_ANIMATION_FINISHED);
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index a892ddc..1da7ccf 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -45,7 +45,6 @@
import android.os.Process;
import android.os.UserManager;
import android.text.TextUtils;
-import android.util.Log;
import android.view.MotionEvent;
import androidx.annotation.BinderThread;
@@ -107,7 +106,7 @@
if (frozen) {
return;
}
- mOrientationTouchTransformer.enableMultipleRegions(false, mDefaultDisplay.getInfo());
+ enableMultipleRegions(false);
}
};
@@ -118,6 +117,13 @@
private final List<ComponentName> mGestureBlockedActivities;
private Runnable mOnDestroyFrozenTaskRunnable;
+ /**
+ * Set to true when user swipes to recents. In recents, we ignore the state of the recents
+ * task list being frozen or not to allow the user to keep interacting with nav bar rotation
+ * they went into recents with as opposed to defaulting to the default display rotation.
+ * TODO: (b/156984037) For when user rotates after entering overview
+ */
+ private boolean mInOverview;
public RecentsAnimationDeviceState(Context context) {
mContext = context;
@@ -508,7 +514,18 @@
mOrientationTouchTransformer.transform(event);
}
+ void onSwipeUpToOverview(BaseActivityInterface activityInterface) {
+ mInOverview = true;
+ activityInterface.onExitOverview(this, () -> {
+ mInOverview = false;
+ enableMultipleRegions(false);
+ });
+ }
+
void enableMultipleRegions(boolean enable) {
+ if (mInOverview) {
+ return;
+ }
mOrientationTouchTransformer.enableMultipleRegions(enable, mDefaultDisplay.getInfo());
UI_HELPER_EXECUTOR.execute(() -> {
int quickStepStartingRotation =
diff --git a/quickstep/src/com/android/quickstep/SysUINavigationMode.java b/quickstep/src/com/android/quickstep/SysUINavigationMode.java
index c715c93..05ce2a2 100644
--- a/quickstep/src/com/android/quickstep/SysUINavigationMode.java
+++ b/quickstep/src/com/android/quickstep/SysUINavigationMode.java
@@ -24,6 +24,7 @@
import android.content.res.Resources;
import android.util.Log;
+import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.MainThreadInitializedObject;
import java.io.PrintWriter;
@@ -134,6 +135,12 @@
return getMode(context) != Mode.TWO_BUTTONS;
}
+ public static boolean hideShelfInTwoButtonLandscape(Context context,
+ PagedOrientationHandler pagedOrientationHandler) {
+ return getMode(context) == Mode.TWO_BUTTONS &&
+ !pagedOrientationHandler.isLayoutNaturalToLauncher();
+ }
+
public void dump(PrintWriter pw) {
pw.println("SysUINavigationMode:");
pw.println(" mode=" + mMode.name());
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index c1b276a..3f58e01 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -25,6 +25,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
+import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.SysUINavigationMode;
@@ -41,11 +42,13 @@
return swipeHeight;
}
- public static int getShelfTrackingDistance(Context context, DeviceProfile dp) {
+ public static int getShelfTrackingDistance(Context context, DeviceProfile dp,
+ PagedOrientationHandler orientationHandler) {
// Track the bottom of the window.
if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context)) {
Rect taskSize = new Rect();
- LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, taskSize);
+ LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, taskSize,
+ orientationHandler);
return (dp.heightPx - taskSize.height()) / 2;
}
int shelfHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
index 2d8bba2..7e8222c 100644
--- a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
+++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
@@ -15,20 +15,27 @@
*/
package com.android.quickstep.util;
+import static com.android.launcher3.AbstractFloatingView.TYPE_ALL_APPS_EDU;
+import static com.android.launcher3.AbstractFloatingView.getOpenView;
import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.HINT_STATE;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
+import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import android.content.SharedPreferences;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.quickstep.SysUINavigationMode;
+import com.android.quickstep.views.AllAppsEduView;
/**
* Extends {@link OnboardingPrefs} for quickstep-specific onboarding data.
@@ -92,5 +99,51 @@
}
});
}
+
+ if (SysUINavigationMode.getMode(launcher) == NO_BUTTON
+ && FeatureFlags.ENABLE_ALL_APPS_EDU.get()) {
+ stateManager.addStateListener(new StateListener<LauncherState>() {
+ private static final int MAX_NUM_SWIPES_TO_TRIGGER_EDU = 3;
+
+ // Counts the number of consecutive swipes on nav bar without moving screens.
+ private int mCount = 0;
+ private boolean mShouldIncreaseCount;
+
+ @Override
+ public void onStateTransitionStart(LauncherState toState) {
+ if (toState == NORMAL) {
+ return;
+ }
+ mShouldIncreaseCount = toState == HINT_STATE
+ && launcher.getWorkspace().getNextPage() == Workspace.DEFAULT_PAGE;
+ }
+
+ @Override
+ public void onStateTransitionComplete(LauncherState finalState) {
+ if (finalState == NORMAL) {
+ if (mCount == MAX_NUM_SWIPES_TO_TRIGGER_EDU) {
+ if (getOpenView(mLauncher, TYPE_ALL_APPS_EDU) == null) {
+ AllAppsEduView.show(launcher);
+ }
+ mCount = 0;
+ }
+ return;
+ }
+
+ if (mShouldIncreaseCount && finalState == HINT_STATE) {
+ mCount++;
+ } else {
+ mCount = 0;
+ }
+
+ if (finalState == ALL_APPS) {
+ AllAppsEduView view = getOpenView(mLauncher, TYPE_ALL_APPS_EDU);
+ if (view != null) {
+ view.close(false);
+ }
+ }
+ }
+ });
+ }
}
}
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index bed8278..1aa3144 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -59,6 +59,7 @@
TYPE_DISCOVERY_BOUNCE,
TYPE_SNACKBAR,
TYPE_LISTENER,
+ TYPE_ALL_APPS_EDU,
TYPE_TASK_MENU,
TYPE_OPTIONS_POPUP
@@ -74,25 +75,28 @@
public static final int TYPE_DISCOVERY_BOUNCE = 1 << 6;
public static final int TYPE_SNACKBAR = 1 << 7;
public static final int TYPE_LISTENER = 1 << 8;
+ public static final int TYPE_ALL_APPS_EDU = 1 << 9;
// Popups related to quickstep UI
- public static final int TYPE_TASK_MENU = 1 << 9;
- public static final int TYPE_OPTIONS_POPUP = 1 << 10;
+ public static final int TYPE_TASK_MENU = 1 << 10;
+ public static final int TYPE_OPTIONS_POPUP = 1 << 11;
public static final int TYPE_ALL = TYPE_FOLDER | TYPE_ACTION_POPUP
| TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_WIDGETS_FULL_SHEET
| TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE | TYPE_TASK_MENU
- | TYPE_OPTIONS_POPUP | TYPE_SNACKBAR | TYPE_LISTENER;
+ | TYPE_OPTIONS_POPUP | TYPE_SNACKBAR | TYPE_LISTENER | TYPE_ALL_APPS_EDU;
// Type of popups which should be kept open during launcher rebind
public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET
- | TYPE_WIDGETS_BOTTOM_SHEET | TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE;
+ | TYPE_WIDGETS_BOTTOM_SHEET | TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE
+ | TYPE_ALL_APPS_EDU;
// Usually we show the back button when a floating view is open. Instead, hide for these types.
public static final int TYPE_HIDE_BACK_BUTTON = TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE
| TYPE_SNACKBAR | TYPE_WIDGET_RESIZE_FRAME | TYPE_LISTENER;
- public static final int TYPE_ACCESSIBLE = TYPE_ALL & ~TYPE_DISCOVERY_BOUNCE & ~TYPE_LISTENER;
+ public static final int TYPE_ACCESSIBLE = TYPE_ALL & ~TYPE_DISCOVERY_BOUNCE & ~TYPE_LISTENER
+ & ~TYPE_ALL_APPS_EDU;
// These view all have particular operation associated with swipe down interaction.
public static final int TYPE_STATUS_BAR_SWIPE_DOWN_DISALLOW = TYPE_WIDGETS_BOTTOM_SHEET |
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index be941f2..1c157c2 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -38,6 +38,8 @@
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mHasVerticalHotseat;
+ private Workspace mWorkspace;
+ private boolean mSendTouchToWorkspace;
public Hotseat(Context context) {
this(context, null);
@@ -112,8 +114,35 @@
InsettableFrameLayout.dispatchInsets(this, insets);
}
+ public void setWorkspace(Workspace w) {
+ mWorkspace = w;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ // We allow horizontal workspace scrolling from within the Hotseat. We do this by delegating
+ // touch intercept the Workspace, and if it intercepts, delegating touch to the Workspace
+ // for the remainder of the this input stream.
+ int yThreshold = getMeasuredHeight() - getPaddingBottom();
+ if (mWorkspace != null && ev.getY() <= yThreshold) {
+ mSendTouchToWorkspace = mWorkspace.onInterceptTouchEvent(ev);
+ return mSendTouchToWorkspace;
+ }
+ return false;
+ }
+
@Override
public boolean onTouchEvent(MotionEvent event) {
+ // See comment in #onInterceptTouchEvent
+ if (mSendTouchToWorkspace) {
+ final int action = event.getAction();
+ switch (action & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ mSendTouchToWorkspace = false;
+ }
+ return mWorkspace.onTouchEvent(event);
+ }
return event.getY() > getCellHeight();
}
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 59476dd..1f84c42 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1116,6 +1116,7 @@
mWorkspace.initParentViews(mDragLayer);
mOverviewPanel = findViewById(R.id.overview_panel);
mHotseat = findViewById(R.id.hotseat);
+ mHotseat.setWorkspace(mWorkspace);
mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 87ead9e..535c9e6 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -153,12 +153,16 @@
public static final int CONTAINER_PREDICTION = -102;
public static final int CONTAINER_HOTSEAT_PREDICTION = -103;
public static final int CONTAINER_ALL_APPS = -104;
+ public static final int CONTAINER_WIDGETS_TRAY = -105;
+
public static final String containerToString(int container) {
switch (container) {
case CONTAINER_DESKTOP: return "desktop";
case CONTAINER_HOTSEAT: return "hotseat";
case CONTAINER_PREDICTION: return "prediction";
+ case CONTAINER_ALL_APPS: return "all_apps";
+ case CONTAINER_WIDGETS_TRAY: return "widgets_tray";
default: return String.valueOf(container);
}
}
diff --git a/src/com/android/launcher3/PendingAddItemInfo.java b/src/com/android/launcher3/PendingAddItemInfo.java
index 29c9d93..be994ee 100644
--- a/src/com/android/launcher3/PendingAddItemInfo.java
+++ b/src/com/android/launcher3/PendingAddItemInfo.java
@@ -18,12 +18,15 @@
import android.content.ComponentName;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.model.data.ItemInfo;
+import java.util.Optional;
+
/**
- * Meta data that is used for deferred binding.
- * e.g., this object is used to pass information on draggable targets when they are dropped onto
- * the workspace from another container.
+ * Meta data that is used for deferred binding. e.g., this object is used to pass information on
+ * draggable targets when they are dropped onto the workspace from another container.
*/
public class PendingAddItemInfo extends ItemInfo {
@@ -36,4 +39,22 @@
protected String dumpProperties() {
return super.dumpProperties() + " componentName=" + componentName;
}
+
+ /**
+ * Returns shallow copy of the object.
+ */
+ @Override
+ public ItemInfo makeShallowCopy() {
+ PendingAddItemInfo itemInfo = new PendingAddItemInfo();
+ itemInfo.copyFrom(this);
+ itemInfo.componentName = this.componentName;
+ return itemInfo;
+ }
+
+ @Nullable
+ @Override
+ public ComponentName getTargetComponent() {
+ return Optional.ofNullable(super.getTargetComponent()).orElse(componentName);
+ }
+
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 286b522..6b660c1 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -2438,6 +2438,10 @@
// widgets/shortcuts/folders in a slightly different way
mLauncher.addPendingItem(pendingInfo, container, screenId, mTargetCell,
item.spanX, item.spanY);
+ mStatsLogManager.log(
+ LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
+ d.logInstanceId,
+ d.dragInfo.buildProto(null));
}
};
boolean isWidget = pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
@@ -2526,11 +2530,12 @@
mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, view, this);
resetTransitionTransform();
}
+ mStatsLogManager.log(
+ LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
+ d.logInstanceId,
+ d.dragInfo.buildProto(null));
}
- mStatsLogManager.log(
- LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
- d.logInstanceId,
- d.dragInfo.buildProto(null));
+
}
public Bitmap createWidgetBitmap(ItemInfo widgetInfo, View layout) {
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 6919339..869dbbc 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -164,6 +164,10 @@
"ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS", false,
"Always use hardware optimization for folder animations.");
+ public static final BooleanFlag ENABLE_ALL_APPS_EDU = getDebugFlag(
+ "ENABLE_ALL_APPS_EDU", true,
+ "Shows user a tutorial on how to get to All Apps after X amount of attempts.");
+
public static void initialize(Context context) {
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index f2b7e54..a97d529 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
@@ -342,6 +343,11 @@
.setAllAppsContainer(
AllAppsContainer.getDefaultInstance())
.build();
+ case CONTAINER_WIDGETS_TRAY:
+ return ContainerInfo.newBuilder()
+ .setWidgetsContainer(
+ LauncherAtom.WidgetsContainer.getDefaultInstance())
+ .build();
}
return ContainerInfo.getDefaultInstance();
}
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index 97dc052..44f7db9 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -554,6 +554,8 @@
*/
public static class AtomicAnimationFactory<STATE_TYPE> {
+ protected static final int NEXT_INDEX = 0;
+
private final Animator[] mStateElementAnimators;
/**
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 52e2ab8..2e63ccf 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -201,7 +201,7 @@
mToState = newToState;
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS, "reinitCurrentAnimation: "
- + newToState.ordinal);
+ + newToState.ordinal + " " + getClass().getSimpleName());
}
mStartProgress = 0;
diff --git a/src/com/android/launcher3/util/ShortcutUtil.java b/src/com/android/launcher3/util/ShortcutUtil.java
index 1ec0690..91cf835 100644
--- a/src/com/android/launcher3/util/ShortcutUtil.java
+++ b/src/com/android/launcher3/util/ShortcutUtil.java
@@ -34,7 +34,7 @@
* Returns true when we should show depp shortcuts in shortcut menu for the item.
*/
public static boolean supportsDeepShortcuts(ItemInfo info) {
- return isActive(info) && isApp(info);
+ return isActive(info) && isApp(info) && !WidgetsModel.GO_DISABLE_WIDGETS;
}
/**
@@ -64,7 +64,7 @@
private static boolean isActive(ItemInfo info) {
boolean isLoading = info instanceof WorkspaceItemInfo
&& ((WorkspaceItemInfo) info).hasPromiseIconUi();
- return !isLoading && !info.isDisabled() && !WidgetsModel.GO_DISABLE_WIDGETS;
+ return !isLoading && !info.isDisabled();
}
private static boolean isApp(ItemInfo info) {
diff --git a/src/com/android/launcher3/widget/PendingAddShortcutInfo.java b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
index 6e21a41..9601652 100644
--- a/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
+++ b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.widget;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY;
+
import com.android.launcher3.PendingAddItemInfo;
import com.android.launcher3.pm.ShortcutConfigActivityInfo;
@@ -32,5 +34,6 @@
componentName = activityInfo.getComponent();
user = activityInfo.getUser();
itemType = activityInfo.getItemType();
+ this.container = CONTAINER_WIDGETS_TRAY;
}
}
diff --git a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
index bc40484..bef9a08 100644
--- a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
+++ b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.widget;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY;
+
import android.appwidget.AppWidgetHostView;
import android.os.Bundle;
@@ -50,6 +52,7 @@
spanY = i.spanY;
minSpanX = i.minSpanX;
minSpanY = i.minSpanY;
+ this.container = CONTAINER_WIDGETS_TRAY;
}
public WidgetAddFlowHandler getHandler() {
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 69afcc4..223ae29 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -106,21 +106,33 @@
*/
@NonNull
public OverviewTask getCurrentTask() {
+ final List<UiObject2> taskViews = getTasks();
+ mLauncher.assertNotEquals("Unable to find a task", 0, taskViews.size());
+
+ // taskViews contains up to 3 task views: the 'main' (having the widest visible part) one
+ // in the center, and parts of its right and left siblings. Find the main task view by
+ // its width.
+ final UiObject2 widestTask = Collections.max(taskViews,
+ (t1, t2) -> Integer.compare(mLauncher.getVisibleBounds(t1).width(),
+ mLauncher.getVisibleBounds(t2).width()));
+
+ return new OverviewTask(mLauncher, widestTask, this);
+ }
+
+ @NonNull
+ private List<UiObject2> getTasks() {
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
- "want to get current task")) {
+ "want to get overview tasks")) {
verifyActiveContainer();
- final List<UiObject2> taskViews = mLauncher.getDevice().findObjects(
+ return mLauncher.getDevice().findObjects(
mLauncher.getOverviewObjectSelector("snapshot"));
- mLauncher.assertNotEquals("Unable to find a task", 0, taskViews.size());
-
- // taskViews contains up to 3 task views: the 'main' (having the widest visible
- // part) one in the center, and parts of its right and left siblings. Find the
- // main task view by its width.
- final UiObject2 widestTask = Collections.max(taskViews,
- (t1, t2) -> Integer.compare(mLauncher.getVisibleBounds(t1).width(),
- mLauncher.getVisibleBounds(t2).width()));
-
- return new OverviewTask(mLauncher, widestTask, this);
}
}
+
+ /**
+ * Returns whether Overview has tasks.
+ */
+ public boolean hasTasks() {
+ return getTasks().size() > 0;
+ }
}
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 546ff0b..9c92a26 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -440,6 +440,7 @@
try {
Log.e("b/156287114", "Input:");
for (String line : mDevice.executeShellCommand("dumpsys input").split("\\n")) {
+ SystemClock.sleep(10);
Log.d("b/156287114", line);
}
} catch (IOException e) {
@@ -833,27 +834,42 @@
@NonNull
List<UiObject2> getObjectsInContainer(UiObject2 container, String resName) {
- return container.findObjects(getLauncherObjectSelector(resName));
+ try {
+ return container.findObjects(getLauncherObjectSelector(resName));
+ } catch (StaleObjectException e) {
+ fail("The container disappeared from screen");
+ return null;
+ }
}
@NonNull
UiObject2 waitForObjectInContainer(UiObject2 container, String resName) {
- final UiObject2 object = container.wait(
- Until.findObject(getLauncherObjectSelector(resName)),
- WAIT_TIME_MS);
- assertNotNull("Can't find a view in Launcher, id: " + resName + " in container: "
- + container.getResourceName(), object);
- return object;
+ try {
+ final UiObject2 object = container.wait(
+ Until.findObject(getLauncherObjectSelector(resName)),
+ WAIT_TIME_MS);
+ assertNotNull("Can't find a view in Launcher, id: " + resName + " in container: "
+ + container.getResourceName(), object);
+ return object;
+ } catch (StaleObjectException e) {
+ fail("The container disappeared from screen");
+ return null;
+ }
}
@NonNull
UiObject2 waitForObjectInContainer(UiObject2 container, BySelector selector) {
- final UiObject2 object = container.wait(
- Until.findObject(selector),
- WAIT_TIME_MS);
- assertNotNull("Can't find a view in Launcher, id: " + selector + " in container: "
- + container.getResourceName(), object);
- return object;
+ try {
+ final UiObject2 object = container.wait(
+ Until.findObject(selector),
+ WAIT_TIME_MS);
+ assertNotNull("Can't find a view in Launcher, id: " + selector + " in container: "
+ + container.getResourceName(), object);
+ return object;
+ } catch (StaleObjectException e) {
+ fail("The container disappeared from screen");
+ return null;
+ }
}
private boolean hasLauncherObject(String resId) {
@@ -1144,7 +1160,8 @@
}
final MotionEvent event = getMotionEvent(downTime, currentTime, action, point.x, point.y);
- mInstrumentation.getUiAutomation().injectInputEvent(event, true);
+ assertTrue("injectInputEvent failed",
+ mInstrumentation.getUiAutomation().injectInputEvent(event, true));
event.recycle();
}
@@ -1322,6 +1339,7 @@
Log.e("b/156287114", "Input:");
for (String line : mDevice.executeShellCommand("dumpsys input").split(
"\\n")) {
+ SystemClock.sleep(10);
Log.d("b/156287114", line);
}
} catch (IOException e) {