Merge "Make educational half-sheet black in dark mode" into ub-launcher3-rvc-dev
diff --git a/Android.mk b/Android.mk
index 9cfcf17..fcd4a94 100644
--- a/Android.mk
+++ b/Android.mk
@@ -129,6 +129,7 @@
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := \
+ SystemUI-statsd \
SystemUISharedLib \
launcherprotosnano \
launcher_log_protos_lite
@@ -201,6 +202,7 @@
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := \
+ SystemUI-statsd \
SystemUISharedLib \
launcherprotosnano \
launcher_log_protos_lite
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java
index d93aea4..8477b10 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java
@@ -26,10 +26,10 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.FloatingHeaderView;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.views.ArrowTipView;
import com.android.systemui.shared.system.LauncherEventUtil;
@@ -71,17 +71,16 @@
public static void scheduleShowIfNeeded(Launcher launcher) {
if (!hasSeenAllAppsTip(launcher)) {
- launcher.getStateManager().addStateListener(
- new LauncherStateManager.StateListener() {
- @Override
- public void onStateTransitionComplete(LauncherState finalState) {
- if (finalState == ALL_APPS) {
- if (showAllAppsTipIfNecessary(launcher)) {
- launcher.getStateManager().removeStateListener(this);
- }
- }
+ launcher.getStateManager().addStateListener(new StateListener<LauncherState>() {
+ @Override
+ public void onStateTransitionComplete(LauncherState finalState) {
+ if (finalState == ALL_APPS) {
+ if (showAllAppsTipIfNecessary(launcher)) {
+ launcher.getStateManager().removeStateListener(this);
}
- });
+ }
+ }
+ });
}
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java
index 81a6070..914d9e9 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AppsDividerView.java
@@ -38,18 +38,18 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.R;
import com.android.launcher3.allapps.FloatingHeaderRow;
import com.android.launcher3.allapps.FloatingHeaderView;
import com.android.launcher3.anim.PropertySetter;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.Themes;
/**
* A view which shows a horizontal divider
*/
@TargetApi(Build.VERSION_CODES.O)
-public class AppsDividerView extends View implements LauncherStateManager.StateListener,
+public class AppsDividerView extends View implements StateListener<LauncherState>,
FloatingHeaderRow {
private static final String ALL_APPS_VISITED_COUNT = "launcher.all_apps_visited_count";
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java
index e68627a..ab3c71a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java
@@ -32,7 +32,6 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager.StateListener;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsStore.OnUpdateListener;
@@ -41,6 +40,7 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.MainThreadInitializedObject;
@@ -63,8 +63,8 @@
* 4) Maintains the current active client id (for the predictions) and all updates are performed on
* that client id.
*/
-public class PredictionUiStateManager implements StateListener, ItemInfoUpdateReceiver,
- OnIDPChangeListener, OnUpdateListener {
+public class PredictionUiStateManager implements StateListener<LauncherState>,
+ ItemInfoUpdateReceiver, OnIDPChangeListener, OnUpdateListener {
public static final String LAST_PREDICTION_ENABLED_STATE = "last_prediction_enabled_state";
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 1876424..6cfc846 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -30,6 +30,7 @@
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
+import android.util.Log;
import android.view.View;
import androidx.annotation.Nullable;
@@ -38,7 +39,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager.AtomicAnimationFactory;
import com.android.launcher3.Workspace;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimatorPlaybackController;
@@ -49,6 +49,8 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.SystemShortcut;
+import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory;
import com.android.launcher3.uioverrides.touchcontrollers.FlingAndHoldTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.LandscapeEdgeSwipeController;
@@ -244,6 +246,9 @@
@Override
public TouchController[] createTouchControllers() {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "createTouchControllers.1");
+ }
Mode mode = SysUINavigationMode.getMode(this);
ArrayList<TouchController> list = new ArrayList<>();
@@ -251,7 +256,13 @@
if (mode == NO_BUTTON) {
list.add(new NoButtonQuickSwitchTouchController(this));
list.add(new NavBarToHomeTouchController(this));
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "createTouchControllers.2");
+ }
if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "createTouchControllers.3");
+ }
list.add(new NoButtonNavbarToOverviewTouchController(this));
} else {
list.add(new FlingAndHoldTouchController(this));
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
index 4e868b0..a7e7d3a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
@@ -56,7 +56,7 @@
int taskHeight = out.height();
float topMargin = res.getDimension(R.dimen.task_thumbnail_top_margin);
- float bottomMargin = res.getDimension(R.dimen.task_thumbnail_bottom_margin_with_actions);
+ float bottomMargin = res.getDimension(R.dimen.overview_actions_top_margin);
float newHeight = taskHeight + topMargin + bottomMargin;
float scale = newHeight / taskHeight;
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 6bc69f9..11593a1 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
@@ -62,12 +62,12 @@
import com.android.launcher3.Hotseat;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherState.ScaleAndTranslation;
-import com.android.launcher3.LauncherStateManager;
-import com.android.launcher3.LauncherStateManager.AtomicAnimationFactory;
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;
@@ -76,7 +76,7 @@
/**
* Animation factory for quickstep specific transitions
*/
-public class QuickstepAtomicAnimationFactory extends AtomicAnimationFactory {
+public class QuickstepAtomicAnimationFactory extends AtomicAnimationFactory<LauncherState> {
// Scale recents takes before animating in
private static final float RECENTS_PREPARE_SCALE = 1.33f;
@@ -153,7 +153,7 @@
config.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2);
}
- LauncherStateManager stateManager = mLauncher.getStateManager();
+ StateManager<LauncherState> stateManager = mLauncher.getStateManager();
return stateManager.createAtomicAnimation(
stateManager.getCurrentStableState(), OVERVIEW, config);
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
index 05dd797..fac478e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
@@ -37,6 +37,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
@@ -47,6 +48,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.uioverrides.states.QuickstepAtomicAnimationFactory;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.VibratorWrapper;
@@ -178,6 +180,9 @@
@Override
public boolean onDrag(float displacement, MotionEvent event) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "FlingAndHoldTouchController");
+ }
float upDisplacement = -displacement;
mMotionPauseDetector.setDisallowPause(!handlingOverviewAnim()
|| upDisplacement < mMotionPauseMinDisplacement
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index 381ecf1..966e25b 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -27,14 +27,16 @@
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.graphics.PointF;
+import android.util.Log;
import android.view.MotionEvent;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.VibratorWrapper;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
@@ -63,6 +65,9 @@
public NoButtonNavbarToOverviewTouchController(Launcher l) {
super(l);
mRecentsView = l.getOverviewPanel();
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "NoButtonNavbarToOverviewTouchController.ctor");
+ }
}
@Override
@@ -146,6 +151,9 @@
@Override
public boolean onDrag(float yDisplacement, float xDisplacement, MotionEvent event) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "NoButtonNavbarToOverviewTouchController");
+ }
if (mMotionPauseDetector.isPaused()) {
if (!mReachedOverview) {
mStartDisplacement.set(xDisplacement, yDisplacement);
@@ -165,7 +173,7 @@
protected void goToOverviewOnDragEnd(float velocity) {
float velocityDp = dpiFromPx(velocity);
boolean isFling = Math.abs(velocityDp) > 1;
- LauncherStateManager stateManager = mLauncher.getStateManager();
+ StateManager<LauncherState> stateManager = mLauncher.getStateManager();
boolean goToHomeInsteadOfOverview = isFling;
if (goToHomeInsteadOfOverview) {
if (velocity > 0) {
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 b5ac6e5..1eb3bec 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
@@ -36,8 +36,8 @@
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.statehandlers.DepthController;
import com.android.quickstep.util.AppWindowAnimationHelper;
-import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams;
import com.android.quickstep.util.RemoteAnimationProvider;
+import com.android.quickstep.util.TransformParams;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
@@ -164,9 +164,7 @@
valueAnimator.setDuration(RECENTS_LAUNCH_DURATION);
valueAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
valueAnimator.addUpdateListener((v) -> {
- params.setProgress((float) v.getAnimatedValue())
- .setTargetSet(targets)
- .setLauncherOnTop(true);
+ params.setProgress((float) v.getAnimatedValue()).setTargetSet(targets);
clipHelper.applyTransform(params);
});
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 313ae44..dd41d25 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
@@ -15,6 +15,8 @@
*/
package com.android.quickstep;
+import static com.android.launcher3.LauncherState.BACKGROUND_APP;
+import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
@@ -23,44 +25,50 @@
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
+import android.graphics.Matrix;
+import android.graphics.Matrix.ScaleToFit;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.util.Pair;
import android.view.MotionEvent;
-import android.view.View;
import android.view.animation.Interpolator;
+import androidx.annotation.CallSuper;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.views.FloatingIconView;
-import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory;
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.AppWindowAnimationHelper.TransformParams;
-import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.RectFSpringAnim;
+import com.android.quickstep.util.TaskViewSimulator;
+import com.android.quickstep.util.TransformParams;
+import com.android.quickstep.util.TransformParams.BuilderProxy;
+import com.android.quickstep.util.WindowSizeStrategy;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder;
import java.util.ArrayList;
import java.util.function.Consumer;
@@ -93,7 +101,9 @@
protected final BaseActivityInterface<T> mActivityInterface;
protected final InputConsumerController mInputConsumer;
- protected AppWindowAnimationHelper mAppWindowAnimationHelper;
+ protected final TaskViewSimulator mTaskViewSimulator;
+ private AnimatorPlaybackController mWindowTransitionController;
+
protected final TransformParams mTransformParams = new TransformParams();
// Shift in the range of [0, 1].
@@ -113,27 +123,25 @@
protected T mActivity;
protected Q mRecentsView;
protected DeviceProfile mDp;
- private final int mPageSpacing;
protected Runnable mGestureEndCallback;
protected MultiStateCallback mStateCallback;
protected boolean mCanceled;
- protected int mFinishingRecentsAnimationForNewTaskId = -1;
- private RecentsOrientedState mOrientedState;
+ private boolean mRecentsViewScrollLinked = false;
protected BaseSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState,
- GestureState gestureState, InputConsumerController inputConsumer) {
+ GestureState gestureState, InputConsumerController inputConsumer,
+ WindowSizeStrategy windowSizeStrategy) {
mContext = context;
mDeviceState = deviceState;
mGestureState = gestureState;
mActivityInterface = gestureState.getActivityInterface();
mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit);
mInputConsumer = inputConsumer;
- mAppWindowAnimationHelper = new AppWindowAnimationHelper(context);
- mPageSpacing = context.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing);
+ mTaskViewSimulator = new TaskViewSimulator(context, windowSizeStrategy);
}
/**
@@ -193,13 +201,13 @@
updateFinalShift();
}
});
- mRecentsView.setAppWindowAnimationHelper(mAppWindowAnimationHelper);
runOnRecentsAnimationStart(() ->
mRecentsView.setRecentsAnimationTargets(mRecentsAnimationController,
mRecentsAnimationTargets));
+ mRecentsViewScrollLinked = true;
}
- protected void startNewTask(int successStateFlag, Consumer<Boolean> resultCallback) {
+ protected void startNewTask(Consumer<Boolean> resultCallback) {
// Launch the task user scrolled to (mRecentsView.getNextPage()).
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
// We finish recents animation inside launchTask() when live tile is enabled.
@@ -210,18 +218,22 @@
if (!mCanceled) {
TaskView nextTask = mRecentsView.getTaskView(taskId);
if (nextTask != null) {
+ mGestureState.updateLastStartedTaskId(taskId);
nextTask.launchTask(false /* animate */, true /* freezeTaskList */,
success -> {
resultCallback.accept(success);
- if (!success) {
+ if (success) {
+ if (mRecentsView.indexOfChild(nextTask)
+ == getLastAppearedTaskIndex()) {
+ onRestartLastAppearedTask();
+ }
+ } else {
mActivityInterface.onLaunchTaskFailed();
nextTask.notifyTaskLaunchFailed(TAG);
- } else {
- mActivityInterface.onLaunchTaskSuccess();
+ mRecentsAnimationController.finish(true /* toRecents */, null);
}
}, MAIN_EXECUTOR.getHandler());
}
- mStateCallback.setStateOnUiThread(successStateFlag);
}
mCanceled = false;
}
@@ -229,6 +241,19 @@
}
/**
+ * Called when we successfully startNewTask() on the task that was previously running. Normally
+ * we call resumeLastTask() when returning to the previously running task, but this handles a
+ * specific edge case: if we switch from A to B, and back to A before B appears, we need to
+ * start A again to ensure it stays on top.
+ */
+ @CallSuper
+ protected void onRestartLastAppearedTask() {
+ // Finish the controller here, since we won't get onTaskAppeared() for a task that already
+ // appeared.
+ mRecentsAnimationController.finish(false, null);
+ }
+
+ /**
* Runs the given {@param action} if the recents animation has already started, or queues it to
* be run when it is next started.
*/
@@ -241,42 +266,36 @@
}
/**
+ * TODO can we remove this now that we don't finish the controller until onTaskAppeared()?
* @return whether the recents animation has started and there are valid app targets.
*/
protected boolean hasTargets() {
return mRecentsAnimationTargets != null && mRecentsAnimationTargets.hasTargets();
}
- protected void updateSource(Rect stackBounds, RemoteAnimationTargetCompat runningTarget) {
- mAppWindowAnimationHelper.updateSource(stackBounds, runningTarget);
- }
-
@Override
public void onRecentsAnimationStart(RecentsAnimationController recentsAnimationController,
RecentsAnimationTargets targets) {
mRecentsAnimationController = recentsAnimationController;
mRecentsAnimationTargets = targets;
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext).getDeviceProfile(mContext);
- final Rect overviewStackBounds;
RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(
mGestureState.getRunningTaskId());
if (targets.minimizedHomeBounds != null && runningTaskTarget != null) {
- overviewStackBounds = mActivityInterface
+ Rect overviewStackBounds = mActivityInterface
.getOverviewWindowBounds(targets.minimizedHomeBounds, runningTaskTarget);
dp = dp.getMultiWindowProfile(mContext, overviewStackBounds);
} else {
// If we are not in multi-window mode, home insets should be same as system insets.
dp = dp.copy(mContext);
- overviewStackBounds = getStackBounds(dp);
}
dp.updateInsets(targets.homeContentInsets);
dp.updateIsSeascape(mContext);
if (runningTaskTarget != null) {
- updateSource(overviewStackBounds, runningTaskTarget);
+ mTaskViewSimulator.setPreview(runningTaskTarget);
}
- mAppWindowAnimationHelper.prepareAnimation(dp);
initTransitionEndpoints(dp);
// Notify when the animation starts
@@ -306,43 +325,44 @@
}
}
- private Rect getStackBounds(DeviceProfile dp) {
- if (mActivity != null) {
- int loc[] = new int[2];
- View rootView = mActivity.getRootView();
- rootView.getLocationOnScreen(loc);
- return new Rect(loc[0], loc[1], loc[0] + rootView.getWidth(),
- loc[1] + rootView.getHeight());
- } else {
- return new Rect(0, 0, dp.widthPx, dp.heightPx);
+ @Override
+ public void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
+ if (mRecentsAnimationController != null) {
+ if (handleTaskAppeared(appearedTaskTarget)) {
+ mRecentsAnimationController.finish(false /* toRecents */,
+ null /* onFinishComplete */);
+ mActivityInterface.onLaunchTaskSuccess();
+ }
}
}
+ /** @return Whether this was the task we were waiting to appear, and thus handled it. */
+ protected abstract boolean handleTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget);
+
+ /**
+ * @return The index of the TaskView in RecentsView whose taskId matches the task that will
+ * resume if we finish the controller.
+ */
+ protected int getLastAppearedTaskIndex() {
+ return mGestureState.getLastAppearedTaskId() != -1
+ ? mRecentsView.getTaskIndexForId(mGestureState.getLastAppearedTaskId())
+ : mRecentsView.getRunningTaskIndex();
+ }
+
+ /**
+ * @return Whether we are continuing a gesture that already landed on a new task,
+ * but before that task appeared.
+ */
+ protected boolean hasStartedNewTask() {
+ return mGestureState.getLastStartedTaskId() != -1;
+ }
+
protected void initTransitionEndpoints(DeviceProfile dp) {
mDp = dp;
mTransitionDragLength = mActivityInterface.getSwipeUpDestinationAndLength(
dp, mContext, TEMP_RECT);
- if (!dp.isMultiWindowMode) {
- // When updating the target rect, also update the home bounds since the location on
- // screen of the launcher window may be stale (position is not updated until first
- // traversal after the window is resized). We only do this for non-multiwindow because
- // we otherwise use the minimized home bounds provided by the system.
- mAppWindowAnimationHelper.updateHomeBounds(getStackBounds(dp));
- }
- int displayRotation = 0;
- if (mOrientedState != null && mOrientedState.isMultipleOrientationSupportedByDevice()) {
- // TODO(b/150300347): The first recents animation after launcher is started with the
- // foreground app not in landscape will look funky until that bug is fixed
- displayRotation = mOrientedState.getDisplayRotation();
-
- RectF tempRectF = new RectF(TEMP_RECT);
- mOrientedState.mapRectFromRotation(displayRotation,
- tempRectF, dp.widthPx, dp.heightPx);
- tempRectF.roundOut(TEMP_RECT);
- }
- mAppWindowAnimationHelper.updateTargetRect(TEMP_RECT);
if (mDeviceState.isFullyGesturalNavMode()) {
// We can drag all the way to the top of the screen.
mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength;
@@ -351,6 +371,24 @@
mDragLengthFactorStartPullback = dragFactorStartAndMaxProgress.first;
mDragLengthFactorMaxPullback = dragFactorStartAndMaxProgress.second;
}
+
+ mTaskViewSimulator.setDp(dp);
+ mTaskViewSimulator.setLayoutRotation(
+ mDeviceState.getCurrentActiveRotation(),
+ mDeviceState.getDisplayRotation());
+
+ AnimatorSet anim = new AnimatorSet();
+ anim.setDuration(mTransitionDragLength * 2);
+ anim.setInterpolator(t -> t * mDragLengthFactor);
+ anim.play(ObjectAnimator.ofFloat(mTaskViewSimulator.recentsViewScale,
+ AnimatedFloat.VALUE,
+ mTaskViewSimulator.getFullScreenScale(), 1));
+ anim.play(ObjectAnimator.ofFloat(mTaskViewSimulator.fullScreenProgress,
+ AnimatedFloat.VALUE,
+ BACKGROUND_APP.getOverviewFullscreenProgress(),
+ OVERVIEW.getOverviewFullscreenProgress()));
+ mWindowTransitionController =
+ AnimatorPlaybackController.wrap(anim, mTransitionDragLength * 2);
}
/**
@@ -361,9 +399,6 @@
protected boolean onActivityInit(Boolean alreadyOnHome) {
T createdActivity = mActivityInterface.getCreatedActivity();
if (createdActivity != null) {
- mOrientedState = ((RecentsView) createdActivity.getOverviewPanel())
- .getPagedViewOrientedState();
- mAppWindowAnimationHelper = new AppWindowAnimationHelper(mOrientedState, mContext);
initTransitionEndpoints(InvariantDeviceProfile.INSTANCE.get(mContext)
.getDeviceProfile(mContext));
}
@@ -412,35 +447,23 @@
}
/**
- * Applies the transform on the recents animation without any additional null checks
+ * Applies the transform on the recents animation
*/
- protected void applyTransformUnchecked() {
- float shift = mCurrentShift.value;
- float offset = mRecentsView == null ? 0 : mRecentsView.getScrollOffsetScaled();
- float taskSize = getOrientationHandler()
- .getPrimarySize(mAppWindowAnimationHelper.getTargetRect());
- float offsetScale = getTaskCurveScaleForOffset(offset, taskSize);
- mTransformParams
- .setProgress(shift)
- .setOffset(offset)
- .setOffsetScale(offsetScale)
- .setTargetSet(mRecentsAnimationTargets)
- .setLauncherOnTop(true);
- mAppWindowAnimationHelper.applyTransform(mTransformParams);
- }
+ protected void applyWindowTransform() {
+ if (mWindowTransitionController != null) {
+ float progress = mCurrentShift.value / mDragLengthFactor;
+ mWindowTransitionController.setPlayFraction(progress);
+ mTransformParams.setTargetSet(mRecentsAnimationTargets);
- private float getTaskCurveScaleForOffset(float offset, float taskSize) {
- int dpPixel = getOrientationHandler().getShortEdgeLength(mDp);
- float distanceToReachEdge = dpPixel / 2 + taskSize / 2 + mPageSpacing;
- float interpolation = Math.min(1, offset / distanceToReachEdge);
- return TaskView.getCurveScaleForInterpolation(interpolation);
+ if (mRecentsViewScrollLinked) {
+ mTaskViewSimulator.setScroll(mRecentsView.getScrollOffset());
+ }
+ mTaskViewSimulator.apply(mTransformParams);
+ }
}
protected PagedOrientationHandler getOrientationHandler() {
- if (mOrientedState == null) {
- return PagedOrientationHandler.PORTRAIT;
- }
- return mOrientedState.getOrientationHandler();
+ return mTaskViewSimulator.getOrientationState().getOrientationHandler();
}
/**
@@ -451,104 +474,40 @@
protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
HomeAnimationFactory homeAnimationFactory) {
final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
- final View floatingView = homeAnimationFactory.getFloatingView();
- final boolean isFloatingIconView = floatingView instanceof FloatingIconView;
- final RectF startRect = new RectF(
- mAppWindowAnimationHelper.applyTransform(
- mTransformParams.setProgress(startProgress)
- .setTargetSet(mRecentsAnimationTargets)
- .setLauncherOnTop(false)));
- if (isFloatingIconView) {
- mOrientedState.mapInverseRectFromNormalOrientation(
- startRect, mDp.widthPx, mDp.heightPx);
- }
+ final FloatingIconView fiv = homeAnimationFactory.mIconView;
+ final boolean isFloatingIconView = fiv != null;
+
+ mWindowTransitionController.setPlayFraction(startProgress / mDragLengthFactor);
+ mTaskViewSimulator.apply(mTransformParams
+ .setProgress(startProgress)
+ .setTargetSet(mRecentsAnimationTargets));
+ RectF cropRectF = new RectF(mTaskViewSimulator.getCurrentCropRect());
+
+ // Matrix to map a rect in Launcher space to window space
+ Matrix homeToWindowPositionMap = new Matrix();
+ mTaskViewSimulator.applyWindowToHomeRotation(homeToWindowPositionMap);
+
+ final RectF startRect = new RectF(cropRectF);
+ mTaskViewSimulator.getCurrentMatrix().mapRect(startRect);
+ // Move the startRect to Launcher space as floatingIconView runs in Launcher
+ Matrix windowToHomePositionMap = new Matrix();
+ homeToWindowPositionMap.invert(windowToHomePositionMap);
+ windowToHomePositionMap.mapRect(startRect);
+
RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext);
if (isFloatingIconView) {
- FloatingIconView fiv = (FloatingIconView) floatingView;
anim.addAnimatorListener(fiv);
fiv.setOnTargetChangeListener(anim::onTargetPositionChanged);
fiv.setFastFinishRunnable(anim::end);
}
- AnimatorPlaybackController homeAnim = homeAnimationFactory.createActivityAnimationToHome();
-
- // End on a "round-enough" radius so that the shape reveal doesn't have to do too much
- // rounding at the end of the animation.
- float startRadius = mAppWindowAnimationHelper.getCurrentCornerRadius();
- float endRadius = startRect.width() / 6f;
-
- float startTransformProgress = mTransformParams.getProgress();
- float endTransformProgress = 1;
-
- // We want the window alpha to be 0 once this threshold is met, so that the
- // FolderIconView can be seen morphing into the icon shape.
- final float windowAlphaThreshold = isFloatingIconView ? 1f - SHAPE_PROGRESS_DURATION : 1f;
- final RectF rotatedRect = new RectF();
- anim.addOnUpdateListener(new RectFSpringAnim.OnUpdateListener() {
-
- @Override
- public void onUpdate(RectF currentRect, float progress) {
- homeAnim.setPlayFraction(progress);
-
- rotatedRect.set(currentRect);
- if (isFloatingIconView) {
- mOrientedState.mapRectFromNormalOrientation(
- rotatedRect, mDp.widthPx, mDp.heightPx);
- mTransformParams.setCornerRadius(endRadius * progress + startRadius
- * (1f - progress));
- }
- mTransformParams.setProgress(
- Utilities.mapRange(progress, startTransformProgress, endTransformProgress))
- .setCurrentRect(rotatedRect)
- .setTargetAlpha(getWindowAlpha(progress));
- mAppWindowAnimationHelper.applyTransform(mTransformParams);
-
- if (isFloatingIconView) {
- ((FloatingIconView) floatingView).update(currentRect, 1f, progress,
- windowAlphaThreshold, mAppWindowAnimationHelper.getCurrentCornerRadius(),
- false);
- }
- }
-
- @Override
- public void onCancel() {
- if (isFloatingIconView) {
- ((FloatingIconView) floatingView).fastFinish();
- }
- }
- });
- anim.addAnimatorListener(new AnimationSuccessListener() {
- @Override
- public void onAnimationStart(Animator animation) {
- homeAnim.dispatchOnStart();
- }
-
- @Override
- public void onAnimationSuccess(Animator animator) {
- homeAnim.getAnimationPlayer().end();
- }
- });
+ SpringAnimationRunner runner = new SpringAnimationRunner(
+ homeAnimationFactory, cropRectF, homeToWindowPositionMap);
+ anim.addOnUpdateListener(runner);
+ anim.addAnimatorListener(runner);
return anim;
}
- /**
- * @param progress The progress of the animation to the home screen.
- * @return The current alpha to set on the animating app window.
- */
- protected float getWindowAlpha(float progress) {
- // Alpha interpolates between [1, 0] between progress values [start, end]
- final float start = 0f;
- final float end = 0.85f;
-
- if (progress <= start) {
- return 1f;
- }
- if (progress >= end) {
- return 0f;
- }
- return Utilities.mapToRange(progress, start, end, 1, 0, ACCEL_1_5);
- }
-
public interface Factory {
BaseSwipeUpHandler newHandler(GestureState gestureState, long touchTimeMs,
@@ -588,4 +547,135 @@
};
}
}
+
+ /**
+ * @param progress The progress of the animation to the home screen.
+ * @return The current alpha to set on the animating app window.
+ */
+ protected float getWindowAlpha(float progress) {
+ // Alpha interpolates between [1, 0] between progress values [start, end]
+ final float start = 0f;
+ final float end = 0.85f;
+
+ if (progress <= start) {
+ return 1f;
+ }
+ if (progress >= end) {
+ return 0f;
+ }
+ return Utilities.mapToRange(progress, start, end, 1, 0, ACCEL_1_5);
+ }
+
+ protected abstract class HomeAnimationFactory {
+
+ private FloatingIconView mIconView;
+
+ public HomeAnimationFactory(@Nullable FloatingIconView iconView) {
+ mIconView = iconView;
+ }
+
+ public @NonNull RectF getWindowTargetRect() {
+ PagedOrientationHandler orientationHandler = getOrientationHandler();
+ DeviceProfile dp = mDp;
+ final int halfIconSize = dp.iconSizePx / 2;
+ float primaryDimension = orientationHandler
+ .getPrimaryValue(dp.availableWidthPx, dp.availableHeightPx);
+ float secondaryDimension = orientationHandler
+ .getSecondaryValue(dp.availableWidthPx, dp.availableHeightPx);
+ final float targetX = primaryDimension / 2f;
+ final float targetY = secondaryDimension - dp.hotseatBarSizePx;
+ // Fallback to animate to center of screen.
+ return new RectF(targetX - halfIconSize, targetY - halfIconSize,
+ targetX + halfIconSize, targetY + halfIconSize);
+ }
+
+ public abstract @NonNull AnimatorPlaybackController createActivityAnimationToHome();
+
+ public void playAtomicAnimation(float velocity) {
+ // No-op
+ }
+ }
+
+ private class SpringAnimationRunner extends AnimationSuccessListener
+ implements RectFSpringAnim.OnUpdateListener, BuilderProxy {
+
+ final Rect mCropRect = new Rect();
+ final Matrix mMatrix = new Matrix();
+
+ final RectF mWindowCurrentRect = new RectF();
+ final Matrix mHomeToWindowPositionMap;
+
+ final FloatingIconView mFIV;
+ final AnimatorPlaybackController mHomeAnim;
+ final RectF mCropRectF;
+
+ final float mStartRadius;
+ final float mEndRadius;
+ final float mWindowAlphaThreshold;
+
+ SpringAnimationRunner(HomeAnimationFactory factory, RectF cropRectF,
+ Matrix homeToWindowPositionMap) {
+ mHomeAnim = factory.createActivityAnimationToHome();
+ mCropRectF = cropRectF;
+ mHomeToWindowPositionMap = homeToWindowPositionMap;
+
+ cropRectF.roundOut(mCropRect);
+ mFIV = factory.mIconView;
+
+ // End on a "round-enough" radius so that the shape reveal doesn't have to do too much
+ // rounding at the end of the animation.
+ mStartRadius = mTaskViewSimulator.getCurrentCornerRadius();
+ mEndRadius = cropRectF.width() / 2f;
+
+ // We want the window alpha to be 0 once this threshold is met, so that the
+ // FolderIconView can be seen morphing into the icon shape.
+ mWindowAlphaThreshold = mFIV != null ? 1f - SHAPE_PROGRESS_DURATION : 1f;
+ }
+
+ @Override
+ public void onUpdate(RectF currentRect, float progress) {
+ mHomeAnim.setPlayFraction(progress);
+ mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, currentRect);
+
+ mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL);
+ float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius);
+ mTransformParams
+ .setTargetAlpha(getWindowAlpha(progress))
+ .setCornerRadius(cornerRadius);
+
+ mTransformParams.applySurfaceParams(mTransformParams.createSurfaceParams(this));
+ if (mFIV != null) {
+ mFIV.update(currentRect, 1f, progress,
+ mWindowAlphaThreshold, mMatrix.mapRadius(cornerRadius), false);
+ }
+ }
+
+ @Override
+ public void onBuildParams(Builder builder, RemoteAnimationTargetCompat app, int targetMode,
+ TransformParams params) {
+ if (app.mode == targetMode
+ && app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
+ builder.withMatrix(mMatrix)
+ .withWindowCrop(mCropRect)
+ .withCornerRadius(params.getCornerRadius());
+ }
+ }
+
+ @Override
+ public void onCancel() {
+ if (mFIV != null) {
+ mFIV.fastFinish();
+ }
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mHomeAnim.dispatchOnStart();
+ }
+
+ @Override
+ public void onAnimationSuccess(Animator animator) {
+ mHomeAnim.getAnimationPlayer().end();
+ }
+ }
}
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 88dbbe1..4ce972e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
@@ -21,18 +21,14 @@
import static com.android.quickstep.util.WindowSizeStrategy.FALLBACK_RECENTS_SIZE_STRATEGY;
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
-import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Rect;
-import android.graphics.RectF;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.fallback.FallbackRecentsView;
@@ -89,39 +85,6 @@
// set to zero prior to this class becoming active.
}
- @NonNull
- @Override
- public HomeAnimationFactory prepareHomeUI() {
- RecentsActivity activity = getCreatedActivity();
- RecentsView recentsView = activity.getOverviewPanel();
-
- return new HomeAnimationFactory() {
- @NonNull
- @Override
- public RectF getWindowTargetRect() {
- float centerX = recentsView.getPivotX();
- float centerY = recentsView.getPivotY();
- return new RectF(centerX, centerY, centerX, centerY);
- }
-
- @NonNull
- @Override
- public AnimatorPlaybackController createActivityAnimationToHome() {
- Animator anim = ObjectAnimator.ofFloat(recentsView, CONTENT_ALPHA, 0);
- anim.addListener(new AnimationSuccessListener() {
- @Override
- public void onAnimationSuccess(Animator animator) {
- recentsView.startHome();
- }
- });
- AnimatorSet animatorSet = new AnimatorSet();
- animatorSet.play(anim);
- long accuracy = 2 * Math.max(recentsView.getWidth(), recentsView.getHeight());
- return AnimatorPlaybackController.wrap(animatorSet, accuracy);
- }
- };
- }
-
@Override
public AnimationFactory prepareRecentsUI(boolean activityVisible,
boolean animateActivity, Consumer<AnimatorPlaybackController> callback) {
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 45b39c8..8ce6bbc 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -24,6 +24,7 @@
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.util.WindowSizeStrategy.FALLBACK_RECENTS_SIZE_STRATEGY;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import android.animation.Animator;
@@ -32,7 +33,6 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.PointF;
-import android.graphics.RectF;
import android.os.Bundle;
import android.util.ArrayMap;
import android.view.MotionEvent;
@@ -40,17 +40,15 @@
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.ObjectWrapper;
-import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory;
import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.util.RectFSpringAnim;
-import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
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;
/**
* Handles the navigation gestures when a 3rd party launcher is the default home activity.
@@ -108,7 +106,7 @@
public FallbackSwipeHandler(Context context, RecentsAnimationDeviceState deviceState,
GestureState gestureState, InputConsumerController inputConsumer,
boolean isLikelyToStartNewTask, boolean continuingLastGesture) {
- super(context, deviceState, gestureState, inputConsumer);
+ super(context, deviceState, gestureState, inputConsumer, FALLBACK_RECENTS_SIZE_STRATEGY);
mInQuickSwitchMode = isLikelyToStartNewTask || continuingLastGesture;
mContinuingLastGesture = continuingLastGesture;
@@ -118,9 +116,9 @@
// Keep the home launcher invisible until we decide to land there.
mLauncherAlpha.value = mRunningOverHome ? 1 : 0;
if (mSwipeUpOverHome) {
- mAppWindowAnimationHelper.setBaseAlphaCallback((t, a) -> 1 - mLauncherAlpha.value);
+ mTransformParams.setBaseAlphaCallback((t, a) -> 1 - mLauncherAlpha.value);
} else {
- mAppWindowAnimationHelper.setBaseAlphaCallback((t, a) -> mLauncherAlpha.value);
+ mTransformParams.setBaseAlphaCallback((t, a) -> mLauncherAlpha.value);
}
// Going home has an extra long progress to ensure that it animates into the screen
@@ -156,7 +154,7 @@
private void onLauncherAlphaChanged() {
if (mRecentsAnimationTargets != null && mGestureState.getEndTarget() == null) {
- applyTransformUnchecked();
+ applyWindowTransform();
}
}
@@ -261,9 +259,7 @@
updateOverviewThresholdPassed(mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW);
}
- if (mRecentsAnimationTargets != null) {
- applyTransformUnchecked();
- }
+ applyWindowTransform();
}
@Override
@@ -320,15 +316,6 @@
}
if (mRecentsView != null) {
- if (mFinishingRecentsAnimationForNewTaskId != -1) {
- TaskView newRunningTaskView = mRecentsView.getTaskView(
- mFinishingRecentsAnimationForNewTaskId);
- int newRunningTaskId = newRunningTaskView != null
- ? newRunningTaskView.getTask().key.id
- : -1;
- mRecentsView.setCurrentTask(newRunningTaskId);
- mGestureState.setFinishingRecentsAnimationTaskId(newRunningTaskId);
- }
mRecentsView.setOnScrollChangeListener(null);
}
} else {
@@ -401,7 +388,7 @@
break;
}
case NEW_TASK: {
- startNewTask(STATE_HANDLER_INVALIDATED, b -> {});
+ startNewTask(success -> { });
break;
}
}
@@ -416,7 +403,7 @@
if (mRecentsView == null || !hasTargets()) {
mGestureState.setEndTarget(LAST_TASK);
} else {
- final int runningTaskIndex = mRecentsView.getRunningTaskIndex();
+ final int runningTaskIndex = getLastAppearedTaskIndex();
final int taskToLaunch = mRecentsView.getNextPage();
mGestureState.setEndTarget(
(runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex)
@@ -477,11 +464,7 @@
RecentsAnimationTargets targets) {
super.onRecentsAnimationStart(controller, targets);
mRecentsAnimationController.enableInputConsumer();
-
- if (mRunningOverHome) {
- mAppWindowAnimationHelper.prepareAnimation(mDp);
- }
- applyTransformUnchecked();
+ applyWindowTransform();
mStateCallback.setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
}
@@ -494,23 +477,17 @@
super.onRecentsAnimationCanceled(thumbnailData);
}
+ @Override
+ protected boolean handleTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
+ return true;
+ }
+
/**
* 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() {
- @Override
- public RectF getWindowTargetRect() {
- PagedOrientationHandler orientationHandler = mRecentsView != null
- ? mRecentsView.getPagedOrientationHandler()
- : (mDp.isLandscape
- ? PagedOrientationHandler.LANDSCAPE
- : PagedOrientationHandler.PORTRAIT);
- return HomeAnimationFactory
- .getDefaultWindowTargetRect(orientationHandler, mDp);
- }
-
+ HomeAnimationFactory factory = new HomeAnimationFactory(null) {
@Override
public AnimatorPlaybackController createActivityAnimationToHome() {
AnimatorSet anim = new AnimatorSet();
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 5e688fb..dc35bf6 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
@@ -17,7 +17,6 @@
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
-import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.anim.Interpolators.INSTANT;
@@ -34,14 +33,11 @@
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Rect;
-import android.graphics.RectF;
-import android.os.UserHandle;
+import android.util.Log;
import android.util.Pair;
import android.view.MotionEvent;
-import android.view.View;
import android.view.animation.Interpolator;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@@ -55,17 +51,15 @@
import com.android.launcher3.appprediction.PredictionUiStateManager;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statehandlers.DepthController.ClampedDepthProperty;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.userevent.nano.LauncherLogProto;
-import com.android.launcher3.views.FloatingIconView;
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.util.StaggeredWorkspaceAnim;
import com.android.quickstep.views.LauncherRecentsView;
import com.android.quickstep.views.RecentsView;
-import com.android.quickstep.views.TaskView;
import com.android.systemui.plugins.shared.LauncherOverlayManager;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -148,63 +142,6 @@
launcher.onAssistantVisibilityChanged(visibility);
}
- @NonNull
- @Override
- public HomeAnimationFactory prepareHomeUI() {
- Launcher launcher = getCreatedActivity();
- final DeviceProfile dp = launcher.getDeviceProfile();
- final RecentsView recentsView = launcher.getOverviewPanel();
- final TaskView runningTaskView = recentsView.getRunningTaskView();
- final View workspaceView;
- if (runningTaskView != null && runningTaskView.getTask().key.getComponent() != null) {
- workspaceView = launcher.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(launcher, workspaceView,
- true /* hideOriginal */, iconLocation, false /* isOpening */)
- : null;
- setLauncherHideBackArrow(true);
- return new HomeAnimationFactory() {
- @Nullable
- @Override
- public View getFloatingView() {
- return floatingIconView;
- }
-
- @NonNull
- @Override
- public RectF getWindowTargetRect() {
- if (canUseWorkspaceView) {
- return iconLocation;
- } else {
- return HomeAnimationFactory
- .getDefaultWindowTargetRect(recentsView.getPagedOrientationHandler(), dp);
- }
- }
-
- @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(dp.widthPx, dp.heightPx);
- return launcher.getStateManager().createAnimationToNewWorkspace(NORMAL, accuracy,
- 0 /* animComponents */);
- }
-
- @Override
- public void playAtomicAnimation(float velocity) {
- new StaggeredWorkspaceAnim(launcher, velocity, true /* animateOverviewScrim */)
- .start();
- }
- };
- }
-
@Override
public AnimationFactory prepareRecentsUI(boolean activityVisible,
boolean animateActivity, Consumer<AnimatorPlaybackController> callback) {
@@ -383,6 +320,9 @@
@Override
public boolean switchToRecentsIfVisible(Runnable onCompleteCallback) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS, "switchToRecentsIfVisible");
+ }
Launcher launcher = getVisibleLauncher();
if (launcher == null) {
return false;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
index 8e22fbd..e1f34ed 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
@@ -17,8 +17,7 @@
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.BACKGROUND_APP;
-import static com.android.launcher3.LauncherState.OVERVIEW;
+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;
@@ -32,7 +31,6 @@
import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINISHED;
import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
-import static com.android.quickstep.GestureState.STATE_TASK_APPEARED_DURING_SWITCH;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.HIDE;
@@ -42,17 +40,16 @@
import android.animation.Animator;
import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
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.Rect;
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;
@@ -65,6 +62,7 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
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;
@@ -75,16 +73,16 @@
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.BaseActivityInterface.HomeAnimationFactory;
import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.inputconsumers.OverviewInputConsumer;
import com.android.quickstep.util.ActiveGestureLog;
-import com.android.quickstep.util.AppWindowAnimationHelper.TargetAlphaProvider;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.ShelfPeekAnim;
import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
-import com.android.quickstep.util.TaskViewSimulator;
+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;
import com.android.quickstep.views.TaskView;
@@ -97,8 +95,8 @@
* Handles the navigation gestures when Launcher is the default home activity.
*/
@TargetApi(Build.VERSION_CODES.O)
-public class LauncherSwipeHandler<T extends BaseDraggingActivity>
- extends BaseSwipeUpHandler<T, RecentsView> implements OnApplyWindowInsetsListener {
+public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsView>
+ implements OnApplyWindowInsetsListener {
private static final String TAG = LauncherSwipeHandler.class.getSimpleName();
private static final String[] STATE_NAMES = DEBUG_STATES ? new String[16] : null;
@@ -152,7 +150,6 @@
STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED;
public static final long MAX_SWIPE_DURATION = 350;
- public static final long MIN_SWIPE_DURATION = 80;
public static final long MIN_OVERSHOOT_DURATION = 120;
public static final float MIN_PROGRESS_FOR_OVERVIEW = 0.7f;
@@ -181,9 +178,6 @@
private AnimatorPlaybackController mLauncherTransitionController;
private boolean mHasLauncherTransitionControllerStarted;
- private final TaskViewSimulator mTaskViewSimulator;
- private AnimatorPlaybackController mWindowTransitionController;
-
private AnimationFactory mAnimationFactory = (t) -> { };
private boolean mWasLauncherAlreadyVisible;
@@ -204,11 +198,10 @@
TaskAnimationManager taskAnimationManager, GestureState gestureState,
long touchTimeMs, boolean continuingLastGesture,
InputConsumerController inputConsumer) {
- super(context, deviceState, gestureState, inputConsumer);
+ super(context, deviceState, gestureState, inputConsumer, LAUNCHER_ACTIVITY_SIZE_STRATEGY);
mTaskAnimationManager = taskAnimationManager;
mTouchTimeMs = touchTimeMs;
mContinuingLastGesture = continuingLastGesture;
- mTaskViewSimulator = new TaskViewSimulator(context, LAUNCHER_ACTIVITY_SIZE_STRATEGY);
initAfterSubclassConstructor();
initStateCallbacks();
@@ -264,8 +257,6 @@
| STATE_RECENTS_SCROLLING_FINISHED,
this::onSettledOnEndTarget);
- mGestureState.runOnceAtState(STATE_TASK_APPEARED_DURING_SWITCH, this::onTaskAppeared);
-
mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED, this::invalidateHandler);
mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
this::invalidateHandlerWithLauncher);
@@ -282,7 +273,7 @@
@Override
protected boolean onActivityInit(Boolean alreadyOnHome) {
super.onActivityInit(alreadyOnHome);
- final T activity = mActivityInterface.getCreatedActivity();
+ final Launcher activity = mActivityInterface.getCreatedActivity();
if (mActivity == activity) {
return true;
}
@@ -304,7 +295,6 @@
mRecentsView = activity.getOverviewPanel();
mRecentsView.setOnPageTransitionEndCallback(null);
- linkRecentsViewScroll();
addLiveTileOverlay();
mStateCallback.setState(STATE_LAUNCHER_PRESENT);
@@ -321,6 +311,8 @@
// so we need to kick off switching to the overview predictions as soon as possible
mActivityInterface.updateOverviewPredictionState();
}
+ linkRecentsViewScroll();
+
return true;
}
@@ -330,7 +322,7 @@
}
private void onLauncherStart() {
- final T activity = mActivityInterface.getCreatedActivity();
+ final Launcher activity = mActivityInterface.getCreatedActivity();
if (mActivity != activity) {
return;
}
@@ -521,34 +513,6 @@
mAnimationFactory.createActivityInterface(mTransitionDragLength);
}
- @Override
- protected void updateSource(Rect stackBounds, RemoteAnimationTargetCompat runningTarget) {
- super.updateSource(stackBounds, runningTarget);
- mTaskViewSimulator.setPreview(runningTarget, mRecentsAnimationTargets);
- }
-
- @Override
- protected void initTransitionEndpoints(DeviceProfile dp) {
- super.initTransitionEndpoints(dp);
- mTaskViewSimulator.setDp(dp);
- mTaskViewSimulator.setLayoutRotation(
- mDeviceState.getCurrentActiveRotation(),
- mDeviceState.getDisplayRotation());
-
- AnimatorSet anim = new AnimatorSet();
- anim.setDuration(mTransitionDragLength * 2);
- anim.setInterpolator(t -> t * mDragLengthFactor);
- anim.play(ObjectAnimator.ofFloat(mTaskViewSimulator.recentsViewScale,
- AnimatedFloat.VALUE,
- mTaskViewSimulator.getFullScreenScale(), 1));
- anim.play(ObjectAnimator.ofFloat(mTaskViewSimulator.fullScreenProgress,
- AnimatedFloat.VALUE,
- BACKGROUND_APP.getOverviewFullscreenProgress(),
- OVERVIEW.getOverviewFullscreenProgress()));
- mWindowTransitionController =
- AnimatorPlaybackController.wrap(anim, mTransitionDragLength * 2);
- }
-
/**
* 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.
@@ -579,18 +543,11 @@
@Override
public void updateFinalShift() {
- if (mRecentsAnimationTargets != null) {
- // Base class expects applyTransformUnchecked to be called here.
- // TODO: Remove this dependency for swipe-up animation.
- // applyTransformUnchecked();
- updateSysUiFlags(mCurrentShift.value);
- }
-
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
if (mRecentsAnimationTargets != null) {
LiveTileOverlay.INSTANCE.update(
- mAppWindowAnimationHelper.getCurrentRectWithInsets(),
- mAppWindowAnimationHelper.getCurrentCornerRadius());
+ mTaskViewSimulator.getCurrentCropRect(),
+ mTaskViewSimulator.getCurrentCornerRadius());
}
}
@@ -602,16 +559,8 @@
}
}
- if (mWindowTransitionController != null) {
- float progress = mCurrentShift.value / mDragLengthFactor;
- mWindowTransitionController.setPlayFraction(progress);
- mTransformParams
- .setTargetSet(mRecentsAnimationTargets)
- .setLauncherOnTop(true);
-
- mTaskViewSimulator.setScroll(mRecentsView == null ? 0 : mRecentsView.getScrollOffset());
- mTaskViewSimulator.apply(mTransformParams);
- }
+ updateSysUiFlags(mCurrentShift.value);
+ applyWindowTransform();
updateLauncherTransitionProgress();
}
@@ -685,7 +634,7 @@
*/
@UiThread
private void notifyGestureStartedAsync() {
- final T curActivity = mActivity;
+ final Launcher 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
@@ -771,20 +720,17 @@
}
}
- private void onTaskAppeared() {
- RemoteAnimationTargetCompat app = mGestureState.getAnimationTarget();
- if (mRecentsAnimationController != null && app != null) {
-
- // TODO(b/152480470): Update Task target animation after onTaskAppeared holistically.
- /* android.util.Log.d("LauncherSwipeHandler", "onTaskAppeared");
-
- final boolean result = mRecentsAnimationController.removeTaskTarget(app);
- mGestureState.setAnimationTarget(null);
- android.util.Log.d("LauncherSwipeHandler", "removeTask, result=" + result); */
-
- mRecentsAnimationController.finish(false /* toRecents */,
- null /* onFinishComplete */);
+ @Override
+ protected boolean handleTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
+ if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) {
+ return false;
}
+ if (mGestureState.getEndTarget() == NEW_TASK
+ && appearedTaskTarget.taskId == mGestureState.getLastStartedTaskId()) {
+ reset();
+ return true;
+ }
+ return false;
}
private GestureEndTarget calculateEndTarget(PointF velocity, float endVelocity, boolean isFling,
@@ -971,26 +917,63 @@
Interpolator interpolator, GestureEndTarget target, PointF velocityPxPerMs) {
// Set the state, but don't notify until the animation completes
mGestureState.setEndTarget(target, false /* isAtomic */);
-
maybeUpdateRecentsAttachedState();
if (mGestureState.getEndTarget() == HOME) {
HomeAnimationFactory homeAnimFactory;
if (mActivity != null) {
- homeAnimFactory = mActivityInterface.prepareHomeUI();
- } else {
- homeAnimFactory = new HomeAnimationFactory() {
- @NonNull
+ 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);
+
+ homeAnimFactory = new HomeAnimationFactory(floatingIconView) {
+
@Override
public RectF getWindowTargetRect() {
- RectF fallbackTarget = new RectF(mAppWindowAnimationHelper.getTargetRect());
- Utilities.scaleRectFAboutCenter(fallbackTarget, 0.25f);
- return fallbackTarget;
+ 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);
}
};
@@ -1031,12 +1014,24 @@
// skip doing any future work here for the current gesture.
return;
}
- if (target == NEW_TASK && mRecentsView != null
- && mRecentsView.getNextPage() == mRecentsView.getRunningTaskIndex()) {
- // We are about to launch the current running task, so use LAST_TASK state
- // instead of NEW_TASK. This could happen, for example, if our scroll is
- // aborted after we determined the target to be NEW_TASK.
- mGestureState.setEndTarget(LAST_TASK);
+ if (mRecentsView != null) {
+ int taskToLaunch = mRecentsView.getNextPage();
+ int runningTask = getLastAppearedTaskIndex();
+ boolean hasStartedNewTask = hasStartedNewTask();
+ if (target == NEW_TASK && taskToLaunch == runningTask
+ && !hasStartedNewTask) {
+ // We are about to launch the current running task, so use LAST_TASK
+ // state instead of NEW_TASK. This could happen, for example, if our
+ // scroll is aborted after we determined the target to be NEW_TASK.
+ mGestureState.setEndTarget(LAST_TASK);
+ } else if (target == LAST_TASK && hasStartedNewTask) {
+ // We are about to re-launch the previously running task, but we can't
+ // just finish the controller like we normally would because that would
+ // instead resume the last task that appeared, and not ensure that this
+ // task is restored to the top. To address this, re-launch the task as
+ // if it were a new task.
+ mGestureState.setEndTarget(NEW_TASK);
+ }
}
mGestureState.setState(STATE_END_TARGET_ANIMATION_FINISHED);
}
@@ -1160,8 +1155,9 @@
@UiThread
private void startNewTaskInternal() {
- startNewTask(STATE_HANDLER_INVALIDATED, success -> {
+ startNewTask(success -> {
if (!success) {
+ reset();
// We couldn't launch the task, so take user to overview so they can
// decide what to do instead of staying in this broken state.
endLauncherTransitionController();
@@ -1171,6 +1167,12 @@
});
}
+ @Override
+ protected void onRestartLastAppearedTask() {
+ super.onRestartLastAppearedTask();
+ reset();
+ }
+
private void reset() {
mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
}
@@ -1186,19 +1188,6 @@
.getAnimationPlayer().isStarted()) {
mLauncherTransitionController.getAnimationPlayer().cancel();
}
-
- if (mFinishingRecentsAnimationForNewTaskId != -1) {
- // If we are canceling mid-starting a new task, switch to the screenshot since the
- // recents animation has finished
- switchToScreenshot();
- TaskView newRunningTaskView = mRecentsView.getTaskView(
- mFinishingRecentsAnimationForNewTaskId);
- int newRunningTaskId = newRunningTaskView != null
- ? newRunningTaskView.getTask().key.id
- : -1;
- mRecentsView.setCurrentTask(newRunningTaskId);
- mGestureState.setFinishingRecentsAnimationTaskId(newRunningTaskId);
- }
}
private void invalidateHandler() {
@@ -1337,8 +1326,7 @@
}
private void setTargetAlphaProvider(TargetAlphaProvider provider) {
- mAppWindowAnimationHelper.setTaskAlphaCallback(provider);
- mTaskViewSimulator.setTaskAlphaCallback(provider);
+ mTransformParams.setTaskAlphaCallback(provider);
updateFinalShift();
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java
index b44d6df..042c542 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java
@@ -22,6 +22,7 @@
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Rect;
+import android.widget.Toast;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity;
@@ -109,16 +110,26 @@
public void initOverlay(Task task, ThumbnailData thumbnail, Matrix matrix) {
ImageActionsApi imageApi = new ImageActionsApi(
mApplicationContext, mThumbnailView::getThumbnail);
+ final boolean isAllowedByPolicy = thumbnail.isRealSnapshot;
+
getActionsView().setCallbacks(new OverlayUICallbacks() {
@Override
public void onShare() {
- imageApi.startShareActivity();
+ if (isAllowedByPolicy) {
+ imageApi.startShareActivity();
+ } else {
+ showBlockedByPolicyMessage();
+ }
}
@Override
public void onScreenshot() {
- imageApi.saveScreenshot(mThumbnailView.getThumbnail(),
- getTaskSnapshotBounds(), getTaskSnapshotInsets(), task.key.id);
+ if (isAllowedByPolicy) {
+ imageApi.saveScreenshot(mThumbnailView.getThumbnail(),
+ getTaskSnapshotBounds(), getTaskSnapshotInsets(), task.key.id);
+ } else {
+ showBlockedByPolicyMessage();
+ }
}
});
}
@@ -152,6 +163,13 @@
// TODO: return the real insets
return Insets.of(0, 0, 0, 0);
}
+
+ private void showBlockedByPolicyMessage() {
+ Toast.makeText(
+ mThumbnailView.getContext(),
+ R.string.blocked_by_policy,
+ Toast.LENGTH_LONG).show();
+ }
}
/**
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
index 5db8f31..9a7a491 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
@@ -38,6 +38,7 @@
import com.android.launcher3.statehandlers.DepthController;
import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.util.MultiValueUpdateListener;
+import com.android.quickstep.util.TransformParams;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
@@ -132,11 +133,10 @@
final RemoteAnimationTargets targets =
new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_OPENING);
targets.addDependentTransactionApplier(applier);
- AppWindowAnimationHelper.TransformParams params =
- new AppWindowAnimationHelper.TransformParams()
+ TransformParams params =
+ new TransformParams()
.setSyncTransactionApplier(applier)
- .setTargetSet(targets)
- .setLauncherOnTop(true);
+ .setTargetSet(targets);
AnimatorSet animatorSet = new AnimatorSet();
final RecentsView recentsView = v.getRecentsView();
@@ -150,7 +150,7 @@
final RectF mThumbnailRect;
{
- inOutHelper.setTaskAlphaCallback((t, alpha) -> mTaskAlpha.value);
+ params.setTaskAlphaCallback((t, alpha) -> mTaskAlpha.value);
inOutHelper.prepareAnimation(
BaseActivity.fromContext(v.getContext()).getDeviceProfile());
inOutHelper.fromTaskThumbnailView(v.getThumbnail(), (RecentsView) v.getParent(),
@@ -175,7 +175,7 @@
v.getRecentsView().getClipAnimationHelper();
if (liveTileAnimationHelper != null) {
// Append the surface transform params for the live tile app.
- AppWindowAnimationHelper.TransformParams liveTileParams =
+ TransformParams liveTileParams =
v.getRecentsView().getLiveTileParams(true /* mightNeedToRefill */);
if (liveTileParams != null) {
SurfaceParams[] liveTileSurfaceParams =
@@ -186,7 +186,7 @@
}
}
// Apply surface transform using the surface params list.
- AppWindowAnimationHelper.applySurfaceParams(params.getSyncTransactionApplier(),
+ params.applySurfaceParams(
surfaceParamsList.toArray(new SurfaceParams[surfaceParamsList.size()]));
// Get the task bounds for the app that's being opened after surface transform
// update.
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 ce7a141..4b2fc75 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -30,8 +30,6 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
import android.annotation.TargetApi;
-import android.app.ActivityManager;
-import android.app.ActivityManager.RunningTaskInfo;
import android.app.PendingIntent;
import android.app.RemoteAction;
import android.app.Service;
@@ -518,8 +516,13 @@
private GestureState createGestureState() {
GestureState gestureState = new GestureState(mOverviewComponentObserver,
ActiveGestureLog.INSTANCE.generateAndSetLogId());
- gestureState.updateRunningTask(TraceHelper.whitelistIpcs("getRunningTask.0",
- () -> mAM.getRunningTask(false /* filterOnlyVisibleRecents */)));
+ if (mTaskAnimationManager.isRecentsAnimationRunning()) {
+ gestureState.updateRunningTask(mGestureState.getRunningTask());
+ gestureState.updateLastStartedTaskId(mGestureState.getLastStartedTaskId());
+ } else {
+ gestureState.updateRunningTask(TraceHelper.whitelistIpcs("getRunningTask.0",
+ () -> mAM.getRunningTask(false /* filterOnlyVisibleRecents */)));
+ }
return gestureState;
}
@@ -599,15 +602,24 @@
}
private void handleOrientationSetup(InputConsumer baseInputConsumer) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "handleOrientationSetup.1");
+ }
if (!isFixedRotationTransformEnabled(this)) {
return;
}
mDeviceState.enableMultipleRegions(baseInputConsumer instanceof OtherActivityInputConsumer);
BaseDraggingActivity activity =
mOverviewComponentObserver.getActivityInterface().getCreatedActivity();
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "handleOrientationSetup.2");
+ }
if (activity == null || !(activity.getOverviewPanel() instanceof RecentsView)) {
return;
}
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "handleOrientationSetup.3");
+ }
((RecentsView) activity.getOverviewPanel())
.setLayoutRotation(mDeviceState.getCurrentActiveRotation(),
mDeviceState.getDisplayRotation());
@@ -637,14 +649,7 @@
runningComponent != null && runningComponent.equals(homeComponent);
}
- if (previousGestureState.getFinishingRecentsAnimationTaskId() > 0) {
- // If the finish animation was interrupted, then continue using the other activity input
- // consumer but with the next task as the running task
- RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
- info.id = previousGestureState.getFinishingRecentsAnimationTaskId();
- gestureState.updateRunningTask(info);
- return createOtherActivityInputConsumer(previousGestureState, gestureState, event);
- } else if (gestureState.getRunningTask() == null) {
+ if (gestureState.getRunningTask() == null) {
return mResetGestureInputConsumer;
} else if (previousGestureState.isRunningAnimationToLauncher()
|| gestureState.getActivityInterface().isResumed()
@@ -658,25 +663,22 @@
} else if (mDeviceState.isGestureBlockedActivity(gestureState.getRunningTask())) {
return mResetGestureInputConsumer;
} else {
- return createOtherActivityInputConsumer(previousGestureState, gestureState, event);
+ return createOtherActivityInputConsumer(gestureState, event);
}
}
- private InputConsumer createOtherActivityInputConsumer(GestureState previousGestureState,
- GestureState gestureState, MotionEvent event) {
+ private InputConsumer createOtherActivityInputConsumer(GestureState gestureState,
+ MotionEvent event) {
- final boolean shouldDefer;
final BaseSwipeUpHandler.Factory factory;
-
if (!mOverviewComponentObserver.isHomeAndOverviewSame()) {
- shouldDefer = previousGestureState.getFinishingRecentsAnimationTaskId() < 0;
factory = mFallbackSwipeHandlerFactory;
} else {
- shouldDefer = gestureState.getActivityInterface().deferStartingActivity(mDeviceState,
- event);
factory = mLauncherSwipeHandlerFactory;
}
+ final boolean shouldDefer = !mOverviewComponentObserver.isHomeAndOverviewSame()
+ || gestureState.getActivityInterface().deferStartingActivity(mDeviceState, event);
final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager,
gestureState, shouldDefer, this::onConsumerInactive,
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 7b8d40c..adf19df 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,8 +21,8 @@
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.Utilities.squaredTouchSlop;
-import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.LauncherSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW;
+import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
import android.content.ComponentName;
@@ -44,12 +44,13 @@
import com.android.quickstep.InputConsumer;
import com.android.quickstep.LockScreenRecentsActivity;
import com.android.quickstep.MultiStateCallback;
+import com.android.quickstep.RecentsAnimationCallbacks;
import com.android.quickstep.RecentsAnimationController;
import com.android.quickstep.RecentsAnimationDeviceState;
-import com.android.quickstep.RecentsAnimationCallbacks;
import com.android.quickstep.RecentsAnimationTargets;
import com.android.quickstep.TaskAnimationManager;
import com.android.quickstep.util.AppWindowAnimationHelper;
+import com.android.quickstep.util.TransformParams;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -84,7 +85,7 @@
private final PointF mTouchDown = new PointF();
private final AppWindowAnimationHelper mAppWindowAnimationHelper;
- private final AppWindowAnimationHelper.TransformParams mTransformParams;
+ private final TransformParams mTransformParams;
private final Point mDisplaySize;
private final MultiStateCallback mStateCallback;
@@ -105,7 +106,7 @@
mGestureState = gestureState;
mTouchSlopSquared = squaredTouchSlop(context);
mAppWindowAnimationHelper = new AppWindowAnimationHelper(context);
- mTransformParams = new AppWindowAnimationHelper.TransformParams();
+ mTransformParams = new TransformParams();
mInputMonitorCompat = inputMonitorCompat;
// Do not use DeviceProfile as the user data might be locked
@@ -230,8 +231,7 @@
Utilities.scaleRectAboutCenter(displaySize, SCALE_DOWN);
displaySize.offsetTo(displaySize.left, 0);
- mTransformParams.setTargetSet(mRecentsAnimationTargets)
- .setLauncherOnTop(true);
+ mTransformParams.setTargetSet(mRecentsAnimationTargets);
mAppWindowAnimationHelper.updateTargetRect(displaySize);
mAppWindowAnimationHelper.applyTransform(mTransformParams);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
index 6bfabcd..c82d4b5 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
+import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -95,6 +96,9 @@
ev.setEdgeFlags(flags | Utilities.EDGE_NAV_BAR);
}
ev.offsetLocation(-mLocationOnScreen[0], -mLocationOnScreen[1]);
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "OverviewInputConsumer");
+ }
boolean handled = mEventReceiver.test(ev);
ev.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
ev.setEdgeFlags(flags);
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 cd7c7ee..a7979cc 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
@@ -15,11 +15,10 @@
*/
package com.android.quickstep.util;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.launcher3.Utilities.boundToRange;
+import static com.android.launcher3.Utilities.mapRange;
import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
-import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
-import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import android.annotation.TargetApi;
import android.content.Context;
@@ -36,9 +35,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.views.BaseDragLayer;
-import com.android.quickstep.RemoteAnimationTargets;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskThumbnailView;
@@ -46,14 +43,14 @@
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
-import com.android.systemui.shared.system.TransactionCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder;
import com.android.systemui.shared.system.WindowManagerWrapper;
/**
* Utility class to handle window clip animation
*/
@TargetApi(Build.VERSION_CODES.P)
-public class AppWindowAnimationHelper {
+public class AppWindowAnimationHelper implements TransformParams.BuilderProxy {
// The bounds of the source app in device coordinates
private final RectF mSourceStackBounds = new RectF();
@@ -94,9 +91,6 @@
// Corner radius currently applied to transformed window.
private float mCurrentCornerRadius;
- private TargetAlphaProvider mTaskAlphaCallback = (t, a) -> a;
- private TargetAlphaProvider mBaseAlphaCallback = (t, a) -> 1;
-
public AppWindowAnimationHelper(RecentsOrientedState orientedState, Context context) {
Resources res = context.getResources();
mOrientedState = orientedState;
@@ -167,7 +161,7 @@
if (surfaceParams == null) {
return null;
}
- applySurfaceParams(params.mSyncTransactionApplier, surfaceParams);
+ params.applySurfaceParams(surfaceParams);
return mCurrentRect;
}
@@ -176,97 +170,60 @@
* the SurfaceParams to apply via {@link SyncRtSurfaceTransactionApplierCompat#applyParams}.
*/
public SurfaceParams[] computeSurfaceParams(TransformParams params) {
- if (params.mTargetSet == null) {
+ if (params.getTargetSet() == null) {
return null;
}
- float progress = Utilities.boundToRange(params.mProgress, 0, 1);
updateCurrentRect(params);
+ return params.createSurfaceParams(this);
+ }
- SurfaceParams[] surfaceParams = new SurfaceParams[params.mTargetSet.unfilteredApps.length];
- for (int i = 0; i < params.mTargetSet.unfilteredApps.length; i++) {
- RemoteAnimationTargetCompat app = params.mTargetSet.unfilteredApps[i];
- SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash);
+ @Override
+ public void onBuildParams(Builder builder, RemoteAnimationTargetCompat app,
+ int targetMode, TransformParams params) {
+ Rect crop = mTmpRect;
+ crop.set(app.screenSpaceBounds);
+ crop.offsetTo(0, 0);
+ float cornerRadius = 0f;
+ float scale = Math.max(mCurrentRect.width(), mTargetRect.width()) / crop.width();
+ if (app.mode == targetMode
+ && app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
+ mTmpMatrix.setRectToRect(mSourceRect, mCurrentRect, ScaleToFit.FILL);
if (app.localBounds != null) {
- mTmpMatrix.setTranslate(0, 0);
- if (app.activityType == ACTIVITY_TYPE_HOME && app.mode == MODE_CLOSING) {
- mTmpMatrix.setTranslate(app.localBounds.left, app.localBounds.top);
- }
+ mTmpMatrix.postTranslate(app.localBounds.left, app.localBounds.top);
} else {
- mTmpMatrix.setTranslate(app.position.x, app.position.y);
+ mTmpMatrix.postTranslate(app.position.x, app.position.y);
+ }
+ mCurrentClipRectF.roundOut(crop);
+ if (mSupportsRoundedCornersOnWindows) {
+ if (params.getCornerRadius() > -1) {
+ cornerRadius = params.getCornerRadius();
+ scale = mCurrentRect.width() / crop.width();
+ } else {
+ float windowCornerRadius = mUseRoundedCornersOnWindows
+ ? mWindowCornerRadius : 0;
+ cornerRadius = mapRange(boundToRange(params.getProgress(), 0, 1),
+ windowCornerRadius, mTaskCornerRadius);
+ }
+ mCurrentCornerRadius = cornerRadius;
}
- Rect crop = mTmpRect;
- crop.set(app.screenSpaceBounds);
- crop.offsetTo(0, 0);
- float alpha;
- float cornerRadius = 0f;
- float scale = Math.max(mCurrentRect.width(), mTargetRect.width()) / crop.width();
- if (app.mode == params.mTargetSet.targetMode) {
- alpha = mTaskAlphaCallback.getAlpha(app, params.mTargetAlpha);
- if (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);
- }
- mCurrentClipRectF.roundOut(crop);
- if (mSupportsRoundedCornersOnWindows) {
- if (params.mCornerRadius > -1) {
- cornerRadius = params.mCornerRadius;
- scale = mCurrentRect.width() / crop.width();
- } else {
- float windowCornerRadius = mUseRoundedCornersOnWindows
- ? mWindowCornerRadius : 0;
- cornerRadius = Utilities.mapRange(progress, windowCornerRadius,
- mTaskCornerRadius);
- }
- mCurrentCornerRadius = cornerRadius;
- }
- // Fade out Assistant overlay.
- if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT
- && app.isNotInRecents) {
- alpha = 1 - Interpolators.DEACCEL_2_5.getInterpolation(progress);
- }
- } else if (params.mTargetSet.hasRecents) {
- // If home has a different target then recents, reverse anim the
- // home target.
- alpha = 1 - (progress * params.mTargetAlpha);
- }
- } else {
- alpha = mBaseAlphaCallback.getAlpha(app, progress);
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && params.mLauncherOnTop) {
- crop = null;
- }
- }
- builder.withAlpha(alpha)
- .withMatrix(mTmpMatrix)
+ builder.withMatrix(mTmpMatrix)
.withWindowCrop(crop)
// Since radius is in Surface space, but we draw the rounded corners in screen
// space, we have to undo the scale
.withCornerRadius(cornerRadius / scale);
- surfaceParams[i] = builder.build();
+
}
- return surfaceParams;
}
public RectF updateCurrentRect(TransformParams params) {
- if (params.mCurrentRect != null) {
- mCurrentRect.set(params.mCurrentRect);
+ if (params.getCurrentRect() != null) {
+ mCurrentRect.set(params.getCurrentRect());
} else {
mTmpRectF.set(mTargetRect);
- Utilities.scaleRectFAboutCenter(mTmpRectF, params.mOffsetScale);
- mCurrentRect.set(mRectFEvaluator.evaluate(params.mProgress, mSourceRect, mTmpRectF));
- if (mOrientedState == null
- || !mOrientedState.isMultipleOrientationSupportedByDevice()) {
- mCurrentRect.offset(params.mOffset, 0);
- } else {
- int displayRotation = mOrientedState.getDisplayRotation();
- int launcherRotation = mOrientedState.getLauncherRotation();
- mOrientedState.getOrientationHandler().offsetTaskRect(mCurrentRect,
- params.mOffset, displayRotation, launcherRotation);
- }
+ mCurrentRect.set(mRectFEvaluator.evaluate(
+ params.getProgress(), mSourceRect, mTmpRectF));
}
updateClipRect(params);
@@ -275,7 +232,7 @@
private void updateClipRect(TransformParams params) {
// Don't clip past progress > 1.
- float progress = Math.min(1, params.mProgress);
+ float progress = Math.min(1, params.getProgress());
mCurrentClipRectF.left = mSourceWindowClipInsets.left * progress;
mCurrentClipRectF.top = mSourceWindowClipInsets.top * progress;
mCurrentClipRectF.right =
@@ -289,28 +246,6 @@
return mCurrentRectWithInsets;
}
- public static void applySurfaceParams(@Nullable SyncRtSurfaceTransactionApplierCompat
- syncTransactionApplier, SurfaceParams[] params) {
- if (syncTransactionApplier != null) {
- syncTransactionApplier.scheduleApply(params);
- } else {
- TransactionCompat t = new TransactionCompat();
- for (SurfaceParams param : params) {
- SyncRtSurfaceTransactionApplierCompat.applyParams(t, param);
- }
- t.setEarlyWakeup();
- t.apply();
- }
- }
-
- public void setTaskAlphaCallback(TargetAlphaProvider callback) {
- mTaskAlphaCallback = callback;
- }
-
- public void setBaseAlphaCallback(TargetAlphaProvider callback) {
- mBaseAlphaCallback = callback;
- }
-
public void fromTaskThumbnailView(TaskThumbnailView ttv, RecentsView rv,
@Nullable RemoteAnimationTargetCompat target) {
BaseDraggingActivity activity = BaseDraggingActivity.fromContext(ttv.getContext());
@@ -386,157 +321,4 @@
return mCurrentCornerRadius;
}
- public interface TargetAlphaProvider {
- float getAlpha(RemoteAnimationTargetCompat target, float expectedAlpha);
- }
-
- public static class TransformParams {
- private float mProgress;
- private float mOffset;
- private float mOffsetScale;
- private @Nullable RectF mCurrentRect;
- private float mTargetAlpha;
- private float mCornerRadius;
- private boolean mLauncherOnTop;
- private RemoteAnimationTargets mTargetSet;
- private SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier;
-
- public TransformParams() {
- mProgress = 0;
- mOffset = 0;
- mOffsetScale = 1;
- mCurrentRect = null;
- mTargetAlpha = 1;
- mCornerRadius = -1;
- mLauncherOnTop = false;
- }
-
- /**
- * Sets the progress of the transformation, where 0 is the source and 1 is the target. We
- * automatically adjust properties such as currentRect and cornerRadius based on this
- * progress, unless they are manually overridden by setting them on this TransformParams.
- */
- public TransformParams setProgress(float progress) {
- mProgress = progress;
- return this;
- }
-
- /**
- * Sets the corner radius of the transformed window, in pixels. If unspecified (-1), we
- * simply interpolate between the window's corner radius to the task view's corner radius,
- * based on {@link #mProgress}.
- */
- public TransformParams setCornerRadius(float cornerRadius) {
- mCornerRadius = cornerRadius;
- return this;
- }
-
- /**
- * Sets the current rect to show the transformed window, in device coordinates. This gives
- * the caller manual control of where to show the window. If unspecified (null), we
- * interpolate between {@link AppWindowAnimationHelper#mSourceRect} and
- * {@link AppWindowAnimationHelper#mTargetRect}, based on {@link #mProgress}.
- */
- public TransformParams setCurrentRect(RectF currentRect) {
- mCurrentRect = currentRect;
- return this;
- }
-
- /**
- * Specifies the alpha of the transformed window. Default is 1.
- */
- public TransformParams setTargetAlpha(float targetAlpha) {
- mTargetAlpha = targetAlpha;
- return this;
- }
-
- /**
- * If {@link #mCurrentRect} is null (i.e. {@link #setCurrentRect(RectF)} hasn't overridden
- * the default), then offset the current rect by this amount after computing the rect based
- * on {@link #mProgress}.
- */
- public TransformParams setOffset(float offset) {
- mOffset = offset;
- return this;
- }
-
- /**
- * If {@link #mCurrentRect} is null (i.e. {@link #setCurrentRect(RectF)} hasn't overridden
- * the default), then scale the current rect by this amount after computing the rect based
- * on {@link #mProgress}.
- */
- public TransformParams setOffsetScale(float offsetScale) {
- mOffsetScale = offsetScale;
- return this;
- }
-
- /**
- * If true, sets the crop = null and layer = Integer.MAX_VALUE for targets that don't match
- * {@link #mTargetSet}.targetMode. (Currently only does this when live tiles are enabled.)
- */
- public TransformParams setLauncherOnTop(boolean launcherOnTop) {
- mLauncherOnTop = launcherOnTop;
- return this;
- }
-
- /**
- * Specifies the set of RemoteAnimationTargetCompats that are included in the transformation
- * that these TransformParams help compute. These TransformParams generally only apply to
- * the targetSet.apps which match the targetSet.targetMode (e.g. the MODE_CLOSING app when
- * swiping to home).
- */
- public TransformParams setTargetSet(RemoteAnimationTargets targetSet) {
- mTargetSet = targetSet;
- return this;
- }
-
- /**
- * Sets the SyncRtSurfaceTransactionApplierCompat that will apply the SurfaceParams that
- * are computed based on these TransformParams.
- */
- public TransformParams setSyncTransactionApplier(
- SyncRtSurfaceTransactionApplierCompat applier) {
- mSyncTransactionApplier = applier;
- return this;
- }
-
- // Pubic getters so outside packages can read the values.
-
- public float getProgress() {
- return mProgress;
- }
-
- public float getOffset() {
- return mOffset;
- }
-
- public float getOffsetScale() {
- return mOffsetScale;
- }
-
- @Nullable
- public RectF getCurrentRect() {
- return mCurrentRect;
- }
-
- public float getTargetAlpha() {
- return mTargetAlpha;
- }
-
- public float getCornerRadius() {
- return mCornerRadius;
- }
-
- public boolean isLauncherOnTop() {
- return mLauncherOnTop;
- }
-
- public RemoteAnimationTargets getTargetSet() {
- return mTargetSet;
- }
-
- public SyncRtSurfaceTransactionApplierCompat getSyncTransactionApplier() {
- return mSyncTransactionApplier;
- }
- }
}
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 ea22d40..b8f0f4d 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
@@ -19,8 +19,6 @@
import static com.android.launcher3.states.RotationHelper.deltaRotation;
import static com.android.launcher3.touch.PagedOrientationHandler.MATRIX_POST_TRANSLATE;
-import static com.android.quickstep.util.AppWindowAnimationHelper.applySurfaceParams;
-import static com.android.quickstep.util.RecentsOrientedState.isFixedRotationTransformEnabled;
import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_FULLSCREEN;
@@ -33,24 +31,20 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.AnimatedFloat;
-import com.android.quickstep.RecentsAnimationTargets;
-import com.android.quickstep.util.AppWindowAnimationHelper.TargetAlphaProvider;
-import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams;
import com.android.quickstep.views.RecentsView.ScrollState;
import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper;
import com.android.quickstep.views.TaskView;
import com.android.quickstep.views.TaskView.FullscreenDrawParams;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder;
/**
* A utility class which emulates the layout behavior of TaskView and RecentsView
*/
-public class TaskViewSimulator {
+public class TaskViewSimulator implements TransformParams.BuilderProxy {
private final Rect mTmpCropRect = new Rect();
private final RectF mTempRectF = new RectF();
@@ -66,14 +60,11 @@
private final Matrix mMatrix = new Matrix();
private RemoteAnimationTargetCompat mRunningTarget;
- private RecentsAnimationTargets mAllTargets;
-
- private TargetAlphaProvider mTaskAlphaCallback = (t, a) -> a;
// Thumbnail view properties
private final Rect mThumbnailPosition = new Rect();
private final ThumbnailData mThumbnailData = new ThumbnailData();
- private final PreviewPositionHelper mPositionHelper;
+ private final PreviewPositionHelper mPositionHelper = new PreviewPositionHelper();
private final Matrix mInversePositionMatrix = new Matrix();
// TaskView properties
@@ -93,12 +84,8 @@
public TaskViewSimulator(Context context, WindowSizeStrategy sizeStrategy) {
mContext = context;
mSizeStrategy = sizeStrategy;
- mPositionHelper = new PreviewPositionHelper(context);
mOrientationState = new RecentsOrientedState(context, sizeStrategy, i -> { });
- // We do not need to attach listeners as the simulator is created just for the gesture
- // duration, and any settings are unlikely to change during this
- mOrientationState.initWithoutListeners();
mCurrentFullscreenParams = new FullscreenDrawParams(context);
mPageSpacing = context.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing);
@@ -117,15 +104,7 @@
* @see com.android.quickstep.views.RecentsView#setLayoutRotation(int, int)
*/
public void setLayoutRotation(int touchRotation, int displayRotation) {
- int launcherRotation;
- if (!mOrientationState.isMultipleOrientationSupportedByDevice()
- || mOrientationState.isHomeRotationAllowed()) {
- launcherRotation = displayRotation;
- } else {
- launcherRotation = ROTATION_0;
- }
-
- mOrientationState.update(touchRotation, displayRotation, launcherRotation);
+ mOrientationState.update(touchRotation, displayRotation);
mLayoutValid = false;
}
@@ -143,10 +122,8 @@
/**
* Sets the targets which the simulator will control
*/
- public void setPreview(
- RemoteAnimationTargetCompat runningTarget, RecentsAnimationTargets allTargets) {
+ public void setPreview(RemoteAnimationTargetCompat runningTarget) {
mRunningTarget = runningTarget;
- mAllTargets = allTargets;
mThumbnailData.insets.set(mRunningTarget.contentInsets);
// TODO: What is this?
@@ -169,10 +146,40 @@
}
/**
- * Sets an alternate function which can be used to control the alpha
+ * Returns the current clipped/visible window bounds in the window coordinate space
*/
- public void setTaskAlphaCallback(TargetAlphaProvider callback) {
- mTaskAlphaCallback = callback;
+ public RectF getCurrentCropRect() {
+ // Crop rect is the inverse of thumbnail matrix
+ RectF insets = mCurrentFullscreenParams.mCurrentDrawnInsets;
+ mTempRectF.set(-insets.left, -insets.top,
+ mTaskRect.width() + insets.right, mTaskRect.height() + insets.bottom);
+ mInversePositionMatrix.mapRect(mTempRectF);
+ return mTempRectF;
+ }
+
+ public RecentsOrientedState getOrientationState() {
+ return mOrientationState;
+ }
+
+ /**
+ * Returns the current transform applied to the window
+ */
+ public Matrix getCurrentMatrix() {
+ return mMatrix;
+ }
+
+ /**
+ * Applies the rotation on the matrix to so that it maps from launcher coordinate space to
+ * window coordinate space.
+ */
+ public void applyWindowToHomeRotation(Matrix matrix) {
+ mMatrix.postTranslate(mDp.windowX, mDp.windowY);
+ postDisplayRotation(deltaRotation(
+ mOrientationState.getLauncherRotation(), mOrientationState.getDisplayRotation()),
+ mDp.widthPx, mDp.heightPx, matrix);
+ if (mRunningTarget != null) {
+ matrix.postTranslate(-mRunningTarget.position.x, -mRunningTarget.position.y);
+ }
}
/**
@@ -186,12 +193,12 @@
mLayoutValid = true;
getFullScreenScale();
- mThumbnailData.rotation = isFixedRotationTransformEnabled(mContext)
- ? mOrientationState.getDisplayRotation() : mPositionHelper.getCurrentRotation();
+ mThumbnailData.rotation = mOrientationState.getDisplayRotation();
- mPositionHelper.updateThumbnailMatrix(mThumbnailPosition, mThumbnailData,
- mTaskRect.width(), mTaskRect.height(), mDp);
-
+ mPositionHelper.updateThumbnailMatrix(
+ mThumbnailPosition, mThumbnailData,
+ mTaskRect.width(), mTaskRect.height(),
+ mDp, mOrientationState.getLauncherRotation());
mPositionHelper.getMatrix().invert(mInversePositionMatrix);
PagedOrientationHandler poh = mOrientationState.getOrientationHandler();
@@ -201,7 +208,6 @@
mScrollValid = false;
}
-
if (!mScrollValid) {
mScrollValid = true;
int start = mOrientationState.getOrientationHandler()
@@ -233,11 +239,7 @@
// Apply recensView matrix
mMatrix.postScale(recentsViewScale.value, recentsViewScale.value, mPivot.x, mPivot.y);
- postDisplayRotation(deltaRotation(
- mOrientationState.getLauncherRotation(), mOrientationState.getDisplayRotation()),
- mDp.widthPx, mDp.heightPx, mMatrix);
- mMatrix.postTranslate(mDp.windowX - mRunningTarget.position.x,
- mDp.windowY - mRunningTarget.position.y);
+ applyWindowToHomeRotation(mMatrix);
// Crop rect is the inverse of thumbnail matrix
mTempRectF.set(-insets.left, -insets.top,
@@ -245,35 +247,18 @@
mInversePositionMatrix.mapRect(mTempRectF);
mTempRectF.roundOut(mTmpCropRect);
- SurfaceParams[] surfaceParams = new SurfaceParams[mAllTargets.unfilteredApps.length];
- for (int i = 0; i < mAllTargets.unfilteredApps.length; i++) {
- RemoteAnimationTargetCompat app = mAllTargets.unfilteredApps[i];
- SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash);
+ params.applySurfaceParams(params.createSurfaceParams(this));
+ }
- if (app.mode == mAllTargets.targetMode) {
- float alpha = mTaskAlphaCallback.getAlpha(app, params.getTargetAlpha());
- if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
- // Fade out Assistant overlay.
- if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT
- && app.isNotInRecents) {
- alpha = Interpolators.ACCEL_2.getInterpolation(fullScreenProgress.value);
- }
-
- builder.withAlpha(alpha)
- .withMatrix(mMatrix)
- .withWindowCrop(mTmpCropRect)
- .withCornerRadius(getCurrentCornerRadius());
- } else if (params.getTargetSet().hasRecents) {
- // If home has a different target then recents, reverse anim the home target.
- builder.withAlpha(fullScreenProgress.value * params.getTargetAlpha());
- }
- } else {
- builder.withAlpha(1);
- }
- surfaceParams[i] = builder.build();
+ @Override
+ public void onBuildParams(Builder builder, RemoteAnimationTargetCompat app,
+ int targetMode, TransformParams params) {
+ if (app.mode == targetMode
+ && app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
+ builder.withMatrix(mMatrix)
+ .withWindowCrop(mTmpCropRect)
+ .withCornerRadius(getCurrentCornerRadius());
}
-
- applySurfaceParams(params.getSyncTransactionApplier(), surfaceParams);
}
/**
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java
new file mode 100644
index 0000000..83b64db
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java
@@ -0,0 +1,205 @@
+/*
+ * 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 android.graphics.RectF;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.Interpolators;
+import com.android.quickstep.RemoteAnimationTargets;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
+import com.android.systemui.shared.system.TransactionCompat;
+
+public class TransformParams {
+
+ private float mProgress;
+ private @Nullable RectF mCurrentRect;
+ private float mTargetAlpha;
+ private float mCornerRadius;
+ private RemoteAnimationTargets mTargetSet;
+ private SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier;
+
+ private TargetAlphaProvider mTaskAlphaCallback = (t, a) -> a;
+ private TargetAlphaProvider mBaseAlphaCallback = (t, a) -> 1;
+
+ public TransformParams() {
+ mProgress = 0;
+ mCurrentRect = null;
+ mTargetAlpha = 1;
+ mCornerRadius = -1;
+ }
+
+ /**
+ * Sets the progress of the transformation, where 0 is the source and 1 is the target. We
+ * automatically adjust properties such as currentRect and cornerRadius based on this
+ * progress, unless they are manually overridden by setting them on this TransformParams.
+ */
+ public TransformParams setProgress(float progress) {
+ mProgress = progress;
+ return this;
+ }
+
+ /**
+ * Sets the corner radius of the transformed window, in pixels. If unspecified (-1), we
+ * simply interpolate between the window's corner radius to the task view's corner radius,
+ * based on {@link #mProgress}.
+ */
+ public TransformParams setCornerRadius(float cornerRadius) {
+ mCornerRadius = cornerRadius;
+ return this;
+ }
+
+ /**
+ * Sets the current rect to show the transformed window, in device coordinates. This gives
+ * the caller manual control of where to show the window. If unspecified (null), we
+ * interpolate between {@link AppWindowAnimationHelper#mSourceRect} and
+ * {@link AppWindowAnimationHelper#mTargetRect}, based on {@link #mProgress}.
+ */
+ public TransformParams setCurrentRect(RectF currentRect) {
+ mCurrentRect = currentRect;
+ return this;
+ }
+
+ /**
+ * Specifies the alpha of the transformed window. Default is 1.
+ */
+ public TransformParams setTargetAlpha(float targetAlpha) {
+ mTargetAlpha = targetAlpha;
+ return this;
+ }
+
+ /**
+ * Specifies the set of RemoteAnimationTargetCompats that are included in the transformation
+ * that these TransformParams help compute. These TransformParams generally only apply to
+ * the targetSet.apps which match the targetSet.targetMode (e.g. the MODE_CLOSING app when
+ * swiping to home).
+ */
+ public TransformParams setTargetSet(RemoteAnimationTargets targetSet) {
+ mTargetSet = targetSet;
+ return this;
+ }
+
+ /**
+ * Sets the SyncRtSurfaceTransactionApplierCompat that will apply the SurfaceParams that
+ * are computed based on these TransformParams.
+ */
+ public TransformParams setSyncTransactionApplier(
+ SyncRtSurfaceTransactionApplierCompat applier) {
+ mSyncTransactionApplier = applier;
+ return this;
+ }
+
+ /**
+ * Sets an alternate function which can be used to control the alpha of target app
+ */
+ public TransformParams setTaskAlphaCallback(TargetAlphaProvider callback) {
+ mTaskAlphaCallback = callback;
+ return this;
+ }
+
+ /**
+ * Sets an alternate function which can be used to control the alpha of non-target app
+ */
+ public TransformParams setBaseAlphaCallback(TargetAlphaProvider callback) {
+ mBaseAlphaCallback = callback;
+ return this;
+ }
+
+ public SurfaceParams[] createSurfaceParams(BuilderProxy proxy) {
+ RemoteAnimationTargets targets = mTargetSet;
+ SurfaceParams[] surfaceParams = new SurfaceParams[targets.unfilteredApps.length];
+ for (int i = 0; i < targets.unfilteredApps.length; i++) {
+ RemoteAnimationTargetCompat app = targets.unfilteredApps[i];
+ SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash);
+
+ float progress = Utilities.boundToRange(getProgress(), 0, 1);
+ float alpha;
+ if (app.mode == targets.targetMode) {
+ alpha = mTaskAlphaCallback.getAlpha(app, getTargetAlpha());
+ if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
+ // Fade out Assistant overlay.
+ if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT
+ && app.isNotInRecents) {
+ alpha = 1 - Interpolators.DEACCEL_2_5.getInterpolation(progress);
+ }
+ } else if (targets.hasRecents) {
+ // If home has a different target then recents, reverse anim the
+ // home target.
+ alpha = 1 - (progress * getTargetAlpha());
+ }
+ } else {
+ alpha = mBaseAlphaCallback.getAlpha(app, progress);
+ }
+ proxy.onBuildParams(builder.withAlpha(alpha), app, targets.targetMode, this);
+ surfaceParams[i] = builder.build();
+ }
+ return surfaceParams;
+ }
+
+ // Pubic getters so outside packages can read the values.
+
+ public float getProgress() {
+ return mProgress;
+ }
+
+ @Nullable
+ public RectF getCurrentRect() {
+ return mCurrentRect;
+ }
+
+ public float getTargetAlpha() {
+ return mTargetAlpha;
+ }
+
+ public float getCornerRadius() {
+ return mCornerRadius;
+ }
+
+ public RemoteAnimationTargets getTargetSet() {
+ return mTargetSet;
+ }
+
+ public SyncRtSurfaceTransactionApplierCompat getSyncTransactionApplier() {
+ return mSyncTransactionApplier;
+ }
+
+ public void applySurfaceParams(SurfaceParams[] params) {
+ if (mSyncTransactionApplier != null) {
+ mSyncTransactionApplier.scheduleApply(params);
+ } else {
+ TransactionCompat t = new TransactionCompat();
+ for (SurfaceParams param : params) {
+ SyncRtSurfaceTransactionApplierCompat.applyParams(t, param);
+ }
+ t.setEarlyWakeup();
+ t.apply();
+ }
+ }
+
+ public interface TargetAlphaProvider {
+ float getAlpha(RemoteAnimationTargetCompat target, float expectedAlpha);
+ }
+
+ public interface BuilderProxy {
+
+ void onBuildParams(SurfaceParams.Builder builder,
+ RemoteAnimationTargetCompat app, int targetMode, TransformParams params);
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
index 416af2b..9d7efc4 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -41,17 +41,16 @@
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.Hotseat;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager.StateListener;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.appprediction.PredictionUiStateManager;
import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
import com.android.launcher3.statehandlers.DepthController;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.views.ScrimView;
import com.android.quickstep.SysUINavigationMode;
-import com.android.quickstep.util.AppWindowAnimationHelper;
-import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams;
+import com.android.quickstep.util.TransformParams;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.RecentsExtraCard;
@@ -60,7 +59,7 @@
*/
@TargetApi(Build.VERSION_CODES.O)
public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
- implements StateListener {
+ implements StateListener<LauncherState> {
private final TransformParams mTransformParams = new TransformParams();
@@ -213,14 +212,14 @@
@Override
public void redrawLiveTile(boolean mightNeedToRefill) {
- AppWindowAnimationHelper.TransformParams transformParams = getLiveTileParams(mightNeedToRefill);
+ TransformParams transformParams = getLiveTileParams(mightNeedToRefill);
if (transformParams != null) {
mAppWindowAnimationHelper.applyTransform(transformParams);
}
}
@Override
- public AppWindowAnimationHelper.TransformParams getLiveTileParams(
+ public TransformParams getLiveTileParams(
boolean mightNeedToRefill) {
if (!mEnableDrawingLiveTile || mRecentsAnimationController == null
|| mRecentsAnimationTargets == null || mAppWindowAnimationHelper == null) {
@@ -248,8 +247,7 @@
.setCurrentRect(mTempRectF)
.setTargetAlpha(taskView.getAlpha())
.setSyncTransactionApplier(mSyncTransactionApplier)
- .setTargetSet(mRecentsAnimationTargets)
- .setLauncherOnTop(true);
+ .setTargetSet(mRecentsAnimationTargets);
}
return mTransformParams;
}
@@ -373,4 +371,16 @@
protected DepthController getDepthController() {
return mActivity.getDepthController();
}
+
+ @Override
+ public void setModalStateEnabled(boolean isModalState) {
+ super.setModalStateEnabled(isModalState);
+ if (isModalState) {
+ mActivity.getStateManager().goToState(LauncherState.OVERVIEW_MODAL_TASK);
+ } else {
+ if (mActivity.isInState(LauncherState.OVERVIEW_MODAL_TASK)) {
+ mActivity.getStateManager().goToState(LauncherState.OVERVIEW);
+ }
+ }
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java
index 0af1c0e..7201b02 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java
@@ -31,6 +31,7 @@
import com.android.launcher3.R;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
+import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.TaskOverlayFactory.OverlayUICallbacks;
import java.lang.annotation.Retention;
@@ -141,4 +142,21 @@
public AlphaProperty getVisibilityAlpha() {
return mMultiValueAlpha.getProperty(INDEX_VISIBILITY_ALPHA);
}
+
+ /** Updates vertical margins for different navigation mode. */
+ public void updateVerticalMarginForNavModeChange(Mode mode) {
+ int topMargin = getResources()
+ .getDimensionPixelSize(R.dimen.overview_actions_top_margin);
+ int bottomMargin = 0;
+ if (mode == Mode.THREE_BUTTONS) {
+ bottomMargin = getResources()
+ .getDimensionPixelSize(R.dimen.overview_actions_bottom_margin_three_button);
+ } else {
+ bottomMargin = getResources()
+ .getDimensionPixelSize(R.dimen.overview_actions_bottom_margin_gesture);
+ }
+ LayoutParams params = (LayoutParams) getLayoutParams();
+ params.setMargins(
+ params.leftMargin, topMargin, params.rightMargin, bottomMargin);
+ }
}
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 d9cbe0b..700af97 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -16,6 +16,8 @@
package com.android.quickstep.views;
+import static android.view.Surface.ROTATION_0;
+
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
@@ -30,8 +32,8 @@
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_DISMISS_SWIPE_UP;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_LAUNCH_SWIPE_DOWN;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
import static com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController.SUCCESS_TRANSITION_PROGRESS;
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP;
@@ -55,7 +57,6 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.PointF;
@@ -123,14 +124,15 @@
import com.android.quickstep.TaskUtils;
import com.android.quickstep.ViewUtils;
import com.android.quickstep.util.AppWindowAnimationHelper;
+import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RecentsOrientedState;
+import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.WindowSizeStrategy;
import com.android.systemui.plugins.ResourceProvider;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.ConfigurationCompat;
import com.android.systemui.shared.system.LauncherEventUtil;
import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
@@ -507,7 +509,7 @@
mIPinnedStackAnimationListener.setActivity(mActivity);
SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(
mIPinnedStackAnimationListener);
- mOrientationState.init();
+ mOrientationState.initListeners();
}
@Override
@@ -522,7 +524,7 @@
mIdp.removeOnChangeListener(this);
SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(null);
mIPinnedStackAnimationListener.setActivity(null);
- mOrientationState.destroy();
+ mOrientationState.destroyListeners();
}
@Override
@@ -598,20 +600,20 @@
}
@Override
- protected void onPageEndTransition() {
- super.onPageEndTransition();
- if (getNextPage() > 0) {
- setSwipeDownShouldLaunchApp(true);
- }
+ protected void onPageBeginTransition() {
+ super.onPageBeginTransition();
+ LayoutUtils.setViewEnabled(mActionsView, false);
}
@Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- int windowConfigurationRotation = ConfigurationCompat
- .getWindowConfigurationRotation(getResources().getConfiguration());
- setLayoutInternal(mOrientationState.getTouchRotation(),
- mOrientationState.getDisplayRotation(), windowConfigurationRotation);
+ protected void onPageEndTransition() {
+ super.onPageEndTransition();
+ if (getScrollX() == getScrollForPage(getPageNearestToCenterOfScreen())) {
+ LayoutUtils.setViewEnabled(mActionsView, true);
+ }
+ if (getNextPage() > 0) {
+ setSwipeDownShouldLaunchApp(true);
+ }
}
@Override
@@ -958,6 +960,7 @@
setCurrentPage(0);
mDwbToastShown = false;
mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, 0);
+ LayoutUtils.setViewEnabled(mActionsView, true);
}
public @Nullable TaskView getRunningTaskView() {
@@ -965,7 +968,15 @@
}
public int getRunningTaskIndex() {
- TaskView tv = getRunningTaskView();
+ return getTaskIndexForId(mRunningTaskId);
+ }
+
+ /**
+ * Get the index of the task view whose id matches {@param taskId}.
+ * @return -1 if there is no task view for the task id, else the index of the task view.
+ */
+ public int getTaskIndexForId(int taskId) {
+ TaskView tv = getTaskView(taskId);
return tv == null ? -1 : indexOfChild(tv);
}
@@ -1294,7 +1305,8 @@
ComponentKey compKey = TaskUtils.getLaunchComponentKeyForTask(taskView.getTask().key);
mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
endState.logAction, Direction.UP, index, compKey);
- mActivity.getStatsLogManager().log(TASK_DISMISS_SWIPE_UP, taskView.buildProto());
+ mActivity.getStatsLogManager().log(
+ LAUNCHER_TASK_DISMISS_SWIPE_UP, taskView.buildProto());
}
}
@@ -1574,19 +1586,14 @@
}
public void setLayoutRotation(int touchRotation, int displayRotation) {
- int launcherRotation = mOrientationState.getLauncherRotation();
- setLayoutInternal(touchRotation, displayRotation, launcherRotation);
- }
-
- private void setLayoutInternal(int touchRotation, int displayRotation, int launcherRotation) {
- if (mOrientationState.update(touchRotation, displayRotation, launcherRotation)) {
+ if (mOrientationState.update(touchRotation, displayRotation)) {
mOrientationHandler = mOrientationState.getOrientationHandler();
mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
mClearAllButton.setRotation(mOrientationHandler.getDegreesRotated());
mActivity.getDragLayer().recreateControllers();
mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION,
- touchRotation != 0 || launcherRotation != 0);
+ touchRotation != 0 || mOrientationState.getLauncherRotation() != ROTATION_0);
requestLayout();
}
}
@@ -1682,7 +1689,8 @@
}
int count = getChildCount();
- TaskView runningTask = mRunningTaskId == -1 ? null : getTaskView(mRunningTaskId);
+ TaskView runningTask = mRunningTaskId == -1 || !mRunningTaskTileHidden
+ ? null : getTaskView(mRunningTaskId);
int midPoint = runningTask == null ? -1 : indexOfChild(runningTask);
int currentPage = getCurrentPage();
@@ -1872,8 +1880,8 @@
mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
endState.logAction, Direction.DOWN, indexOfChild(tv),
TaskUtils.getLaunchComponentKeyForTask(task.key));
- mActivity.getStatsLogManager().log(TASK_LAUNCH_SWIPE_DOWN, tv.buildProto()
- );
+ mActivity.getStatsLogManager().log(
+ LAUNCHER_TASK_LAUNCH_SWIPE_DOWN, tv.buildProto());
}
} else {
onTaskLaunched(false);
@@ -2059,14 +2067,6 @@
return getScrollForPage(getRunningTaskIndex()) - mOrientationHandler.getPrimaryScroll(this);
}
- /**
- * @return How many pixels the running task is offset on the x-axis due to the current scrollX
- * and parent scale.
- */
- public float getScrollOffsetScaled() {
- return getScrollOffset() * mOrientationHandler.getPrimaryScale(this);
- }
-
public Consumer<MotionEvent> getEventDispatcher(float navbarRotation) {
float degreesRotated;
if (navbarRotation == 0) {
@@ -2100,7 +2100,7 @@
return mAppWindowAnimationHelper;
}
- public AppWindowAnimationHelper.TransformParams getLiveTileParams(
+ public TransformParams getLiveTileParams(
boolean mightNeedToRefill) {
return null;
}
@@ -2166,6 +2166,12 @@
}
/**
+ * Enables or disables modal state for RecentsView
+ * @param isModalState
+ */
+ public void setModalStateEnabled(boolean isModalState) { }
+
+ /**
* Used to register callbacks for when our empty message state changes.
*
* @see #setOnEmptyMessageUpdatedListener(OnEmptyMessageUpdatedListener)
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 b837a21..a3e360f 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
@@ -90,7 +90,7 @@
// Contains the portion of the thumbnail that is clipped when fullscreen progress = 0.
private final Rect mPreviewRect = new Rect();
- private final PreviewPositionHelper mPreviewPositionHelper;
+ private final PreviewPositionHelper mPreviewPositionHelper = new PreviewPositionHelper();
// Initialize with dummy value. It is overridden later by TaskView
private TaskView.FullscreenDrawParams mFullscreenParams = TEMP_PARAMS;
@@ -122,7 +122,6 @@
mDimmingPaintAfterClearing.setColor(Color.BLACK);
mActivity = BaseActivity.fromContext(context);
mIsDarkTextTheme = Themes.getAttrBoolean(mActivity, R.attr.isWorkspaceDarkText);
- mPreviewPositionHelper = new PreviewPositionHelper(context);
}
/**
@@ -349,8 +348,11 @@
if (mBitmapShader != null && mThumbnailData != null) {
mPreviewRect.set(0, 0, mThumbnailData.thumbnail.getWidth(),
mThumbnailData.thumbnail.getHeight());
+ int currentRotation = ConfigurationCompat.getWindowConfigurationRotation(
+ mActivity.getResources().getConfiguration());
mPreviewPositionHelper.updateThumbnailMatrix(mPreviewRect, mThumbnailData,
- getMeasuredWidth(), getMeasuredHeight(), mActivity.getDeviceProfile());
+ getMeasuredWidth(), getMeasuredHeight(), mActivity.getDeviceProfile(),
+ currentRotation);
mBitmapShader.setLocalMatrix(mPreviewPositionHelper.mMatrix);
mPaint.setShader(mBitmapShader);
@@ -417,17 +419,6 @@
private float mClipBottom = -1;
private boolean mIsOrientationChanged;
- private final Context mContext;
-
- public PreviewPositionHelper(Context context) {
- mContext = context;
- }
-
- public int getCurrentRotation() {
- return ConfigurationCompat.getWindowConfigurationRotation(
- mContext.getResources().getConfiguration());
- }
-
public Matrix getMatrix() {
return mMatrix;
}
@@ -436,7 +427,7 @@
* Updates the matrix based on the provided parameters
*/
public void updateThumbnailMatrix(Rect thumbnailPosition, ThumbnailData thumbnailData,
- int canvasWidth, int canvasHeight, DeviceProfile dp) {
+ int canvasWidth, int canvasHeight, DeviceProfile dp, int currentRotation) {
boolean isRotated = false;
boolean isOrientationDifferent;
mClipBottom = -1;
@@ -451,7 +442,6 @@
final float thumbnailScale;
int thumbnailRotation = thumbnailData.rotation;
- int currentRotation = getCurrentRotation();
int deltaRotate = getRotationDelta(currentRotation, thumbnailRotation);
Rect deviceInsets = dp.getInsets();
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
index 97652aa..da9468e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
@@ -30,7 +30,7 @@
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_LAUNCH_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -212,7 +212,7 @@
mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
Touch.TAP, Direction.NONE, getRecentsView().indexOfChild(this),
TaskUtils.getLaunchComponentKeyForTask(getTask().key));
- mActivity.getStatsLogManager().log(TASK_LAUNCH_TAP, buildProto());
+ mActivity.getStatsLogManager().log(LAUNCHER_TASK_LAUNCH_TAP, buildProto());
});
mCurrentFullscreenParams = new FullscreenDrawParams(context);
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index e5606a3..c1cf68e 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_split_screen" msgid="5353188922202653570">"Splitscreen"</string>
- <string name="recent_task_option_pin" msgid="7929860679018978258">"Anpinnen"</string>
+ <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixieren"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform-Modus"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Keine kürzlich verwendeten Elemente"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Einstellungen zur App-Nutzung"</string>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index b06dc6b..5c30651 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -17,14 +17,16 @@
<resources>
<dimen name="task_thumbnail_top_margin">24dp</dimen>
- <dimen name="task_thumbnail_bottom_margin_with_actions">44dp</dimen>
<dimen name="task_thumbnail_half_top_margin">12dp</dimen>
<dimen name="task_thumbnail_icon_size">48dp</dimen>
<!-- For screens without rounded corners -->
<dimen name="task_corner_radius_small">2dp</dimen>
<!-- Overrideable in overlay that provides the Overview Actions. -->
- <dimen name="overview_actions_height">110dp</dimen>
+ <dimen name="overview_actions_height">66dp</dimen>
+ <dimen name="overview_actions_top_margin">44dp</dimen>
+ <dimen name="overview_actions_bottom_margin_gesture">16dp</dimen>
+ <dimen name="overview_actions_bottom_margin_three_button">8dp</dimen>
<dimen name="overview_actions_horizontal_margin">16dp</dimen>
<dimen name="recents_page_spacing">10dp</dimen>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index b474a32..8368817 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -141,4 +141,6 @@
<string name="action_share">Share</string>
<!-- Label for a button that causes a screen shot of the current app to be taken. [CHAR_LIMIT=40] -->
<string name="action_screenshot">Screenshot</string>
+ <!-- Message shown when an action is blocked by a policy enforced by the app or the organization managing the device. [CHAR_LIMIT=NONE] -->
+ <string name="blocked_by_policy">This action isn\'t allowed by the app or your organization</string>
</resources>
\ No newline at end of file
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index c97ee7c..d3c4f4d 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -79,8 +79,8 @@
<style name="OverviewActionButton"
parent="@android:style/Widget.DeviceDefault.Button.Borderless">
- <item name="android:textColor">?attr/workspaceTextColor</item>
- <item name="android:drawableTint">?attr/workspaceTextColor</item>
+ <item name="android:textColor">@color/overview_button</item>
+ <item name="android:drawableTint">@color/overview_button</item>
<item name="android:tint">?attr/workspaceTextColor</item>
<item name="android:drawablePadding">4dp</item>
<item name="android:textAllCaps">false</item>
diff --git a/quickstep/robolectric_tests/src/com/android/quickstep/RecentsActivityTest.java b/quickstep/robolectric_tests/src/com/android/quickstep/RecentsActivityTest.java
new file mode 100644
index 0000000..93b64e6
--- /dev/null
+++ b/quickstep/robolectric_tests/src/com/android/quickstep/RecentsActivityTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.util.LauncherUIHelper.doLayout;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+
+import com.android.quickstep.fallback.FallbackRecentsView;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.android.controller.ActivityController;
+import org.robolectric.annotation.LooperMode;
+import org.robolectric.annotation.LooperMode.Mode;
+import org.robolectric.shadows.ShadowLooper;
+import org.robolectric.util.ReflectionHelpers;
+
+
+@RunWith(RobolectricTestRunner.class)
+@LooperMode(Mode.PAUSED)
+public class RecentsActivityTest {
+
+ @Test
+ public void testRecentsActivityCreates() {
+ ActivityController<RecentsActivity> controller =
+ Robolectric.buildActivity(RecentsActivity.class);
+
+ RecentsActivity launcher = controller.setup().get();
+ doLayout(launcher);
+
+ // TODO: Ensure that LauncherAppState is not created
+ }
+
+ @Test
+ public void testRecets_showCurrentTask() {
+ ActivityController<RecentsActivity> controller =
+ Robolectric.buildActivity(RecentsActivity.class);
+
+ RecentsActivity activity = controller.setup().get();
+ doLayout(activity);
+
+ FallbackRecentsView frv = activity.getOverviewPanel();
+ frv.showCurrentTask(22);
+ doLayout(activity);
+
+ ThumbnailData thumbnailData = new ThumbnailData();
+ ReflectionHelpers.setField(thumbnailData, "thumbnail",
+ Bitmap.createBitmap(300, 500, Config.ARGB_8888));
+ frv.switchToScreenshot(thumbnailData, () -> { });
+ ShadowLooper.idleMainLooper();
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 10e3a28..629a74b 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -30,7 +30,6 @@
import android.os.Bundle;
import android.os.CancellationSignal;
-import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.WellbeingModel;
import com.android.launcher3.popup.SystemShortcut;
@@ -38,6 +37,7 @@
import com.android.launcher3.proxy.StartActivityParams;
import com.android.launcher3.statehandlers.BackButtonAlphaHandler;
import com.android.launcher3.statehandlers.DepthController;
+import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.uioverrides.RecentsViewStateController;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.UiThreadHelper;
@@ -92,6 +92,9 @@
@Override
public void onNavigationModeChanged(Mode newMode) {
getDragLayer().recreateControllers();
+ if (mActionsView != null && isOverviewActionsEnabled()) {
+ mActionsView.updateVerticalMarginForNavModeChange(newMode);
+ }
}
@Override
@@ -150,6 +153,7 @@
@Override
protected void onDeferredResumed() {
+ super.onDeferredResumed();
if (mPendingActivityRequestCode != -1 && isInState(NORMAL)) {
// Remove any active ProxyActivityStarter task and send RESULT_CANCELED to Launcher.
onActivityResult(mPendingActivityRequestCode, RESULT_CANCELED, null);
@@ -167,13 +171,18 @@
mActionsView = findViewById(R.id.overview_actions_view);
((RecentsView) getOverviewPanel()).init(mActionsView);
- if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(this)) {
+ if (isOverviewActionsEnabled()) {
// Overview is above all other launcher elements, including qsb, so move it to the top.
getOverviewPanel().bringToFront();
mActionsView.bringToFront();
+ mActionsView.updateVerticalMarginForNavModeChange(SysUINavigationMode.getMode(this));
}
}
+ private boolean isOverviewActionsEnabled() {
+ return FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(this);
+ }
+
public <T extends OverviewActionsView> T getActionsView() {
return (T) mActionsView;
}
@@ -186,7 +195,7 @@
}
@Override
- protected StateHandler[] createStateHandlers() {
+ protected StateHandler<LauncherState>[] createStateHandlers() {
return new StateHandler[] {
getAllAppsController(),
getWorkspace(),
@@ -200,9 +209,8 @@
}
@Override
- protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs,
- LauncherStateManager stateManager) {
- return new QuickstepOnboardingPrefs(this, sharedPrefs, stateManager);
+ protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs) {
+ return new QuickstepOnboardingPrefs(this, sharedPrefs);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index 2cb23f1..fc60434 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.os.Build;
import android.os.Handler;
+import android.util.Log;
import androidx.annotation.BinderThread;
import androidx.annotation.UiThread;
@@ -37,6 +38,8 @@
public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat,
WrappedAnimationRunnerImpl {
+ private static final String TAG = "LauncherAnimationRunner";
+
private final Handler mHandler;
private final boolean mStartAtFrontOfQueue;
private AnimationResult mAnimationResult;
@@ -151,7 +154,16 @@
// Because t=0 has the app icon in its original spot, we can skip the
// first frame and have the same movement one frame earlier.
- mAnimator.setCurrentPlayTime(getSingleFrameMs(context));
+ int singleFrameMs = getSingleFrameMs(context);
+ long playTime = singleFrameMs;
+ // b/153821199 Add logs to debug crash but ensure release builds do not crash.
+ if (Utilities.IS_DEBUG_DEVICE) {
+ Log.e(TAG, "Total duration=[" + mAnimator.getTotalDuration()
+ + "], singleFrameMs=[" + singleFrameMs + "], mAnimator=" + mAnimator);
+ } else {
+ playTime = Math.min(singleFrameMs, mAnimator.getTotalDuration());
+ }
+ mAnimator.setCurrentPlayTime(playTime);
}
}
}
diff --git a/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java b/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java
index 075a483..13501a4 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java
@@ -16,14 +16,13 @@
package com.android.launcher3.statehandlers;
-import static com.android.launcher3.LauncherState.FLAG_HIDE_BACK_BUTTON;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.AnimatedFloat.VALUE;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.util.UiThreadHelper;
import com.android.quickstep.AnimatedFloat;
@@ -33,7 +32,7 @@
/**
* State handler for animating back button alpha
*/
-public class BackButtonAlphaHandler implements LauncherStateManager.StateHandler {
+public class BackButtonAlphaHandler implements StateHandler<LauncherState> {
private final BaseQuickstepLauncher mLauncher;
private final AnimatedFloat mBackAlpha = new AnimatedFloat(this::updateBackAlpha);
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index 8c778c0..8292a92 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -26,10 +26,10 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SurfaceControlCompat;
@@ -39,7 +39,7 @@
/**
* Controls blur and wallpaper zoom, for the Launcher surface only.
*/
-public class DepthController implements LauncherStateManager.StateHandler {
+public class DepthController implements StateHandler<LauncherState> {
public static final FloatProperty<DepthController> DEPTH =
new FloatProperty<DepthController>("depth") {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index 47fff5e..ec3a490 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -36,9 +36,9 @@
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.graphics.OverviewScrim;
+import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.quickstep.views.RecentsView;
@@ -49,7 +49,7 @@
* @param <T> the recents view
*/
public abstract class BaseRecentsViewStateController<T extends RecentsView>
- implements StateHandler {
+ implements StateHandler<LauncherState> {
protected final T mRecentsView;
protected final BaseQuickstepLauncher mLauncher;
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index d51d6df..bdddb3f 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -18,14 +18,12 @@
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.os.Build;
import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@@ -33,7 +31,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.statehandlers.DepthController;
-import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.ShelfPeekAnim;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -66,8 +63,6 @@
default void onSwipeUpToHomeComplete() { }
void onAssistantVisibilityChanged(float visibility);
- @NonNull HomeAnimationFactory prepareHomeUI();
-
AnimationFactory prepareRecentsUI(boolean activityVisible, boolean animateActivity,
Consumer<AnimatorPlaybackController> callback);
@@ -152,35 +147,4 @@
*/
default void setRecentsAttachedToAppWindow(boolean attached, boolean animate) { }
}
-
- interface HomeAnimationFactory {
-
- /** Return the floating view that will animate in sync with the closing window. */
- default @Nullable View getFloatingView() {
- return null;
- }
-
- @NonNull RectF getWindowTargetRect();
-
- @NonNull AnimatorPlaybackController createActivityAnimationToHome();
-
- default void playAtomicAnimation(float velocity) {
- // No-op
- }
-
- static RectF getDefaultWindowTargetRect(PagedOrientationHandler orientationHandler,
- DeviceProfile dp) {
- final int halfIconSize = dp.iconSizePx / 2;
- float primaryDimension = orientationHandler
- .getPrimaryValue(dp.availableWidthPx, dp.availableHeightPx);
- float secondaryDimension = orientationHandler
- .getSecondaryValue(dp.availableWidthPx, dp.availableHeightPx);
- final float targetX = primaryDimension / 2f;
- final float targetY = secondaryDimension - dp.hotseatBarSizePx;
- // Fallback to animate to center of screen.
- return new RectF(targetX - halfIconSize, targetY - halfIconSize,
- targetX + halfIconSize, targetY + halfIconSize);
- }
-
- }
}
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index 544f420..9b515ae 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -110,10 +110,6 @@
public static final int STATE_RECENTS_SCROLLING_FINISHED =
getFlagForIndex("STATE_RECENTS_SCROLLING_FINISHED");
- // Called when the new task appeared from quick switching.
- public static final int STATE_TASK_APPEARED_DURING_SWITCH =
- getFlagForIndex("STATE_TASK_APPEARED_DURING_SWITCH");
-
// Needed to interact with the current activity
private final Intent mHomeIntent;
private final Intent mOverviewIntent;
@@ -123,9 +119,8 @@
private ActivityManager.RunningTaskInfo mRunningTask;
private GestureEndTarget mEndTarget;
- private RemoteAnimationTargetCompat mAnimationTarget;
- // TODO: This can be removed once we stop finishing the animation when starting a new task
- private int mFinishingRecentsAnimationTaskId = -1;
+ private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
+ private int mLastStartedTaskId = -1;
public GestureState(OverviewComponentObserver componentObserver, int gestureId) {
mHomeIntent = componentObserver.getHomeIntent();
@@ -143,7 +138,8 @@
mGestureId = other.mGestureId;
mRunningTask = other.mRunningTask;
mEndTarget = other.mEndTarget;
- mFinishingRecentsAnimationTaskId = other.mFinishingRecentsAnimationTaskId;
+ mLastAppearedTaskTarget = other.mLastAppearedTaskTarget;
+ mLastStartedTaskId = other.mLastStartedTaskId;
}
public GestureState() {
@@ -226,20 +222,41 @@
}
/**
+ * Updates the last task that appeared during this gesture.
+ */
+ public void updateLastAppearedTaskTarget(RemoteAnimationTargetCompat lastAppearedTaskTarget) {
+ mLastAppearedTaskTarget = lastAppearedTaskTarget;
+ }
+
+ /**
+ * @return The id of the task that appeared during this gesture.
+ */
+ public int getLastAppearedTaskId() {
+ return mLastAppearedTaskTarget != null ? mLastAppearedTaskTarget.taskId : -1;
+ }
+
+ /**
+ * Updates the last task that we started via startActivityFromRecents() during this gesture.
+ */
+ public void updateLastStartedTaskId(int lastStartedTaskId) {
+ mLastStartedTaskId = lastStartedTaskId;
+ }
+
+ /**
+ * @return The id of the task that was most recently started during this gesture, or -1 if
+ * no task has been started yet (i.e. we haven't settled on a new task).
+ */
+ public int getLastStartedTaskId() {
+ return mLastStartedTaskId;
+ }
+
+ /**
* @return the end target for this gesture (if known).
*/
public GestureEndTarget getEndTarget() {
return mEndTarget;
}
- public void setAnimationTarget(RemoteAnimationTargetCompat target) {
- mAnimationTarget = target;
- }
-
- public RemoteAnimationTargetCompat getAnimationTarget() {
- return mAnimationTarget;
- }
-
/**
* Sets the end target of this gesture and immediately notifies the state changes.
*/
@@ -260,29 +277,8 @@
}
/**
- * @return the id for the task that was about to be launched following the finish of the recents
- * animation. Only defined between when the finish-recents call was made and the launch
- * activity call is made.
- */
- public int getFinishingRecentsAnimationTaskId() {
- return mFinishingRecentsAnimationTaskId;
- }
-
- /**
- * Sets the id for the task will be launched after the recents animation is finished. Once the
- * animation has finished then the id will be reset to -1.
- */
- public void setFinishingRecentsAnimationTaskId(int taskId) {
- mFinishingRecentsAnimationTaskId = taskId;
- mStateCallback.runOnceAtState(STATE_RECENTS_ANIMATION_FINISHED, () -> {
- mFinishingRecentsAnimationTaskId = -1;
- });
- }
-
- /**
* @return whether the current gesture is still running a recents animation to a state in the
* Launcher or Recents activity.
- * Updates the running task for the gesture to be the given {@param runningTask}.
*/
public boolean isRunningAnimationToLauncher() {
return isRecentsAnimationRunning() && mEndTarget != null && mEndTarget.isLauncher;
@@ -314,18 +310,13 @@
mStateCallback.setState(STATE_RECENTS_ANIMATION_ENDED);
}
- @Override
- public void onTaskAppeared(RemoteAnimationTargetCompat app) {
- mAnimationTarget = app;
- mStateCallback.setState(STATE_TASK_APPEARED_DURING_SWITCH);
- }
-
public void dump(PrintWriter pw) {
pw.println("GestureState:");
pw.println(" gestureID=" + mGestureId);
pw.println(" runningTask=" + mRunningTask);
pw.println(" endTarget=" + mEndTarget);
- pw.println(" finishingRecentsAnimationTaskId=" + mFinishingRecentsAnimationTaskId);
+ pw.println(" lastAppearedTaskTarget=" + mLastAppearedTaskTarget);
+ pw.println(" lastStartedTaskId=" + mLastStartedTaskId);
pw.println(" isRecentsAnimationRunning=" + isRecentsAnimationRunning());
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index 103ea4e..a21c714 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -159,6 +159,6 @@
/**
* Callback made when a task started from the recents is ready for an app transition.
*/
- default void onTaskAppeared(RemoteAnimationTargetCompat app) {}
+ default void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {}
}
}
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 21e8c92..cad51f4 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED;
+import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED;
import android.content.Intent;
import android.util.Log;
@@ -28,6 +29,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
@@ -36,6 +38,7 @@
private RecentsAnimationTargets mTargets;
// Temporary until we can hook into gesture state events
private GestureState mLastGestureState;
+ private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
/**
* Preloads the recents animation.
@@ -79,6 +82,8 @@
}
mController = controller;
mTargets = targets;
+ mLastAppearedTaskTarget = mTargets.findTask(mLastGestureState.getRunningTaskId());
+ mLastGestureState.updateLastAppearedTaskTarget(mLastAppearedTaskTarget);
}
@Override
@@ -96,6 +101,20 @@
public void onRecentsAnimationFinished(RecentsAnimationController controller) {
cleanUpRecentsAnimation(null /* canceledThumbnail */);
}
+
+ @Override
+ public void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
+ if (mController != null) {
+ if (mLastAppearedTaskTarget == null
+ || appearedTaskTarget.taskId != mLastAppearedTaskTarget.taskId) {
+ if (mLastAppearedTaskTarget != null) {
+ mController.removeTaskTarget(mLastAppearedTaskTarget);
+ }
+ mLastAppearedTaskTarget = appearedTaskTarget;
+ mLastGestureState.updateLastAppearedTaskTarget(mLastAppearedTaskTarget);
+ }
+ }
+ }
});
mCallbacks.addListener(gestureState);
mCallbacks.addListener(listener);
@@ -112,6 +131,9 @@
mCallbacks.removeListener(mLastGestureState);
mLastGestureState = gestureState;
mCallbacks.addListener(gestureState);
+ gestureState.setState(STATE_RECENTS_ANIMATION_INITIALIZED
+ | STATE_RECENTS_ANIMATION_STARTED);
+ gestureState.updateLastAppearedTaskTarget(mLastAppearedTaskTarget);
return mCallbacks;
}
@@ -171,6 +193,7 @@
mCallbacks = null;
mTargets = null;
mLastGestureState = null;
+ mLastAppearedTaskTarget = null;
}
public void dump() {
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index fe95e83..f3cefb9 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -75,9 +75,6 @@
@Override
Integer getActionTextButtonStringId() {
- if (mTutorialType == BACK_NAVIGATION_COMPLETE) {
- return R.string.gesture_tutorial_action_text_button_label;
- }
return null;
}
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index 2d51732..a98aad1 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -16,17 +16,17 @@
package com.android.quickstep.logging;
-import static android.stats.launcher.nano.Launcher.ALLAPPS;
-import static android.stats.launcher.nano.Launcher.BACKGROUND;
-import static android.stats.launcher.nano.Launcher.HOME;
-import static android.stats.launcher.nano.Launcher.OVERVIEW;
+import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.FOLDER;
+import static com.android.launcher3.logger.LauncherAtom.ItemInfo.ItemCase.WIDGET;
import android.content.Context;
+import android.util.Log;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.Utilities;
import com.android.launcher3.logger.LauncherAtom;
+import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.StatsLogManager;
-import com.android.launcher3.logging.StatsLogUtils;
import com.android.launcher3.model.AllAppsList;
import com.android.launcher3.model.BaseModelUpdateTask;
import com.android.launcher3.model.BgDataModel;
@@ -34,11 +34,13 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.util.IntSparseArrayMap;
+import com.android.launcher3.util.LogConfig;
+import com.android.systemui.shared.system.SysUiStatsLog;
import java.util.ArrayList;
/**
- * This method calls the StatsLog hidden method until they are made available public.
+ * This class calls StatsLog compile time generated methods.
*
* To see if the logs are properly sent to statsd, execute following command.
* $ adb root && adb shell statsd
@@ -47,29 +49,69 @@
*/
public class StatsLogCompatManager extends StatsLogManager {
- private static final int SUPPORTED_TARGET_DEPTH = 2;
private static final String TAG = "StatsLog";
- private static final boolean DEBUG = false;
+ private static final boolean IS_VERBOSE = Utilities.isPropertyEnabled(LogConfig.STATSLOG);
+
private static Context sContext;
+ private static final int DEFAULT_WIDGET_SPAN_XY = 1;
+ private static final int DEFAULT_WORKSPACE_GRID_XY = -1;
+ private static final int DEFAULT_PAGE_INDEX = -2;
+ private static final InstanceId DEFAULT_INSTANCE_ID = InstanceId.fakeInstanceId(0);
+
public StatsLogCompatManager(Context context) {
sContext = context;
}
+ /**
+ * Logs an event and accompanying {@link ItemInfo}
+ */
+ public void log(LauncherEvent event, LauncherAtom.ItemInfo itemInfo) {
+ log(event, DEFAULT_INSTANCE_ID, itemInfo);
+ }
+
+ /**
+ * Logs an event and accompanying {@link LauncherAtom.ItemInfo}
+ */
@Override
- public void verify() {
- if (!(StatsLogUtils.LAUNCHER_STATE_ALLAPPS == ALLAPPS
- && StatsLogUtils.LAUNCHER_STATE_BACKGROUND == BACKGROUND
- && StatsLogUtils.LAUNCHER_STATE_OVERVIEW == OVERVIEW
- && StatsLogUtils.LAUNCHER_STATE_HOME == HOME)) {
- throw new IllegalStateException(
- "StatsLogUtil constants doesn't match enums in launcher.proto");
+ public void log(LauncherEvent event, InstanceId instanceId, LauncherAtom.ItemInfo itemInfo) {
+ if (IS_VERBOSE) {
+ Log.d(TAG, String.format("\n%s\n%s", event.name(), itemInfo));
}
+ if (!Utilities.ATLEAST_R) {
+ return;
+ }
+ SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_EVENT,
+ SysUiStatsLog.LAUNCHER_UICHANGED__ACTION__DEFAULT_ACTION /* deprecated */,
+ SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__HOME /* TODO */,
+ SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__BACKGROUND /* TODO */,
+ null /* launcher extensions, deprecated */,
+ false /* quickstep_enabled, deprecated */,
+ event.getId() /* event_id */,
+ itemInfo.getItemCase().getNumber() /* target_id */,
+ instanceId.getId() /* instance_id TODO */,
+ 0 /* uid TODO */,
+ getPackageName(itemInfo) /* package_name */,
+ getComponentName(itemInfo) /* component_name */,
+ getGridX(itemInfo, false) /* grid_x */,
+ getGridY(itemInfo, false) /* grid_y */,
+ getPageId(itemInfo, false) /* page_id */,
+ getGridX(itemInfo, true) /* grid_x_parent */,
+ getGridY(itemInfo, true) /* grid_y_parent */,
+ getPageId(itemInfo, true) /* page_id_parent */,
+ getHierarchy(itemInfo) /* hierarchy */,
+ itemInfo.getIsWork() /* is_work_profile */,
+ itemInfo.getRank() /* rank */,
+ 0 /* fromState */,
+ 0 /* toState */,
+ null /* edittext */,
+ 0 /* cardinality */);
}
/**
* Logs the workspace layout information on the model thread.
*/
+ @Override
public void logSnapshot() {
LauncherAppState.getInstance(sContext).getModel().enqueueModelUpdateTask(
new SnapshotWorker());
@@ -84,18 +126,160 @@
for (ItemInfo info : workspaceItems) {
LauncherAtom.ItemInfo atomInfo = info.buildProto(null);
- // call StatsLog method
+ writeSnapshot(atomInfo);
}
for (FolderInfo fInfo : folders) {
for (ItemInfo info : fInfo.contents) {
LauncherAtom.ItemInfo atomInfo = info.buildProto(fInfo);
- // call StatsLog method
+ writeSnapshot(atomInfo);
}
}
for (ItemInfo info : appWidgets) {
LauncherAtom.ItemInfo atomInfo = info.buildProto(null);
- // call StatsLog method
+ writeSnapshot(atomInfo);
}
}
}
+ private static void writeSnapshot(LauncherAtom.ItemInfo itemInfo) {
+ if (IS_VERBOSE) {
+ Log.d(TAG, "\nwriteSnapshot:" + itemInfo);
+ }
+ if (!Utilities.ATLEAST_R) {
+ return;
+ }
+ SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_SNAPSHOT,
+ 0 /* event_id */,
+ itemInfo.getItemCase().getNumber() /* target_id */,
+ 0 /* instance_id */,
+ 0 /* uid */,
+ getPackageName(itemInfo) /* package_name */,
+ getComponentName(itemInfo) /* component_name */,
+ getGridX(itemInfo, false) /* grid_x */,
+ getGridY(itemInfo, false) /* grid_y */,
+ getPageId(itemInfo, false) /* page_id */,
+ getGridX(itemInfo, true) /* grid_x_parent */,
+ getGridY(itemInfo, true) /* grid_y_parent */,
+ getPageId(itemInfo, true) /* page_id_parent */,
+ getHierarchy(itemInfo) /* hierarchy */,
+ itemInfo.getIsWork() /* is_work_profile */,
+ 0 /* origin TODO */,
+ 0 /* cardinality */,
+ getSpanX(itemInfo),
+ getSpanY(itemInfo));
+ }
+
+ private static int getSpanX(LauncherAtom.ItemInfo atomInfo) {
+ if (atomInfo.getItemCase() != WIDGET) {
+ return DEFAULT_WIDGET_SPAN_XY;
+ }
+ return atomInfo.getWidget().getSpanX();
+ }
+
+ private static int getSpanY(LauncherAtom.ItemInfo atomInfo) {
+ if (atomInfo.getItemCase() != WIDGET) {
+ return DEFAULT_WIDGET_SPAN_XY;
+ }
+ return atomInfo.getWidget().getSpanY();
+ }
+
+ private static String getPackageName(LauncherAtom.ItemInfo atomInfo) {
+ switch (atomInfo.getItemCase()) {
+ case APPLICATION:
+ return atomInfo.getApplication().getPackageName();
+ case SHORTCUT:
+ return atomInfo.getShortcut().getShortcutName();
+ case WIDGET:
+ return atomInfo.getWidget().getPackageName();
+ case TASK:
+ return atomInfo.getTask().getPackageName();
+ default:
+ return null;
+ }
+ }
+
+ private static String getComponentName(LauncherAtom.ItemInfo atomInfo) {
+ switch (atomInfo.getItemCase()) {
+ case APPLICATION:
+ return atomInfo.getApplication().getComponentName();
+ case SHORTCUT:
+ return atomInfo.getShortcut().getShortcutName();
+ case WIDGET:
+ return atomInfo.getWidget().getComponentName();
+ case TASK:
+ return atomInfo.getTask().getComponentName();
+ default:
+ return null;
+ }
+ }
+
+ private static int getGridX(LauncherAtom.ItemInfo info, boolean parent) {
+ switch (info.getContainerInfo().getContainerCase()) {
+ case WORKSPACE:
+ if (parent) {
+ return DEFAULT_WORKSPACE_GRID_XY;
+ } else {
+ return info.getContainerInfo().getWorkspace().getGridX();
+ }
+ case FOLDER:
+ if (parent) {
+ switch (info.getContainerInfo().getFolder().getParentContainerCase()) {
+ case WORKSPACE:
+ return info.getContainerInfo().getFolder().getWorkspace().getGridX();
+ default:
+ return DEFAULT_WORKSPACE_GRID_XY;
+ }
+ } else {
+ return info.getContainerInfo().getFolder().getGridX();
+ }
+ default:
+ return DEFAULT_WORKSPACE_GRID_XY;
+ }
+ }
+
+ private static int getGridY(LauncherAtom.ItemInfo info, boolean parent) {
+ switch (info.getContainerInfo().getContainerCase()) {
+ case WORKSPACE:
+ if (parent) {
+ return DEFAULT_WORKSPACE_GRID_XY;
+ } else {
+ return info.getContainerInfo().getWorkspace().getGridY();
+ }
+ case FOLDER:
+ if (parent) {
+ switch (info.getContainerInfo().getFolder().getParentContainerCase()) {
+ case WORKSPACE:
+ return info.getContainerInfo().getFolder().getWorkspace().getGridY();
+ default:
+ return DEFAULT_WORKSPACE_GRID_XY;
+ }
+ } else {
+ return info.getContainerInfo().getFolder().getGridY();
+ }
+ default:
+ return DEFAULT_WORKSPACE_GRID_XY;
+ }
+ }
+
+ private static int getPageId(LauncherAtom.ItemInfo info, boolean parent) {
+ switch (info.getContainerInfo().getContainerCase()) {
+ case HOTSEAT:
+ return info.getContainerInfo().getHotseat().getIndex();
+ case WORKSPACE:
+ return info.getContainerInfo().getWorkspace().getPageIndex();
+ default:
+ return DEFAULT_PAGE_INDEX;
+ }
+ }
+
+ /**
+ *
+ */
+ private static int getHierarchy(LauncherAtom.ItemInfo info) {
+ // TODO
+ if (info.getContainerInfo().getContainerCase() == FOLDER) {
+ return info.getContainerInfo().getFolder().getParentContainerCase().getNumber() + 100;
+ } else {
+ return info.getContainerInfo().getContainerCase().getNumber();
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index 14e5485..fa53be2 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -21,6 +21,8 @@
import android.content.Context;
import android.graphics.Rect;
+import android.view.View;
+import android.view.ViewGroup;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
@@ -66,4 +68,21 @@
return srcHeight / targetHeight;
}
}
+
+ /**
+ * Recursively sets view and all children enabled/disabled.
+ * @param viewGroup Top most parent view to change.
+ * @param enabled True = enable, False = disable.
+ */
+ public static void setViewEnabled(ViewGroup viewGroup, boolean enabled) {
+ viewGroup.setEnabled(enabled);
+ for (int i = 0; i < viewGroup.getChildCount(); i++) {
+ View child = viewGroup.getChildAt(i);
+ if (child instanceof ViewGroup) {
+ setViewEnabled((ViewGroup) child, enabled);
+ } else {
+ child.setEnabled(enabled);
+ }
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
index 7d52571..a5d4568 100644
--- a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
+++ b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
@@ -19,11 +19,13 @@
import android.content.Context;
import android.content.res.Resources;
+import android.util.Log;
import android.view.MotionEvent;
import com.android.launcher3.Alarm;
import com.android.launcher3.R;
import com.android.launcher3.compat.AccessibilityManagerCompat;
+import com.android.launcher3.testing.TestProtocol;
/**
* Given positions along x- or y-axis, tracks velocity and acceleration and determines when there is
@@ -84,6 +86,9 @@
mSpeedSlow = res.getDimension(R.dimen.motion_pause_detector_speed_slow);
mSpeedSomewhatFast = res.getDimension(R.dimen.motion_pause_detector_speed_somewhat_fast);
mSpeedFast = res.getDimension(R.dimen.motion_pause_detector_speed_fast);
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "creating alarm");
+ }
mForcePauseTimeout = new Alarm();
mForcePauseTimeout.setOnAlarmListener(alarm -> updatePaused(true /* isPaused */));
mMakePauseHarderToTrigger = makePauseHarderToTrigger;
@@ -120,6 +125,9 @@
* @param pointerIndex Index for the pointer being tracked in the motion event
*/
public void addPosition(MotionEvent ev, int pointerIndex) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "setting alarm");
+ }
mForcePauseTimeout.setAlarm(mMakePauseHarderToTrigger
? HARDER_TRIGGER_TIMEOUT
: FORCE_PAUSE_TIMEOUT);
@@ -167,6 +175,9 @@
}
private void updatePaused(boolean isPaused) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "updatePaused: " + isPaused);
+ }
if (mDisallowPause) {
isPaused = false;
}
@@ -188,6 +199,9 @@
setOnMotionPauseListener(null);
mIsPaused = mHasEverBeenPaused = false;
mSlowStartTime = 0;
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "canceling alarm");
+ }
mForcePauseTimeout.cancelAlarm();
}
diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
index aa6d56a..2d8bba2 100644
--- a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
+++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
@@ -25,8 +25,8 @@
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
-import com.android.launcher3.LauncherStateManager.StateListener;
+import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.quickstep.SysUINavigationMode;
@@ -35,23 +35,23 @@
*/
public class QuickstepOnboardingPrefs extends OnboardingPrefs<BaseQuickstepLauncher> {
- public QuickstepOnboardingPrefs(BaseQuickstepLauncher launcher, SharedPreferences sharedPrefs,
- LauncherStateManager stateManager) {
- super(launcher, sharedPrefs, stateManager);
+ public QuickstepOnboardingPrefs(BaseQuickstepLauncher launcher, SharedPreferences sharedPrefs) {
+ super(launcher, sharedPrefs);
+ StateManager<LauncherState> stateManager = launcher.getStateManager();
if (!getBoolean(HOME_BOUNCE_SEEN)) {
- mStateManager.addStateListener(new StateListener() {
+ stateManager.addStateListener(new StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
boolean swipeUpEnabled = SysUINavigationMode.INSTANCE
.get(mLauncher).getMode().hasGestures;
- LauncherState prevState = mStateManager.getLastState();
+ LauncherState prevState = stateManager.getLastState();
if (((swipeUpEnabled && finalState == OVERVIEW) || (!swipeUpEnabled
&& finalState == ALL_APPS && prevState == NORMAL) ||
hasReachedMaxCount(HOME_BOUNCE_COUNT))) {
mSharedPrefs.edit().putBoolean(HOME_BOUNCE_SEEN, true).apply();
- mStateManager.removeStateListener(this);
+ stateManager.removeStateListener(this);
}
}
});
@@ -65,27 +65,27 @@
mSharedPrefs.edit().putBoolean(SHELF_BOUNCE_SEEN, shelfBounceSeen).apply();
}
if (!shelfBounceSeen) {
- mStateManager.addStateListener(new StateListener() {
+ stateManager.addStateListener(new StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
- LauncherState prevState = mStateManager.getLastState();
+ LauncherState prevState = stateManager.getLastState();
if ((finalState == ALL_APPS && prevState == OVERVIEW) ||
hasReachedMaxCount(SHELF_BOUNCE_COUNT)) {
mSharedPrefs.edit().putBoolean(SHELF_BOUNCE_SEEN, true).apply();
- mStateManager.removeStateListener(this);
+ stateManager.removeStateListener(this);
}
}
});
}
if (!hasReachedMaxCount(ALL_APPS_COUNT)) {
- mStateManager.addStateListener(new StateListener() {
+ stateManager.addStateListener(new StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
if (finalState == ALL_APPS) {
if (incrementEventCount(ALL_APPS_COUNT)) {
- mStateManager.removeStateListener(this);
+ stateManager.removeStateListener(this);
mLauncher.getScrimView().updateDragHandleVisibility();
}
}
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index f6c4e66..fffbb34 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -23,6 +23,7 @@
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
+import static com.android.launcher3.logging.LoggerUtils.extractObjectNameAndAddress;
import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@@ -36,7 +37,6 @@
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.os.Handler;
import android.provider.Settings;
import android.util.Log;
@@ -84,7 +84,7 @@
private @SurfaceRotation int mTouchRotation = ROTATION_0;
private @SurfaceRotation int mDisplayRotation = ROTATION_0;
- private @SurfaceRotation int mLauncherRotation = Surface.ROTATION_0;
+ private @SurfaceRotation int mLauncherRotation = ROTATION_0;
// Launcher activity supports multiple orientation, but fallback activity does not
private static final int FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY = 1 << 0;
@@ -102,6 +102,8 @@
private static final int FLAG_ROTATION_WATCHER_SUPPORTED = 1 << 6;
// Whether to enable rotation watcher when multi-rotation is supported
private static final int FLAG_ROTATION_WATCHER_ENABLED = 1 << 7;
+ // Enable home rotation for UI tests, ignoring home rotation value from prefs
+ private static final int FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING = 1 << 8;
private static final int MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE =
FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY
@@ -121,7 +123,6 @@
private final WindowSizeStrategy mSizeStrategy;
private final Matrix mTmpMatrix = new Matrix();
- private final Matrix mTmpInverseMatrix = new Matrix();
private int mFlags;
private int mPreviousRotation = ROTATION_0;
@@ -163,6 +164,10 @@
if (mOrientationListener.canDetectOrientation()) {
mFlags |= FLAG_ROTATION_WATCHER_SUPPORTED;
}
+
+ // initialize external flags
+ updateAutoRotateSetting();
+ updateHomeRotationSetting();
}
/**
@@ -181,13 +186,15 @@
* false otherwise
*/
public boolean update(
- @SurfaceRotation int touchRotation, @SurfaceRotation int displayRotation,
- @SurfaceRotation int launcherRotation) {
+ @SurfaceRotation int touchRotation, @SurfaceRotation int displayRotation) {
if (!isMultipleOrientationSupportedByDevice()) {
return false;
}
- if (mDisplayRotation == displayRotation && mTouchRotation == touchRotation
- && launcherRotation == mLauncherRotation) {
+
+ int launcherRotation = inferLauncherRotation(displayRotation);
+ if (mDisplayRotation == displayRotation
+ && mTouchRotation == touchRotation
+ && mLauncherRotation == launcherRotation) {
return false;
}
@@ -195,11 +202,10 @@
mDisplayRotation = displayRotation;
mTouchRotation = touchRotation;
- if (canLauncherRotate() || mLauncherRotation == mTouchRotation) {
- // TODO(b/153476489) Need to determine when launcher is rotated
+ if (mLauncherRotation == mTouchRotation) {
mOrientationHandler = PagedOrientationHandler.HOME_ROTATED;
if (DEBUG) {
- Log.d(TAG, "Set Orientation Handler: " + mOrientationHandler);
+ Log.d(TAG, "current RecentsOrientedState: " + this);
}
return true;
}
@@ -212,11 +218,20 @@
mOrientationHandler = PagedOrientationHandler.PORTRAIT;
}
if (DEBUG) {
- Log.d(TAG, "Set Orientation Handler: " + mOrientationHandler);
+ Log.d(TAG, "current RecentsOrientedState: " + this);
}
return true;
}
+ @SurfaceRotation
+ private int inferLauncherRotation(@SurfaceRotation int displayRotation) {
+ if (!isMultipleOrientationSupportedByDevice() || isHomeRotationAllowed()) {
+ return displayRotation;
+ } else {
+ return ROTATION_0;
+ }
+ }
+
private void setFlag(int mask, boolean enabled) {
boolean wasRotationEnabled = !TestProtocol.sDisableSensorRotation
&& mFlags == VALUE_ROTATION_WATCHER_ENABLED;
@@ -241,7 +256,9 @@
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
- updateHomeRotationSetting();
+ if (ALLOW_ROTATION_PREFERENCE_KEY.equals(s)) {
+ updateHomeRotationSetting();
+ }
}
private void updateAutoRotateSetting() {
@@ -255,23 +272,24 @@
}
/**
- * Initializes aany system values and registers corresponding change listeners. It must be
- * paired with {@link #destroy()} call
+ * Initializes any system values and registers corresponding change listeners. It must be
+ * paired with {@link #destroyListeners()} call
*/
- public void init() {
+ public void initListeners() {
if (isMultipleOrientationSupportedByDevice()) {
mSharedPrefs.registerOnSharedPreferenceChangeListener(this);
mContentResolver.registerContentObserver(
Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION),
false, mSystemAutoRotateObserver);
}
- initWithoutListeners();
+ updateAutoRotateSetting();
+ updateHomeRotationSetting();
}
/**
* Unregisters any previously registered listeners.
*/
- public void destroy() {
+ public void destroyListeners() {
if (isMultipleOrientationSupportedByDevice()) {
mSharedPrefs.unregisterOnSharedPreferenceChangeListener(this);
mContentResolver.unregisterContentObserver(mSystemAutoRotateObserver);
@@ -279,13 +297,8 @@
setRotationWatcherEnabled(false);
}
- /**
- * Initializes the OrientationState without attaching any listeners. This can be used when
- * the object is short lived.
- */
- public void initWithoutListeners() {
- updateAutoRotateSetting();
- updateHomeRotationSetting();
+ public void forceAllowRotationForTesting(boolean forceAllow) {
+ setFlag(FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING, forceAllow);
}
@SurfaceRotation
@@ -310,7 +323,8 @@
public boolean isHomeRotationAllowed() {
return (mFlags & (FLAG_HOME_ROTATION_ALLOWED_IN_PREFS | FLAG_MULTIWINDOW_ROTATION_ALLOWED))
- != 0;
+ != 0 ||
+ (mFlags & FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING) != 0;
}
public boolean canLauncherRotate() {
@@ -403,23 +417,6 @@
*/
}
- public void mapRectFromNormalOrientation(RectF src, int screenWidth, int screenHeight) {
- mapRectFromRotation(mDisplayRotation, src, screenWidth, screenHeight);
- }
-
- public void mapRectFromRotation(int rotation, RectF src, int screenWidth, int screenHeight) {
- mTmpMatrix.reset();
- postDisplayRotation(rotation, screenWidth, screenHeight, mTmpMatrix);
- mTmpMatrix.mapRect(src);
- }
-
- public void mapInverseRectFromNormalOrientation(RectF src, int screenWidth, int screenHeight) {
- mTmpMatrix.reset();
- postDisplayRotation(mDisplayRotation, screenWidth, screenHeight, mTmpMatrix);
- mTmpMatrix.invert(mTmpInverseMatrix);
- mTmpInverseMatrix.mapRect(src);
- }
-
@SurfaceRotation
public static int getRotationForUserDegreesRotated(float degrees, int currentRotation) {
if (degrees == ORIENTATION_UNKNOWN) {
@@ -440,9 +437,13 @@
if (degrees < (90 - threshold)) {
return ROTATION_0;
}
- if (degrees > (90 + threshold)) {
+ if (degrees > (90 + threshold) && degrees < 180) {
return ROTATION_180;
}
+ // flip from seascape to landscape
+ if (degrees > (180 + threshold) && degrees < 360) {
+ return ROTATION_90;
+ }
break;
case ROTATION_180:
if (degrees < (180 - threshold)) {
@@ -453,12 +454,16 @@
}
break;
case ROTATION_90:
- if (degrees < (270 - threshold)) {
+ if (degrees < (270 - threshold) && degrees > 90) {
return ROTATION_180;
}
- if (degrees > (270 + threshold)) {
+ if (degrees > (270 + threshold) && degrees < 360) {
return ROTATION_0;
}
+ // flip from landscape to seascape
+ if (degrees > threshold && degrees < 180) {
+ return ROTATION_270;
+ }
break;
}
@@ -506,13 +511,15 @@
public String toString() {
boolean systemRotationOn = (mFlags & FLAG_SYSTEM_ROTATION_ALLOWED) != 0;
return "["
- + "mDisplayRotation=" + mDisplayRotation
+ + "this=" + extractObjectNameAndAddress(super.toString())
+ + " mOrientationHandler=" +
+ extractObjectNameAndAddress(mOrientationHandler.toString())
+ + " mDisplayRotation=" + mDisplayRotation
+ " mTouchRotation=" + mTouchRotation
+ " mLauncherRotation=" + mLauncherRotation
+ " mHomeRotation=" + isHomeRotationAllowed()
+ " mSystemRotation=" + systemRotationOn
+ " mFlags=" + mFlags
- + " mOrientationHandler=" + mOrientationHandler
+ "]";
}
}
diff --git a/quickstep/src/com/android/quickstep/util/WindowSizeStrategy.java b/quickstep/src/com/android/quickstep/util/WindowSizeStrategy.java
index 8bb0d70..81a1924 100644
--- a/quickstep/src/com/android/quickstep/util/WindowSizeStrategy.java
+++ b/quickstep/src/com/android/quickstep/util/WindowSizeStrategy.java
@@ -16,6 +16,7 @@
package com.android.quickstep.util;
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
+import static com.android.quickstep.SysUINavigationMode.getMode;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import static com.android.quickstep.util.LayoutUtils.getDefaultSwipeHeight;
@@ -26,6 +27,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
+import com.android.quickstep.SysUINavigationMode.Mode;
/**
* Utility class to wrap different layout behavior for Launcher and RecentsView
@@ -136,7 +138,19 @@
if (showOverviewActions(context)) {
//TODO: this needs to account for the swipe gesture height and accessibility
// UI when shown.
- return res.getDimensionPixelSize(R.dimen.overview_actions_height);
+ float actionsBottomMargin = 0;
+ if (getMode(context) == Mode.THREE_BUTTONS) {
+ actionsBottomMargin = res.getDimensionPixelSize(
+ R.dimen.overview_actions_bottom_margin_three_button);
+ } else {
+ actionsBottomMargin = res.getDimensionPixelSize(
+ R.dimen.overview_actions_bottom_margin_gesture);
+ }
+ float actionsTopMargin = res.getDimensionPixelSize(
+ R.dimen.overview_actions_top_margin);
+ float actionsHeight = actionsTopMargin + actionsBottomMargin
+ + res.getDimensionPixelSize(R.dimen.overview_actions_height);
+ return actionsHeight;
} else {
return getDefaultSwipeHeight(context, dp) + dp.workspacePageIndicatorHeight
+ res.getDimensionPixelSize(
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 75fcfe2..bf093fd 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -42,6 +42,7 @@
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import com.android.quickstep.views.RecentsView;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -53,6 +54,18 @@
public void setUp() throws Exception {
super.setUp();
TaplTestsLauncher3.initialize(this);
+ executeOnLauncher(launcher -> {
+ RecentsView recentsView = launcher.getOverviewPanel();
+ recentsView.getPagedViewOrientedState().forceAllowRotationForTesting(true);
+ });
+ }
+
+ @After
+ public void tearDown() {
+ executeOnLauncher(launcher -> {
+ RecentsView recentsView = launcher.getOverviewPanel();
+ recentsView.getPagedViewOrientedState().forceAllowRotationForTesting(false);
+ });
}
private void startTestApps() throws Exception {
diff --git a/res/color/overview_button.xml b/res/color/overview_button.xml
new file mode 100644
index 0000000..6ac36bf
--- /dev/null
+++ b/res/color/overview_button.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:alpha="1"
+ android:color="?attr/workspaceTextColor"
+ android:state_enabled="true" />
+ <item
+ android:alpha="?android:disabledAlpha"
+ android:color="?attr/workspaceTextColor"
+ android:state_enabled="false" />
+</selector>
\ No newline at end of file
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 3276d44..af40f5c 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -131,7 +131,7 @@
<string name="accessibility_close" msgid="2277148124685870734">"بستن"</string>
<string name="notification_dismissed" msgid="6002233469409822874">"اعلان رد شد"</string>
<string name="all_apps_personal_tab" msgid="4190252696685155002">"شخصی"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"محل کار"</string>
+ <string name="all_apps_work_tab" msgid="4884822796154055118">"کاری"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"نمایه کاری"</string>
<string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"دادههای شخصی از برنامههای کاری جدا است و از آن پنهان است"</string>
<string name="work_profile_edu_work_apps" msgid="237051938268703058">"برنامههای کاری و دادهها برای سرپرست فناوری اطلاعات نمایان هستند"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 1d69f86..0aa2f1b 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="work_folder_name" msgid="3753320833950115786">"કાર્યાલય"</string>
+ <string name="work_folder_name" msgid="3753320833950115786">"ઑફિસ"</string>
<string name="activity_not_found" msgid="8071924732094499514">"ઍપ્લિકેશન ઇન્સ્ટોલ થઈ નથી."</string>
<string name="activity_not_available" msgid="7456344436509528827">"ઍપ્લિકેશન ઉપલબ્ધ નથી"</string>
<string name="safemode_shortcut_error" msgid="9160126848219158407">"સુરક્ષિત મોડમાં ડાઉનલોડ કરેલ ઍપ્લિકેશન અક્ષમ કરી"</string>
@@ -131,7 +131,7 @@
<string name="accessibility_close" msgid="2277148124685870734">"બંધ કરો"</string>
<string name="notification_dismissed" msgid="6002233469409822874">"સૂચના છોડી દીધી"</string>
<string name="all_apps_personal_tab" msgid="4190252696685155002">"મનગમતી ઍપ"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"કાર્યાલયની ઍપ"</string>
+ <string name="all_apps_work_tab" msgid="4884822796154055118">"ઑફિસની ઍપ"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"ઑફિસની પ્રોફાઇલ"</string>
<string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"વ્યક્તિગત ડેટા ઑફિસ માટેની ઍપથી અલગ અને છુપાવીને રાખેલો છે"</string>
<string name="work_profile_edu_work_apps" msgid="237051938268703058">"ઑફિસ માટેની ઍપ અને ડેટા તમારા IT વ્યવસ્થાપકને દેખાય છે"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 3fa16ab..4667ede 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -53,11 +53,11 @@
<string name="app_info_drop_target_label" msgid="692894985365717661">"अनुप्रयोगको जानकारी"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"स्थापना गर्नुहोस्"</string>
<string name="permlab_install_shortcut" msgid="5632423390354674437">"सर्टकट स्थापना गर्नेहोस्"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा अनुप्रयोगलाई सर्टकटमा थप्नको लागि अनुमति दिनुहोस्।"</string>
+ <string name="permdesc_install_shortcut" msgid="923466509822011139">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा एपलाई सर्टकटमा थप्नको लागि अनुमति दिनुहोस्।"</string>
<string name="permlab_read_settings" msgid="1941457408239617576">"गृह सेटिङहरू र सर्टकटहरू पढ्नुहोस्"</string>
- <string name="permdesc_read_settings" msgid="5833423719057558387">"गृहमा एउटा अनुप्रयोगलाई सेटिङहरू र सर्टकटहरू पढ्न अनुमति दिनुहोस्।"</string>
+ <string name="permdesc_read_settings" msgid="5833423719057558387">"गृहमा एउटा एपलाई सेटिङहरू र सर्टकटहरू पढ्न अनुमति दिनुहोस्।"</string>
<string name="permlab_write_settings" msgid="3574213698004620587">"गृह सेटिङहरू र सर्टकटहरू लेख्नुहोस्"</string>
- <string name="permdesc_write_settings" msgid="5440712911516509985">"गृहमा एउटा अनुप्रयोगलाई सेटिङ र सर्टकट बदल्न अनुमति दिनुहोस्।"</string>
+ <string name="permdesc_write_settings" msgid="5440712911516509985">"गृहमा एउटा एपलाई सेटिङ र सर्टकट बदल्न अनुमति दिनुहोस्।"</string>
<string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले फोन कलहरू गर्न अनुमति छैन"</string>
<string name="gadget_error_text" msgid="6081085226050792095">"समस्या लोडिङ गर्ने विजेट"</string>
<string name="gadget_setup_text" msgid="8274003207686040488">"सेटअप"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index e548b87..87a1948 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="649227358658669779">"ଲଞ୍ଚର୍3"</string>
- <string name="work_folder_name" msgid="3753320833950115786">"କାମ"</string>
+ <string name="work_folder_name" msgid="3753320833950115786">"ୱାର୍କ"</string>
<string name="activity_not_found" msgid="8071924732094499514">"ଆପ୍ ଇନଷ୍ଟଲ୍ ହୋଇନାହିଁ"</string>
<string name="activity_not_available" msgid="7456344436509528827">"ଆପ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="safemode_shortcut_error" msgid="9160126848219158407">"ନିରାପଦ ମୋଡରେ ଡାଉନଲୋଡ୍ ହେଇଥିବା ଆପ୍ ଅକ୍ଷମ କରାଗଲା"</string>
@@ -131,7 +131,7 @@
<string name="accessibility_close" msgid="2277148124685870734">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="notification_dismissed" msgid="6002233469409822874">"ବିଜ୍ଞପ୍ତି ଖାରଜ କରାଗଲା"</string>
<string name="all_apps_personal_tab" msgid="4190252696685155002">"ବ୍ୟକ୍ତିଗତ"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"କାମ"</string>
+ <string name="all_apps_work_tab" msgid="4884822796154055118">"ୱାର୍କ"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"ୱର୍କ ପ୍ରୋଫାଇଲ୍"</string>
<string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"ବ୍ୟକ୍ତିଗତ ଡାଟା କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପଗୁଡ଼ିକ ଠାରୁ ପୃଥକ୍ ଓ ଲୁକ୍କାୟିତ ଅଟେ"</string>
<string name="work_profile_edu_work_apps" msgid="237051938268703058">"କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପଗୁଡ଼ିକ ଓ ଡାଟା ଆପଣଙ୍କ IT ଆଡମିନଙ୍କୁ ଦେଖାଯାଏ"</string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5f4bd8e..2efa66f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -103,9 +103,9 @@
<!-- Label for install drop target. [CHAR_LIMIT=20] -->
<string name="install_drop_target_label">Install</string>
<!-- Label for install dismiss prediction. -->
- <string translatable="false" name="dismiss_prediction_label">Don\'t suggest app</string>
+ <string name="dismiss_prediction_label">Don\'t suggest app</string>
<!-- Label for pinning predicted app. -->
- <string name="pin_prediction" translatable="false">Pin Prediction</string>
+ <string name="pin_prediction">Pin Prediction</string>
<!-- Permissions: -->
@@ -342,7 +342,7 @@
<!--- heading shown when user opens work apps tab while work apps are paused -->
<string name="work_apps_paused_title">Work profile is paused</string>
<!--- body shown when user opens work apps tab while work apps are paused -->
- <string name="work_apps_paused_body">Work apps can\’t send you notifications, use your battery, or access your location</string>
+ <string name="work_apps_paused_body">Work apps can\'t send you notifications, use your battery, or access your location</string>
<!-- content description for paused work apps list -->
<string name="work_apps_paused_content_description">Work profile is paused. Work apps can\’t send you notifications, use your battery, or access your location</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index d491296..26b7205 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -91,7 +91,7 @@
<item name="android:textColorHint">#A0FFFFFF</item>
<item name="android:colorControlHighlight">#A0FFFFFF</item>
<item name="android:colorPrimary">#FF212121</item>
- <item name="allAppsScrimColor">#FF212121</item>
+ <item name="allAppsScrimColor">#FF000000</item>
<item name="allAppsInterimScrimAlpha">102</item>
<item name="allAppsNavBarScrimColor">#80000000</item>
<item name="popupColorPrimary">#3C4043</item> <!-- Gray 800 -->
@@ -231,9 +231,7 @@
<style name="TextHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle" />
<style name="PrimaryMediumText" parent="@android:style/TextAppearance.DeviceDefault.Medium"/>
- <style name="PrimaryHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle">
- <item name="android:textStyle">bold</item>
- </style>
+ <style name="PrimaryHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle"/>
<style name="TextTitle" parent="@android:style/TextAppearance.DeviceDefault" />
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index 09fe64a..239d8a3 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -16,7 +16,7 @@
package com.android.launcher3;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.APP_LAUNCH_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
import static com.android.launcher3.util.DefaultDisplay.CHANGE_ROTATION;
import android.app.ActivityOptions;
@@ -183,8 +183,7 @@
sourceContainer);
}
getUserEventDispatcher().logAppLaunch(v, intent, user);
-
- getStatsLogManager().log(APP_LAUNCH_TAP, item == null ? null
+ getStatsLogManager().log(LAUNCHER_APP_LAUNCH_TAP, item == null ? null
: item.buildProto(null));
return true;
} catch (NullPointerException|ActivityNotFoundException|SecurityException e) {
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index d7d4a27..79ed2b8 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -722,11 +722,27 @@
}
@Override
- public void getVisualDragBounds(Rect bounds) {
+ public void getWorkspaceVisualDragBounds(Rect bounds) {
DeviceProfile grid = mActivity.getDeviceProfile();
BubbleTextView.getIconBounds(this, bounds, grid.iconSizePx);
}
+ private int getIconSizeForDisplay(int display) {
+ DeviceProfile grid = mActivity.getDeviceProfile();
+ switch (display) {
+ case DISPLAY_ALL_APPS:
+ return grid.allAppsIconSizePx;
+ case DISPLAY_WORKSPACE:
+ case DISPLAY_FOLDER:
+ default:
+ return grid.iconSizePx;
+ }
+ }
+
+ public void getSourceVisualDragBounds(Rect bounds) {
+ BubbleTextView.getIconBounds(this, bounds, getIconSizeForDisplay(mDisplay));
+ }
+
@Override
public void prepareDrawDragView() {
if (getIcon() instanceof FastBitmapDrawable) {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 873b066..59476dd 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -67,7 +67,6 @@
import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
-import android.os.Handler;
import android.os.Parcelable;
import android.os.Process;
import android.os.StrictMode;
@@ -87,13 +86,12 @@
import android.view.animation.OvershootInterpolator;
import android.widget.Toast;
+import androidx.annotation.CallSuper;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.DropTarget.DragObject;
-import com.android.launcher3.LauncherStateManager.AtomicAnimationFactory;
-import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsStore;
@@ -131,6 +129,10 @@
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.qsb.QsbContainerView;
+import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.statemanager.StateManager.StateHandler;
+import com.android.launcher3.statemanager.StateManager.StateListener;
+import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.states.RotationHelper;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol;
@@ -194,7 +196,7 @@
/**
* Default launcher application.
*/
-public class Launcher extends BaseDraggingActivity implements LauncherExterns,
+public class Launcher extends StatefulActivity<LauncherState> implements LauncherExterns,
Callbacks, InvariantDeviceProfile.OnIDPChangeListener, PluginListener<OverlayPlugin> {
public static final String TAG = "Launcher";
@@ -241,7 +243,7 @@
public static final String ON_RESUME_EVT = "Launcher.onResume";
public static final String ON_NEW_INTENT_EVT = "Launcher.onNewIntent";
- private LauncherStateManager mStateManager;
+ private StateManager<LauncherState> mStateManager;
private static final int ON_ACTIVITY_RESULT_ANIMATION_DELAY = 500;
@@ -325,10 +327,6 @@
private RotationHelper mRotationHelper;
- final Handler mHandler = new Handler();
- private final Runnable mHandleDeferredResume = this::handleDeferredResume;
- private boolean mDeferredResumePending;
-
private float mCurrentAssistantVisibility = 0f;
protected LauncherOverlayManager mOverlayManager;
@@ -375,9 +373,9 @@
mDragController = new DragController(this);
mAllAppsController = new AllAppsTransitionController(this);
- mStateManager = new LauncherStateManager(this);
+ mStateManager = new StateManager<>(this, NORMAL);
- mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs, mStateManager);
+ mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs);
mAppWidgetManager = new WidgetManagerHelper(this);
mAppWidgetHost = new LauncherAppWidgetHost(this,
@@ -440,7 +438,7 @@
mRotationHelper.initialize();
- mStateManager.addStateListener(new LauncherStateManager.StateListener() {
+ mStateManager.addStateListener(new StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
@@ -467,9 +465,8 @@
return new LauncherOverlayManager() { };
}
- protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs,
- LauncherStateManager stateManager) {
- return new OnboardingPrefs<>(this, sharedPrefs, stateManager);
+ protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs) {
+ return new OnboardingPrefs<>(this, sharedPrefs);
}
public OnboardingPrefs getOnboardingPrefs() {
@@ -523,13 +520,9 @@
}
@Override
- public void reapplyUi() {
- reapplyUi(true /* cancelCurrentAnimation */);
- }
-
public void reapplyUi(boolean cancelCurrentAnimation) {
getRootView().dispatchInsets();
- getStateManager().reapplyState(cancelCurrentAnimation);
+ super.reapplyUi(cancelCurrentAnimation);
}
@Override
@@ -583,7 +576,8 @@
return mFocusHandler;
}
- public LauncherStateManager getStateManager() {
+ @Override
+ public StateManager<LauncherState> getStateManager() {
return mStateManager;
}
@@ -890,11 +884,7 @@
@Override
protected void onStop() {
- final boolean wasActive = isUserActive();
- final LauncherState origState = getStateManager().getState();
- final int origDragLayerChildCount = mDragLayer.getChildCount();
super.onStop();
-
if (mDeferOverlayCallbacks) {
checkIfOverlayStillDeferred();
} else {
@@ -902,28 +892,8 @@
}
logStopAndResume(Action.Command.STOP);
-
mAppWidgetHost.setListenIfResumed(false);
-
NotificationListener.removeNotificationsChangedListener();
- getStateManager().moveToRestState();
-
- // Workaround for b/78520668, explicitly trim memory once UI is hidden
- onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
-
- if (wasActive) {
- // The expected condition is that this activity is stopped because the device goes to
- // sleep and the UI may have noticeable changes.
- mDragLayer.post(() -> {
- if ((!getStateManager().isInStableState(origState)
- // The drag layer may be animating (e.g. dismissing QSB).
- || mDragLayer.getAlpha() < 1
- // Maybe an ArrowPopup is closed.
- || mDragLayer.getChildCount() != origDragLayerChildCount)) {
- onUiChangedWhileSleeping();
- }
- });
- }
}
@Override
@@ -939,35 +909,27 @@
TraceHelper.INSTANCE.endSection(traceToken);
}
- private void handleDeferredResume() {
- if (hasBeenResumed() && !mStateManager.getState().hasFlag(FLAG_NON_INTERACTIVE)) {
- logStopAndResume(Action.Command.RESUME);
- getUserEventDispatcher().startSession();
+ @Override
+ @CallSuper
+ protected void onDeferredResumed() {
+ logStopAndResume(Action.Command.RESUME);
+ getUserEventDispatcher().startSession();
- AppLaunchTracker.INSTANCE.get(this).onReturnedToHome();
+ AppLaunchTracker.INSTANCE.get(this).onReturnedToHome();
- // Process any items that were added while Launcher was away.
- InstallShortcutReceiver.disableAndFlushInstallQueue(
- InstallShortcutReceiver.FLAG_ACTIVITY_PAUSED, this);
+ // Process any items that were added while Launcher was away.
+ InstallShortcutReceiver.disableAndFlushInstallQueue(
+ InstallShortcutReceiver.FLAG_ACTIVITY_PAUSED, this);
- // Refresh shortcuts if the permission changed.
- mModel.refreshShortcutsIfRequired();
+ // Refresh shortcuts if the permission changed.
+ mModel.refreshShortcutsIfRequired();
- // Set the notification listener and fetch updated notifications when we resume
- NotificationListener.setNotificationsChangedListener(mPopupDataProvider);
+ // Set the notification listener and fetch updated notifications when we resume
+ NotificationListener.setNotificationsChangedListener(mPopupDataProvider);
- DiscoveryBounce.showForHomeIfNeeded(this);
-
- onDeferredResumed();
- addActivityFlags(ACTIVITY_STATE_DEFERRED_RESUMED);
-
- mDeferredResumePending = false;
- } else {
- mDeferredResumePending = true;
- }
+ DiscoveryBounce.showForHomeIfNeeded(this);
}
- protected void onDeferredResumed() { }
private void logStopAndResume(int command) {
int containerType = mStateManager.getState().containerType;
@@ -1016,10 +978,9 @@
return mOverlayManager;
}
+ @Override
public void onStateSetStart(LauncherState state) {
- if (mDeferredResumePending) {
- handleDeferredResume();
- }
+ super.onStateSetStart(state);
if (mDeferOverlayCallbacks) {
scheduleDeferredCheck();
}
@@ -1042,7 +1003,9 @@
mWorkspace.getPageIndicator().setShouldAutoHide(!state.hasFlag(FLAG_MULTI_PAGE));
}
+ @Override
public void onStateSetEnd(LauncherState state) {
+ super.onStateSetStart(state);
getAppWidgetHost().setResumed(state == LauncherState.NORMAL);
getWorkspace().setClipChildren(!state.hasFlag(FLAG_MULTI_PAGE));
@@ -1068,9 +1031,6 @@
TraceHelper.FLAG_UI_EVENT);
super.onResume();
- mHandler.removeCallbacks(mHandleDeferredResume);
- Utilities.postAsyncCallback(mHandler, mHandleDeferredResume);
-
if (!mOnResumeCallbacks.isEmpty()) {
final ArrayList<OnResumeCallback> resumeCallbacks = new ArrayList<>(mOnResumeCallbacks);
mOnResumeCallbacks.clear();
@@ -1113,10 +1073,6 @@
}
}
- public boolean isInState(LauncherState state) {
- return mStateManager.getState() == state;
- }
-
/**
* Restores the previous state, if it exists.
*
@@ -1355,8 +1311,6 @@
}
};
- protected void onUiChangedWhileSleeping() { }
-
private void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
mWorkspace.updateNotificationDots(updatedDots);
mAppsView.getAppsStore().updateNotificationDots(updatedDots);
@@ -2721,17 +2675,10 @@
return super.onKeyUp(keyCode, event);
}
- protected StateHandler[] createStateHandlers() {
+ protected StateHandler<LauncherState>[] createStateHandlers() {
return new StateHandler[] { getAllAppsController(), getWorkspace() };
}
- /**
- * Creates a factory for atomic state animations
- */
- public AtomicAnimationFactory createAtomicAnimationFactory() {
- return new AtomicAnimationFactory(0);
- }
-
public TouchController[] createTouchControllers() {
return new TouchController[] {getDragController(), new AllAppsSwipeController(this)};
}
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 21cd04e..48b97fa 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -20,7 +20,6 @@
import static com.android.launcher3.provider.LauncherDbUtils.copyTable;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import static com.android.launcher3.provider.LauncherDbUtils.tableExists;
-import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.annotation.TargetApi;
import android.app.backup.BackupManager;
@@ -48,7 +47,6 @@
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
-import android.os.Handler;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
@@ -85,6 +83,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
+import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
public class LauncherProvider extends ContentProvider {
@@ -92,8 +91,7 @@
private static final boolean LOGD = false;
private static final String DOWNGRADE_SCHEMA_FILE = "downgrade_schema.json";
- private static final String TOKEN_RESTORE_BACKUP_TABLE = "restore_backup_table";
- private static final long RESTORE_BACKUP_TABLE_DELAY = 60000;
+ private static final long RESTORE_BACKUP_TABLE_DELAY = TimeUnit.SECONDS.toMillis(30);
/**
* Represents the schema of the database. Changes in scheme need not be backwards compatible.
@@ -107,6 +105,8 @@
protected DatabaseHelper mOpenHelper;
+ private long mLastRestoreTimestamp = 0L;
+
/**
* $ adb shell dumpsys activity provider com.android.launcher3
*/
@@ -412,11 +412,12 @@
return null;
}
case LauncherSettings.Settings.METHOD_RESTORE_BACKUP_TABLE: {
- final Handler handler = MODEL_EXECUTOR.getHandler();
- handler.removeCallbacksAndMessages(TOKEN_RESTORE_BACKUP_TABLE);
- handler.postDelayed(() -> RestoreDbTask.restoreIfPossible(
- getContext(), mOpenHelper, new BackupManager(getContext())),
- TOKEN_RESTORE_BACKUP_TABLE, RESTORE_BACKUP_TABLE_DELAY);
+ final long ts = System.currentTimeMillis();
+ if (ts - mLastRestoreTimestamp > RESTORE_BACKUP_TABLE_DELAY) {
+ mLastRestoreTimestamp = ts;
+ RestoreDbTask.restoreIfPossible(
+ getContext(), mOpenHelper, new BackupManager(getContext()));
+ }
return null;
}
case LauncherSettings.Settings.METHOD_UPDATE_CURRENT_OPEN_HELPER: {
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index e133d31..db2a6cd 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -29,6 +29,8 @@
import android.content.Context;
import android.view.animation.Interpolator;
+import com.android.launcher3.statemanager.BaseState;
+import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.states.HintState;
import com.android.launcher3.states.SpringLoadedState;
import com.android.launcher3.uioverrides.states.AllAppsState;
@@ -40,7 +42,7 @@
/**
* Base state for various states used for the Launcher
*/
-public abstract class LauncherState {
+public abstract class LauncherState implements BaseState<LauncherState> {
/**
* Set of elements indicating various workspace elements which change visibility across states
@@ -60,25 +62,22 @@
HOTSEAT_SEARCH_BOX | ALL_APPS_HEADER | ALL_APPS_HEADER_EXTRA | ALL_APPS_CONTENT;
// Flag indicating workspace has multiple pages visible.
- public static final int FLAG_MULTI_PAGE = 1 << 0;
+ public static final int FLAG_MULTI_PAGE = BaseState.getFlag(0);
// Flag indicating that workspace and its contents are not accessible
- public static final int FLAG_WORKSPACE_INACCESSIBLE = 1 << 1;
+ public static final int FLAG_WORKSPACE_INACCESSIBLE = BaseState.getFlag(1);
- public static final int FLAG_DISABLE_RESTORE = 1 << 2;
// Flag indicating the state allows workspace icons to be dragged.
- public static final int FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED = 1 << 3;
+ public static final int FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED = BaseState.getFlag(2);
// Flag to indicate that workspace should draw page background
- public static final int FLAG_WORKSPACE_HAS_BACKGROUNDS = 1 << 4;
- // Flag to indicate that Launcher is non-interactive in this state
- public static final int FLAG_NON_INTERACTIVE = 1 << 5;
+ public static final int FLAG_WORKSPACE_HAS_BACKGROUNDS = BaseState.getFlag(3);
// True if the back button should be hidden when in this state (assuming no floating views are
// open, launcher has window focus, etc).
- public static final int FLAG_HIDE_BACK_BUTTON = 1 << 6;
+ public static final int FLAG_HIDE_BACK_BUTTON = BaseState.getFlag(4);
// Flag to indicate if the state would have scrim over sysui region: statu sbar and nav bar
- public static final int FLAG_HAS_SYS_UI_SCRIM = 1 << 7;
+ public static final int FLAG_HAS_SYS_UI_SCRIM = BaseState.getFlag(5);
// Flag to inticate that all popups should be closed when this state is enabled.
- public static final int FLAG_CLOSE_POPUPS = 1 << 8;
- public static final int FLAG_OVERVIEW_UI = 1 << 9;
+ public static final int FLAG_CLOSE_POPUPS = BaseState.getFlag(6);
+ public static final int FLAG_OVERVIEW_UI = BaseState.getFlag(7);
public static final float NO_OFFSET = 0;
@@ -151,26 +150,15 @@
/**
* Returns if the state has the provided flag
*/
+ @Override
public final boolean hasFlag(int mask) {
return (mFlags & mask) != 0;
}
- /**
- * @return true if the state can be persisted across activity restarts.
- */
- public final boolean shouldDisableRestore() {
- return hasFlag(FLAG_DISABLE_RESTORE);
- }
-
public static LauncherState[] values() {
return Arrays.copyOf(sAllStates, sAllStates.length);
}
- /**
- * @return How long the animation to this state should take (or from this state to NORMAL).
- */
- public abstract int getTransitionDuration(Context context);
-
public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
return new ScaleAndTranslation(NO_SCALE, NO_OFFSET, NO_OFFSET);
}
@@ -264,14 +252,20 @@
};
}
+ @Override
public LauncherState getHistoryForState(LauncherState previousState) {
// No history is supported
return NORMAL;
}
+ @Override
+ public String toString() {
+ return "Ordinal-" + ordinal;
+ }
+
public void onBackPressed(Launcher launcher) {
if (this != NORMAL) {
- LauncherStateManager lsm = launcher.getStateManager();
+ StateManager<LauncherState> lsm = launcher.getStateManager();
LauncherState lastState = lsm.getLastState();
lsm.goToState(lastState);
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 412eef1..286b522 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -89,6 +89,7 @@
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pageindicators.WorkspacePageIndicator;
import com.android.launcher3.popup.PopupContainerWithArrow;
+import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.WorkspaceTouchListener;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
@@ -119,7 +120,7 @@
*/
public class Workspace extends PagedView<WorkspacePageIndicator>
implements DropTarget, DragSource, View.OnTouchListener,
- DragController.DragListener, Insettable, LauncherStateManager.StateHandler,
+ DragController.DragListener, Insettable, StateHandler<LauncherState>,
WorkspaceLayoutManager {
/** The value that {@link #mTransitionProgress} must be greater than for
@@ -1441,6 +1442,10 @@
mOutlineProvider = previewProvider;
+ if (draggableView == null && child instanceof DraggableView) {
+ draggableView = (DraggableView) child;
+ }
+
// The drag bitmap follows the touch point around on the screen
final Bitmap b = previewProvider.createDragBitmap();
int halfPadding = previewProvider.previewPadding / 2;
@@ -1451,12 +1456,8 @@
Point dragVisualizeOffset = null;
Rect dragRect = new Rect();
- if (draggableView == null && child instanceof DraggableView) {
- draggableView = (DraggableView) child;
- }
-
if (draggableView != null) {
- draggableView.getVisualDragBounds(dragRect);
+ draggableView.getSourceVisualDragBounds(dragRect);
dragLayerY += dragRect.top;
dragVisualizeOffset = new Point(- halfPadding, halfPadding);
}
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 29cf803..06a73db 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -66,7 +66,7 @@
}
/**
- * @see com.android.launcher3.LauncherStateManager.StateHandler#setStateWithAnimation
+ * @see com.android.launcher3.statemanager.StateManager.StateHandler#setStateWithAnimation
*/
public void setStateWithAnimation(
LauncherState toState, StateAnimationConfig config, PendingAnimation animation) {
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 21dd141..f057036 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -28,11 +28,11 @@
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
+import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.Themes;
@@ -50,8 +50,8 @@
* If release velocity < THRES1, snap according to either top or bottom depending on whether it's
* closer to top or closer to the page indicator.
*/
-public class AllAppsTransitionController implements StateHandler, OnDeviceProfileChangeListener,
- PluginListener<AllAppsSearchPlugin> {
+public class AllAppsTransitionController implements StateHandler<LauncherState>,
+ OnDeviceProfileChangeListener, PluginListener<AllAppsSearchPlugin> {
public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PROGRESS =
new FloatProperty<AllAppsTransitionController>("allAppsProgress") {
diff --git a/src/com/android/launcher3/allapps/DiscoveryBounce.java b/src/com/android/launcher3/allapps/DiscoveryBounce.java
index 0648682..5397942 100644
--- a/src/com/android/launcher3/allapps/DiscoveryBounce.java
+++ b/src/com/android/launcher3/allapps/DiscoveryBounce.java
@@ -31,9 +31,9 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager.StateListener;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.OnboardingPrefs;
/**
@@ -46,7 +46,7 @@
private final Launcher mLauncher;
private final Animator mDiscoBounceAnimation;
- private final StateListener mStateListener = new StateListener() {
+ private final StateListener<LauncherState> mStateListener = new StateListener<LauncherState>() {
@Override
public void onStateTransitionStart(LauncherState toState) {
handleClose(false);
diff --git a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
index f6766c4..80b6a5a 100644
--- a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
@@ -22,7 +22,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.views.WorkEduView;
/**
@@ -32,7 +32,7 @@
private final Launcher mLauncher;
- private LauncherStateManager.StateListener mWorkTabListener;
+ private StateListener<LauncherState> mWorkTabListener;
public LauncherAllAppsContainerView(Context context) {
this(context, null);
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 970c5a0..ddf44ca 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -274,19 +274,29 @@
scale *= childScale;
int toX = Math.round(coord[0]);
int toY = Math.round(coord[1]);
+
float toScale = scale;
if (child instanceof DraggableView) {
+ // This code is fairly subtle. Please verify drag and drop is pixel-perfect in a number
+ // of scenarios before modifying (from all apps, from workspace, different grid-sizes,
+ // shortcuts from in and out of Launcher etc).
DraggableView d = (DraggableView) child;
- d.getVisualDragBounds(dragViewBounds);
+ Rect destRect = new Rect();
+ d.getWorkspaceVisualDragBounds(destRect);
+
+ // In most cases this additional scale factor should be a no-op (1). It mainly accounts
+ // for alternate grids where the source and destination icon sizes are different
+ toScale *= ((1f * destRect.width())
+ / (dragView.getMeasuredWidth() - dragView.getBlurSizeOutline()));
// This accounts for the offset of the DragView created by scaling it about its
// center as it animates into place.
- float scaleShiftX = dragView.getMeasuredWidth() * (1 - scale) / 2;
- float scaleShiftY = dragView.getMeasuredHeight() * (1 - scale) / 2;
+ float scaleShiftX = dragView.getMeasuredWidth() * (1 - toScale) / 2;
+ float scaleShiftY = dragView.getMeasuredHeight() * (1 - toScale) / 2;
- toX += scale * (dragViewBounds.left - dragView.getBlurSizeOutline() / 2) - scaleShiftX;
- toY += scale * (dragViewBounds.top - dragView.getBlurSizeOutline() / 2) - scaleShiftY;
+ toX += scale * destRect.left - toScale * dragView.getBlurSizeOutline() / 2 - scaleShiftX;
+ toY += scale * destRect.top - toScale * dragView.getBlurSizeOutline() / 2 - scaleShiftY;
}
child.setVisibility(INVISIBLE);
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 1e23bb6..de0fa1a 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -49,18 +49,18 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.Thunk;
import java.util.Arrays;
-public class DragView extends View implements LauncherStateManager.StateListener {
+public class DragView extends View implements StateListener<LauncherState> {
private static final ColorMatrix sTempMatrix1 = new ColorMatrix();
private static final ColorMatrix sTempMatrix2 = new ColorMatrix();
diff --git a/src/com/android/launcher3/dragndrop/DraggableView.java b/src/com/android/launcher3/dragndrop/DraggableView.java
index df99902..287c781 100644
--- a/src/com/android/launcher3/dragndrop/DraggableView.java
+++ b/src/com/android/launcher3/dragndrop/DraggableView.java
@@ -53,5 +53,14 @@
*
* @param bounds Visual bounds in the views coordinates will be written here.
*/
- default void getVisualDragBounds(Rect bounds) { }
+ default void getWorkspaceVisualDragBounds(Rect bounds) { }
+
+ /**
+ * Same as above, but accounts for differing icon sizes between source and destination
+ *
+ * @param bounds Visual bounds in the views coordinates will be written here.
+ */
+ default void getSourceVisualDragBounds(Rect bounds) {
+ getWorkspaceVisualDragBounds(bounds);
+ }
}
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index e2963d7..93208d4 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -53,6 +53,7 @@
import com.android.launcher3.Reorderable;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
+import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dot.FolderDotInfo;
@@ -385,6 +386,14 @@
float finalAlpha = index < MAX_NUM_ITEMS_IN_PREVIEW ? 0.5f : 0f;
float finalScale = scale * scaleRelativeToDragLayer;
+
+ // Account for potentially different icon sizes with non-default grid settings
+ if (d.dragSource instanceof AllAppsContainerView) {
+ DeviceProfile grid = mActivity.getDeviceProfile();
+ float containerScale = (1f * grid.iconSizePx / grid.allAppsIconSizePx);
+ finalScale *= containerScale;
+ }
+
dragLayer.animateView(animateView, from, to, finalAlpha,
1, 1, finalScale, finalScale, DROP_IN_ANIMATION_DURATION,
Interpolators.DEACCEL_2, Interpolators.ACCEL_2,
@@ -758,7 +767,7 @@
}
@Override
- public void getVisualDragBounds(Rect bounds) {
+ public void getWorkspaceVisualDragBounds(Rect bounds) {
getPreviewBounds(bounds);
}
}
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index 848c04a..634d07e 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -77,7 +77,7 @@
if (mView instanceof DraggableView) {
DraggableView dv = (DraggableView) mView;
dv.prepareDrawDragView();
- dv.getVisualDragBounds(mTempRect);
+ dv.getSourceVisualDragBounds(mTempRect);
destCanvas.translate(blurSizeOutline / 2 - mTempRect.left,
blurSizeOutline / 2 - mTempRect.top);
mView.draw(destCanvas);
@@ -95,7 +95,7 @@
// Assume scaleX == scaleY, which is always the case for workspace items.
float scale = mView.getScaleX();
if (mView instanceof DraggableView) {
- ((DraggableView) mView).getVisualDragBounds(mTempRect);
+ ((DraggableView) mView).getSourceVisualDragBounds(mTempRect);
width = mTempRect.width();
height = mTempRect.height();
} else {
diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java
index 0f79bd6..cd4f034 100644
--- a/src/com/android/launcher3/logging/LoggerUtils.java
+++ b/src/com/android/launcher3/logging/LoggerUtils.java
@@ -41,6 +41,7 @@
private static final ArrayMap<Class, SparseArray<String>> sNameCache = new ArrayMap<>();
private static final String UNKNOWN = "UNKNOWN";
private static final int DEFAULT_PREDICTED_RANK = 10000;
+ private static final String DELIMITER_DOT = "\\.";
public static String getFieldName(int value, Class c) {
SparseArray<String> cache;
@@ -173,4 +174,17 @@
targets.toArray(targetsArray);
return newLauncherEvent(action, targetsArray);
}
+
+ /**
+ * String conversion for only the helpful parts of {@link Object#toString()} method
+ * @param stringToExtract "foo.bar.baz.MyObject@1234"
+ * @return "MyObject@1234"
+ */
+ public static String extractObjectNameAndAddress(String stringToExtract) {
+ String[] superStringParts = stringToExtract.split(DELIMITER_DOT);
+ if (superStringParts.length == 0) {
+ return "";
+ }
+ return superStringParts[superStringParts.length - 1];
+ }
}
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index abf027d..fdd32b8 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -16,34 +16,33 @@
package com.android.launcher3.logging;
import android.content.Context;
-import android.util.Log;
import com.android.launcher3.R;
import com.android.launcher3.logger.LauncherAtom;
-import com.android.launcher3.logger.LauncherAtom.ItemInfo;
import com.android.launcher3.logging.StatsLogUtils.LogStateProvider;
import com.android.launcher3.util.ResourceBasedOverride;
/**
* Handles the user event logging in R+.
+ * All of the event id is defined here.
+ * Most of the methods are dummy methods for Launcher3
+ * Actual call happens only for Launcher variant that implements QuickStep.
*/
public class StatsLogManager implements ResourceBasedOverride {
- private static final String TAG = "StatsLogManager";
-
interface EventEnum {
int getId();
}
public enum LauncherEvent implements EventEnum {
@LauncherUiEvent(doc = "App launched from workspace, hotseat or folder in launcher")
- APP_LAUNCH_TAP(1),
+ LAUNCHER_APP_LAUNCH_TAP(338),
@LauncherUiEvent(doc = "Task launched from overview using TAP")
- TASK_LAUNCH_TAP(2),
+ LAUNCHER_TASK_LAUNCH_TAP(339),
@LauncherUiEvent(doc = "Task launched from overview using SWIPE DOWN")
- TASK_LAUNCH_SWIPE_DOWN(2),
+ LAUNCHER_TASK_LAUNCH_SWIPE_DOWN(340),
@LauncherUiEvent(doc = "TASK dismissed from overview using SWIPE UP")
- TASK_DISMISS_SWIPE_UP(3),
+ LAUNCHER_TASK_DISMISS_SWIPE_UP(341),
@LauncherUiEvent(doc = "User dragged a launcher item")
LAUNCHER_ITEM_DRAG_STARTED(383),
@LauncherUiEvent(doc = "A dragged launcher item is successfully dropped")
@@ -75,30 +74,18 @@
StatsLogManager mgr = Overrides.getObject(StatsLogManager.class,
context.getApplicationContext(), R.string.stats_log_manager_class);
mgr.mStateProvider = stateProvider;
- mgr.verify();
return mgr;
}
/**
- * Logs an event and accompanying {@link ItemInfo}
+ * Logs an event and accompanying {@link LauncherAtom.ItemInfo}
*/
- public void log(LauncherEvent event, LauncherAtom.ItemInfo itemInfo) {
- Log.d(TAG, String.format("%s\n%s", event.name(), itemInfo));
- // Call StatsLog method
- }
+ public void log(LauncherEvent event, InstanceId instanceId, LauncherAtom.ItemInfo itemInfo) { }
+ public void log(LauncherEvent event, LauncherAtom.ItemInfo itemInfo) { }
- /**
- * Logs an event and accompanying {@link ItemInfo}
- */
- public void log(LauncherEvent event, InstanceId instanceId, LauncherAtom.ItemInfo itemInfo) {
- Log.d(TAG, String.format("%s(InstanceId:%s)\n%s", event.name(), instanceId, itemInfo));
- // Call StatsLog method
- }
/**
* Logs snapshot, or impression of the current workspace.
*/
public void logSnapshot() { }
-
- public void verify() {} // TODO: should move into robo tests
}
diff --git a/src/com/android/launcher3/logging/StatsLogUtils.java b/src/com/android/launcher3/logging/StatsLogUtils.java
index 97aaf84..10d88e5 100644
--- a/src/com/android/launcher3/logging/StatsLogUtils.java
+++ b/src/com/android/launcher3/logging/StatsLogUtils.java
@@ -1,7 +1,5 @@
package com.android.launcher3.logging;
-import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType.DEFAULT_CONTAINERTYPE;
-
import android.view.View;
import android.view.ViewParent;
@@ -13,6 +11,7 @@
import java.util.ArrayList;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType.DEFAULT_CONTAINERTYPE;
public class StatsLogUtils {
@@ -31,8 +30,6 @@
/**
* Implemented by containers to provide a container source for a given child.
- *
- * Currently,
*/
public interface LogContainerProvider {
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 90aaf44..9e6282e 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -851,20 +851,23 @@
}
private List<AppInfo> loadCachedPredictions() {
- List<ComponentKey> componentKeys = mApp.getPredictionModel().getPredictionComponentKeys();
- List<AppInfo> results = new ArrayList<>();
- if (componentKeys == null) return results;
- List<LauncherActivityInfo> l;
- mBgDataModel.cachedPredictedItems.clear();
- for (ComponentKey key : componentKeys) {
- l = mLauncherApps.getActivityList(key.componentName.getPackageName(), key.user);
- if (l.size() == 0) continue;
- boolean quietMode = mUserManager.isQuietModeEnabled(key.user);
- AppInfo info = new AppInfo(l.get(0), key.user, quietMode);
- mBgDataModel.cachedPredictedItems.add(info);
- mIconCache.getTitleAndIcon(info, false);
+ synchronized (mBgDataModel) {
+ List<ComponentKey> componentKeys =
+ mApp.getPredictionModel().getPredictionComponentKeys();
+ List<AppInfo> results = new ArrayList<>();
+ if (componentKeys == null) return results;
+ List<LauncherActivityInfo> l;
+ mBgDataModel.cachedPredictedItems.clear();
+ for (ComponentKey key : componentKeys) {
+ l = mLauncherApps.getActivityList(key.componentName.getPackageName(), key.user);
+ if (l.size() == 0) continue;
+ boolean quietMode = mUserManager.isQuietModeEnabled(key.user);
+ AppInfo info = new AppInfo(l.get(0), key.user, quietMode);
+ mBgDataModel.cachedPredictedItems.add(info);
+ mIconCache.getTitleAndIcon(info, false);
+ }
+ return results;
}
- return results;
}
private List<LauncherActivityInfo> loadAllApps() {
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index 976d7ba..901d27f 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -56,8 +56,6 @@
// Set<String> of session ids of promise icons that have been added to the home screen
// as FLAG_PROMISE_NEW_INSTALLS.
protected static final String PROMISE_ICON_IDS = "promise_icon_ids";
- public static final String KEY_INSTALL_SESSION_CREATED_TIMESTAMP =
- "key_install_session_created_timestamp";
private static final boolean DEBUG = false;
@@ -166,14 +164,13 @@
}
/**
- * Attempt to restore workspace layout if the session is triggered due to device restore and it
- * has a newer timestamp.
+ * Attempt to restore workspace layout if the session is triggered due to device restore.
*/
public boolean restoreDbIfApplicable(@NonNull final SessionInfo info) {
if (!Utilities.ATLEAST_OREO || !FeatureFlags.ENABLE_DATABASE_RESTORE.get()) {
return false;
}
- if (isRestore(info) && hasNewerTimestamp(mAppContext, info)) {
+ if (isRestore(info)) {
LauncherSettings.Settings.call(mAppContext.getContentResolver(),
LauncherSettings.Settings.METHOD_RESTORE_BACKUP_TABLE);
return true;
@@ -186,13 +183,6 @@
return info.getInstallReason() == PackageManager.INSTALL_REASON_DEVICE_RESTORE;
}
- private static boolean hasNewerTimestamp(
- @NonNull final Context context, @NonNull final SessionInfo info) {
- return PackageManagerHelper.getSessionCreatedTimeInMillis(info)
- > Utilities.getDevicePrefs(context).getLong(
- KEY_INSTALL_SESSION_CREATED_TIMESTAMP, 0);
- }
-
public boolean promiseIconAddedForId(int sessionId) {
return mPromiseIconIds.contains(sessionId);
}
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 33eff57..53183bf 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -16,7 +16,6 @@
package com.android.launcher3.provider;
-import static com.android.launcher3.pm.InstallSessionHelper.KEY_INSTALL_SESSION_CREATED_TIMESTAMP;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import android.app.backup.BackupManager;
@@ -87,13 +86,10 @@
*/
public static boolean restoreIfPossible(@NonNull Context context,
@NonNull DatabaseHelper helper, @NonNull BackupManager backupManager) {
- Utilities.getDevicePrefs(context).edit().putLong(
- KEY_INSTALL_SESSION_CREATED_TIMESTAMP, System.currentTimeMillis()).apply();
final SQLiteDatabase db = helper.getWritableDatabase();
try (SQLiteTransaction t = new SQLiteTransaction(db)) {
RestoreDbTask task = new RestoreDbTask();
task.restoreWorkspace(context, db, helper, backupManager);
- task.restoreAppWidgetIdsIfExists(context);
t.commit();
return true;
} catch (Exception e) {
@@ -107,7 +103,6 @@
*/
private void backupWorkspace(Context context, SQLiteDatabase db) throws Exception {
InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
- // TODO(pinyaoting): Support backing up workspace with multiple grid options.
new GridBackupTable(context, db, idp.numHotseatIcons, idp.numColumns, idp.numRows)
.doBackup(getDefaultProfileId(db), GridBackupTable.OPTION_REQUIRES_SANITIZATION);
}
@@ -115,13 +110,17 @@
private void restoreWorkspace(@NonNull Context context, @NonNull SQLiteDatabase db,
@NonNull DatabaseHelper helper, @NonNull BackupManager backupManager)
throws Exception {
- // TODO(pinyaoting): Support restoring workspace with multiple grid options.
final InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
GridBackupTable backupTable = new GridBackupTable(context, db, idp.numHotseatIcons,
idp.numColumns, idp.numRows);
if (backupTable.restoreFromRawBackupIfAvailable(getDefaultProfileId(db))) {
- sanitizeDB(helper, db, backupManager);
+ int itemsDeleted = sanitizeDB(helper, db, backupManager);
LauncherAppState.getInstance(context).getModel().forceReload();
+ restoreAppWidgetIdsIfExists(context);
+ if (itemsDeleted == 0) {
+ // all the items are restored, we no longer need the backup table
+ dropTable(db, Favorites.BACKUP_TABLE_NAME);
+ }
}
}
@@ -132,8 +131,10 @@
* the restored apps get installed.
* 3. If the user serial for any restored profile is different than that of the previous
* device, update the entries to the new profile id.
+ *
+ * @return number of items deleted.
*/
- private void sanitizeDB(DatabaseHelper helper, SQLiteDatabase db, BackupManager backupManager)
+ private int sanitizeDB(DatabaseHelper helper, SQLiteDatabase db, BackupManager backupManager)
throws Exception {
// Primary user ids
long myProfileId = helper.getDefaultUserSerial();
@@ -210,6 +211,7 @@
if (myProfileId != oldProfileId) {
changeDefaultColumn(db, myProfileId);
}
+ return itemsDeleted;
}
/**
diff --git a/src/com/android/launcher3/statemanager/BaseState.java b/src/com/android/launcher3/statemanager/BaseState.java
new file mode 100644
index 0000000..daec1d8
--- /dev/null
+++ b/src/com/android/launcher3/statemanager/BaseState.java
@@ -0,0 +1,55 @@
+/*
+ * 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.launcher3.statemanager;
+
+import android.content.Context;
+
+/**
+ * Interface representing a state of a StatefulActivity
+ */
+public interface BaseState<T extends BaseState> {
+
+ // Flag to indicate that Launcher is non-interactive in this state
+ int FLAG_NON_INTERACTIVE = 1 << 0;
+ int FLAG_DISABLE_RESTORE = 1 << 1;
+
+ static int getFlag(int index) {
+ // reserve few spots to base flags
+ return 1 << (index + 2);
+ }
+
+ /**
+ * @return How long the animation to this state should take (or from this state to NORMAL).
+ */
+ int getTransitionDuration(Context context);
+
+ /**
+ * Returns the state to go back to from this state
+ */
+ T getHistoryForState(T previousState);
+
+ /**
+ * @return true if the state can be persisted across activity restarts.
+ */
+ default boolean shouldDisableRestore() {
+ return hasFlag(FLAG_DISABLE_RESTORE);
+ }
+
+ /**
+ * Returns if the state has the provided flag
+ */
+ boolean hasFlag(int flagMask);
+}
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
similarity index 76%
rename from src/com/android/launcher3/LauncherStateManager.java
rename to src/com/android/launcher3/statemanager/StateManager.java
index 1aae201..4447166 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -14,9 +14,8 @@
* limitations under the License.
*/
-package com.android.launcher3;
+package com.android.launcher3.statemanager;
-import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
import android.animation.Animator;
@@ -25,94 +24,62 @@
import android.animation.AnimatorSet;
import android.os.Handler;
import android.os.Looper;
+import android.util.Log;
+import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
+import com.android.launcher3.testing.TestProtocol;
import java.io.PrintWriter;
import java.util.ArrayList;
/**
- * TODO: figure out what kind of tests we can write for this
- *
- * Things to test when changing the following class.
- * - Home from workspace
- * - from center screen
- * - from other screens
- * - Home from all apps
- * - from center screen
- * - from other screens
- * - Back from all apps
- * - from center screen
- * - from other screens
- * - Launch app from workspace and quit
- * - with back
- * - with home
- * - Launch app from all apps and quit
- * - with back
- * - with home
- * - Go to a screen that's not the default, then all
- * apps, and launch and app, and go back
- * - with back
- * -with home
- * - On workspace, long press power and go back
- * - with back
- * - with home
- * - On all apps, long press power and go back
- * - with back
- * - with home
- * - On workspace, power off
- * - On all apps, power off
- * - Launch an app and turn off the screen while in that app
- * - Go back with home key
- * - Go back with back key TODO: make this not go to workspace
- * - From all apps
- * - From workspace
- * - Enter and exit car mode (becase it causes an extra configuration changed)
- * - From all apps
- * - From the center workspace
- * - From another workspace
+ * Class to manage transitions between different states for a StatefulActivity based on different
+ * states
*/
-public class LauncherStateManager {
+public class StateManager<STATE_TYPE extends BaseState<STATE_TYPE>> {
public static final String TAG = "StateManager";
private final AnimationState mConfig = new AnimationState();
private final Handler mUiHandler;
- private final Launcher mLauncher;
- private final ArrayList<StateListener> mListeners = new ArrayList<>();
+ private final StatefulActivity<STATE_TYPE> mActivity;
+ private final ArrayList<StateListener<STATE_TYPE>> mListeners = new ArrayList<>();
+ private final STATE_TYPE mBaseState;
// Animators which are run on properties also controlled by state animations.
private final AtomicAnimationFactory mAtomicAnimationFactory;
- private StateHandler[] mStateHandlers;
- private LauncherState mState = NORMAL;
+ private StateHandler<STATE_TYPE>[] mStateHandlers;
+ private STATE_TYPE mState;
- private LauncherState mLastStableState = NORMAL;
- private LauncherState mCurrentStableState = NORMAL;
+ private STATE_TYPE mLastStableState;
+ private STATE_TYPE mCurrentStableState;
- private LauncherState mRestState;
+ private STATE_TYPE mRestState;
- public LauncherStateManager(Launcher l) {
+ public StateManager(StatefulActivity<STATE_TYPE> l, STATE_TYPE baseState) {
mUiHandler = new Handler(Looper.getMainLooper());
- mLauncher = l;
-
+ mActivity = l;
+ mBaseState = baseState;
+ mState = mLastStableState = mCurrentStableState = baseState;
mAtomicAnimationFactory = l.createAtomicAnimationFactory();
}
- public LauncherState getState() {
+ public STATE_TYPE getState() {
return mState;
}
- public LauncherState getCurrentStableState() {
+ public STATE_TYPE getCurrentStableState() {
return mCurrentStableState;
}
public void dump(String prefix, PrintWriter writer) {
- writer.println(prefix + "LauncherState:");
+ writer.println(prefix + "StateManager:");
writer.println(prefix + "\tmLastStableState:" + mLastStableState);
writer.println(prefix + "\tmCurrentStableState:" + mCurrentStableState);
writer.println(prefix + "\tmState:" + mState);
@@ -122,7 +89,7 @@
public StateHandler[] getStateHandlers() {
if (mStateHandlers == null) {
- mStateHandlers = mLauncher.createStateHandlers();
+ mStateHandlers = mActivity.createStateHandlers();
}
return mStateHandlers;
}
@@ -139,29 +106,29 @@
* Returns true if the state changes should be animated.
*/
public boolean shouldAnimateStateChange() {
- return !mLauncher.isForceInvisible() && mLauncher.isStarted();
+ return !mActivity.isForceInvisible() && mActivity.isStarted();
}
/**
* @return {@code true} if the state matches the current state and there is no active
* transition to different state.
*/
- public boolean isInStableState(LauncherState state) {
+ public boolean isInStableState(STATE_TYPE state) {
return mState == state && mCurrentStableState == state
&& (mConfig.targetState == null || mConfig.targetState == state);
}
/**
- * @see #goToState(LauncherState, boolean, Runnable)
+ * @see #goToState(STATE_TYPE, boolean, Runnable)
*/
- public void goToState(LauncherState state) {
+ public void goToState(STATE_TYPE state) {
goToState(state, shouldAnimateStateChange());
}
/**
- * @see #goToState(LauncherState, boolean, Runnable)
+ * @see #goToState(STATE_TYPE, boolean, Runnable)
*/
- public void goToState(LauncherState state, boolean animated) {
+ public void goToState(STATE_TYPE state, boolean animated) {
goToState(state, animated, 0, null);
}
@@ -172,21 +139,21 @@
* true otherwise
* @paras onCompleteRunnable any action to perform at the end of the transition, of null.
*/
- public void goToState(LauncherState state, boolean animated, Runnable onCompleteRunnable) {
+ public void goToState(STATE_TYPE state, boolean animated, Runnable onCompleteRunnable) {
goToState(state, animated, 0, onCompleteRunnable);
}
/**
* Changes the Launcher state to the provided state after the given delay.
*/
- public void goToState(LauncherState state, long delay, Runnable onCompleteRunnable) {
+ public void goToState(STATE_TYPE state, long delay, Runnable onCompleteRunnable) {
goToState(state, true, delay, onCompleteRunnable);
}
/**
* Changes the Launcher state to the provided state after the given delay.
*/
- public void goToState(LauncherState state, long delay) {
+ public void goToState(STATE_TYPE state, long delay) {
goToState(state, true, delay, null);
}
@@ -210,10 +177,10 @@
}
}
- private void goToState(LauncherState state, boolean animated, long delay,
+ private void goToState(STATE_TYPE state, boolean animated, long delay,
final Runnable onCompleteRunnable) {
- animated &= Utilities.areAnimationsEnabled(mLauncher);
- if (mLauncher.isInState(state)) {
+ animated &= Utilities.areAnimationsEnabled(mActivity);
+ if (mActivity.isInState(state)) {
if (mConfig.currentAnimation == null) {
// Run any queued runnable
if (onCompleteRunnable != null) {
@@ -231,7 +198,7 @@
}
// Cancel the current animation. This will reset mState to mCurrentStableState, so store it.
- LauncherState fromState = mState;
+ STATE_TYPE fromState = mState;
mConfig.reset();
if (!animated) {
@@ -264,13 +231,13 @@
}
}
- private void goToStateAnimated(LauncherState state, LauncherState fromState,
+ private void goToStateAnimated(STATE_TYPE state, STATE_TYPE fromState,
Runnable onCompleteRunnable) {
- // Since state NORMAL can be reached from multiple states, just assume that the
+ // Since state mBaseState can be reached from multiple states, just assume that the
// transition plays in reverse and use the same duration as previous state.
- mConfig.duration = state == NORMAL
- ? fromState.getTransitionDuration(mLauncher)
- : state.getTransitionDuration(mLauncher);
+ mConfig.duration = state == mBaseState
+ ? fromState.getTransitionDuration(mActivity)
+ : state.getTransitionDuration(mActivity);
prepareForAtomicAnimation(fromState, state, mConfig);
AnimatorSet animation = createAnimationToNewWorkspaceInternal(state).getAnim();
if (onCompleteRunnable != null) {
@@ -284,7 +251,7 @@
* - Setting interpolators for various animations included in the state transition.
* - Setting some start values (e.g. scale) for views that are hidden but about to be shown.
*/
- public void prepareForAtomicAnimation(LauncherState fromState, LauncherState toState,
+ public void prepareForAtomicAnimation(STATE_TYPE fromState, STATE_TYPE toState,
StateAnimationConfig config) {
mAtomicAnimationFactory.prepareForAtomicAnimation(fromState, toState, config);
}
@@ -293,11 +260,11 @@
* Creates an animation representing atomic transitions between the provided states
*/
public AnimatorSet createAtomicAnimation(
- LauncherState fromState, LauncherState toState, StateAnimationConfig config) {
+ STATE_TYPE fromState, STATE_TYPE toState, StateAnimationConfig config) {
PendingAnimation builder = new PendingAnimation(config.duration);
prepareForAtomicAnimation(fromState, toState, config);
- for (StateHandler handler : mLauncher.getStateManager().getStateHandlers()) {
+ for (StateHandler handler : mActivity.getStateManager().getStateHandlers()) {
handler.setStateWithAnimation(toState, config, builder);
}
return builder.getAnim();
@@ -307,23 +274,23 @@
* Creates a {@link AnimatorPlaybackController} that can be used for a controlled
* state transition.
* @param state the final state for the transition.
- * @param duration intended duration for normal playback. Use higher duration for better
+ * @param duration intended duration for state playback. Use higher duration for better
* accuracy.
*/
public AnimatorPlaybackController createAnimationToNewWorkspace(
- LauncherState state, long duration) {
+ STATE_TYPE state, long duration) {
return createAnimationToNewWorkspace(state, duration, ANIM_ALL_COMPONENTS);
}
public AnimatorPlaybackController createAnimationToNewWorkspace(
- LauncherState state, long duration, @AnimationFlags int animComponents) {
+ STATE_TYPE state, long duration, @AnimationFlags int animComponents) {
StateAnimationConfig config = new StateAnimationConfig();
config.duration = duration;
config.animFlags = animComponents;
return createAnimationToNewWorkspace(state, config);
}
- public AnimatorPlaybackController createAnimationToNewWorkspace(LauncherState state,
+ public AnimatorPlaybackController createAnimationToNewWorkspace(STATE_TYPE state,
StateAnimationConfig config) {
config.userControlled = true;
mConfig.reset();
@@ -333,7 +300,11 @@
return mConfig.playbackController;
}
- private PendingAnimation createAnimationToNewWorkspaceInternal(final LauncherState state) {
+ private PendingAnimation createAnimationToNewWorkspaceInternal(final STATE_TYPE state) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS, "createAnimationToNewWorkspaceInternal: "
+ + state);
+ }
PendingAnimation builder = new PendingAnimation(mConfig.duration);
for (StateHandler handler : getStateHandlers()) {
handler.setStateWithAnimation(state, mConfig, builder);
@@ -348,6 +319,9 @@
@Override
public void onAnimationSuccess(Animator animator) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS, "onAnimationSuccess: " + state);
+ }
onStateTransitionEnd(state);
}
});
@@ -355,24 +329,24 @@
return builder;
}
- private void onStateTransitionStart(LauncherState state) {
+ private void onStateTransitionStart(STATE_TYPE state) {
mState = state;
- mLauncher.onStateSetStart(mState);
+ mActivity.onStateSetStart(mState);
for (int i = mListeners.size() - 1; i >= 0; i--) {
mListeners.get(i).onStateTransitionStart(state);
}
}
- private void onStateTransitionEnd(LauncherState state) {
+ private void onStateTransitionEnd(STATE_TYPE state) {
// Only change the stable states after the transitions have finished
if (state != mCurrentStableState) {
mLastStableState = state.getHistoryForState(mCurrentStableState);
mCurrentStableState = state;
}
- mLauncher.onStateSetEnd(state);
- if (state == NORMAL) {
+ mActivity.onStateSetEnd(state);
+ if (state == mBaseState) {
setRestState(null);
}
@@ -381,7 +355,7 @@
}
}
- public LauncherState getLastState() {
+ public STATE_TYPE getLastState() {
return mLastStableState;
}
@@ -393,15 +367,15 @@
if (mState.shouldDisableRestore()) {
goToState(getRestState());
// Reset history
- mLastStableState = NORMAL;
+ mLastStableState = mBaseState;
}
}
- public LauncherState getRestState() {
- return mRestState == null ? NORMAL : mRestState;
+ public STATE_TYPE getRestState() {
+ return mRestState == null ? mBaseState : mRestState;
}
- public void setRestState(LauncherState restState) {
+ public void setRestState(STATE_TYPE restState) {
mRestState = restState;
}
@@ -496,13 +470,14 @@
}
}
- private static class AnimationState extends StateAnimationConfig implements AnimatorListener {
+ private static class AnimationState<STATE_TYPE> extends StateAnimationConfig
+ implements AnimatorListener {
private static final StateAnimationConfig DEFAULT = new StateAnimationConfig();
public AnimatorPlaybackController playbackController;
public AnimatorSet currentAnimation;
- public LauncherState targetState;
+ public STATE_TYPE targetState;
// Id to keep track of config changes, to tie an animation with the corresponding request
public int changeId = 0;
@@ -537,7 +512,7 @@
}
}
- public void setAnimation(AnimatorSet animation, LauncherState targetState) {
+ public void setAnimation(AnimatorSet animation, STATE_TYPE targetState) {
currentAnimation = animation;
this.targetState = targetState;
currentAnimation.addListener(this);
@@ -553,31 +528,31 @@
public void onAnimationRepeat(Animator animator) { }
}
- public interface StateHandler {
+ public interface StateHandler<STATE_TYPE> {
/**
* Updates the UI to {@param state} without any animations
*/
- void setState(LauncherState state);
+ void setState(STATE_TYPE state);
/**
* Sets the UI to {@param state} by animating any changes.
*/
void setStateWithAnimation(
- LauncherState toState, StateAnimationConfig config, PendingAnimation animation);
+ STATE_TYPE toState, StateAnimationConfig config, PendingAnimation animation);
}
- public interface StateListener {
+ public interface StateListener<STATE_TYPE> {
- default void onStateTransitionStart(LauncherState toState) { }
+ default void onStateTransitionStart(STATE_TYPE toState) { }
- default void onStateTransitionComplete(LauncherState finalState) { }
+ default void onStateTransitionComplete(STATE_TYPE finalState) { }
}
/**
* Factory class to configure and create atomic animations.
*/
- public static class AtomicAnimationFactory {
+ public static class AtomicAnimationFactory<STATE_TYPE> {
private final Animator[] mStateElementAnimators;
@@ -613,6 +588,6 @@
* - Setting some start values (e.g. scale) for views that are hidden but about to be shown.
*/
public void prepareForAtomicAnimation(
- LauncherState fromState, LauncherState toState, StateAnimationConfig config) { }
+ STATE_TYPE fromState, STATE_TYPE toState, StateAnimationConfig config) { }
}
}
diff --git a/src/com/android/launcher3/statemanager/StatefulActivity.java b/src/com/android/launcher3/statemanager/StatefulActivity.java
new file mode 100644
index 0000000..0a1607c
--- /dev/null
+++ b/src/com/android/launcher3/statemanager/StatefulActivity.java
@@ -0,0 +1,149 @@
+/*
+ * 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.launcher3.statemanager;
+
+import static com.android.launcher3.LauncherState.FLAG_NON_INTERACTIVE;
+
+import android.os.Handler;
+
+import androidx.annotation.CallSuper;
+
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
+import com.android.launcher3.statemanager.StateManager.StateHandler;
+import com.android.launcher3.views.BaseDragLayer;
+
+/**
+ * Abstract activity with state management
+ * @param <STATE_TYPE> Type of state object
+ */
+public abstract class StatefulActivity<STATE_TYPE extends BaseState<STATE_TYPE>>
+ extends BaseDraggingActivity {
+
+ public final Handler mHandler = new Handler();
+ private final Runnable mHandleDeferredResume = this::handleDeferredResume;
+ private boolean mDeferredResumePending;
+
+ /**
+ * Create handlers to control the property changes for this activity
+ */
+ protected abstract StateHandler<STATE_TYPE>[] createStateHandlers();
+
+ /**
+ * Returns true if the activity is in the provided state
+ */
+ public boolean isInState(STATE_TYPE state) {
+ return getStateManager().getState() == state;
+ }
+
+ /**
+ * Returns the state manager for this activity
+ */
+ public abstract StateManager<STATE_TYPE> getStateManager();
+
+ /**
+ * Called when transition to the state starts
+ */
+ @CallSuper
+ public void onStateSetStart(STATE_TYPE state) {
+ if (mDeferredResumePending) {
+ handleDeferredResume();
+ }
+ }
+
+ /**
+ * Called when transition to state ends
+ */
+ public void onStateSetEnd(STATE_TYPE state) { }
+
+ /**
+ * Creates a factory for atomic state animations
+ */
+ public AtomicAnimationFactory<STATE_TYPE> createAtomicAnimationFactory() {
+ return new AtomicAnimationFactory(0);
+ }
+
+ @Override
+ public void reapplyUi() {
+ reapplyUi(true /* cancelCurrentAnimation */);
+ }
+
+ /**
+ * Re-applies if any state transition is not running, optionally cancelling
+ * the transition if requested.
+ */
+ public void reapplyUi(boolean cancelCurrentAnimation) {
+ getStateManager().reapplyState(cancelCurrentAnimation);
+ }
+
+ @Override
+ protected void onStop() {
+ BaseDragLayer dragLayer = getDragLayer();
+ final boolean wasActive = isUserActive();
+ final STATE_TYPE origState = getStateManager().getState();
+ final int origDragLayerChildCount = dragLayer.getChildCount();
+ super.onStop();
+
+ getStateManager().moveToRestState();
+
+ // Workaround for b/78520668, explicitly trim memory once UI is hidden
+ onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
+
+ if (wasActive) {
+ // The expected condition is that this activity is stopped because the device goes to
+ // sleep and the UI may have noticeable changes.
+ dragLayer.post(() -> {
+ if ((!getStateManager().isInStableState(origState)
+ // The drag layer may be animating (e.g. dismissing QSB).
+ || dragLayer.getAlpha() < 1
+ // Maybe an ArrowPopup is closed.
+ || dragLayer.getChildCount() != origDragLayerChildCount)) {
+ onUiChangedWhileSleeping();
+ }
+ });
+ }
+ }
+
+ /**
+ * Called if the Activity UI changed while the activity was not visible
+ */
+ protected void onUiChangedWhileSleeping() { }
+
+ private void handleDeferredResume() {
+ if (hasBeenResumed() && !getStateManager().getState().hasFlag(FLAG_NON_INTERACTIVE)) {
+ onDeferredResumed();
+ addActivityFlags(ACTIVITY_STATE_DEFERRED_RESUMED);
+
+ mDeferredResumePending = false;
+ } else {
+ mDeferredResumePending = true;
+ }
+ }
+
+ /**
+ * Called want the activity has stayed resumed for 1 frame.
+ */
+ protected void onDeferredResumed() { }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ mHandler.removeCallbacks(mHandleDeferredResume);
+ Utilities.postAsyncCallback(mHandler, mHandleDeferredResume);
+ }
+}
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index fba6269..0aab495 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -99,4 +99,6 @@
public static final String REQUEST_MOCK_SENSOR_ROTATION = "mock-sensor-rotation";
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
+ public static final String PAUSE_NOT_DETECTED = "b/139891609";
+ public static final String OVERIEW_NOT_ALLAPPS = "b/156095088";
}
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index cbc5257..52e2ab8 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -31,6 +31,7 @@
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.os.SystemClock;
+import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
@@ -43,6 +44,7 @@
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
@@ -162,6 +164,9 @@
@Override
public final boolean onControllerTouchEvent(MotionEvent ev) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "onControllerTouchEvent");
+ }
return mDetector.onTouchEvent(ev);
}
@@ -194,6 +199,10 @@
mFromState = newFromState;
mToState = newToState;
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS, "reinitCurrentAnimation: "
+ + newToState.ordinal);
+ }
mStartProgress = 0;
mPassedOverviewAtomicThreshold = false;
diff --git a/src/com/android/launcher3/touch/BaseSwipeDetector.java b/src/com/android/launcher3/touch/BaseSwipeDetector.java
index 1276ece..01b33d8 100644
--- a/src/com/android/launcher3/touch/BaseSwipeDetector.java
+++ b/src/com/android/launcher3/touch/BaseSwipeDetector.java
@@ -26,6 +26,8 @@
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import com.android.launcher3.testing.TestProtocol;
+
import java.util.LinkedList;
import java.util.Queue;
@@ -173,6 +175,9 @@
if (mState != ScrollState.DRAGGING && shouldScrollStart(mDisplacement)) {
setState(ScrollState.DRAGGING);
}
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "before report dragging");
+ }
if (mState == ScrollState.DRAGGING) {
reportDragging(ev);
}
diff --git a/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java b/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
index d725486..875eefb 100644
--- a/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
+++ b/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
@@ -17,6 +17,7 @@
import android.content.Context;
import android.graphics.PointF;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -24,6 +25,7 @@
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.Utilities;
+import com.android.launcher3.testing.TestProtocol;
/**
* One dimensional scroll/drag/swipe gesture detector (either HORIZONTAL or VERTICAL).
@@ -103,6 +105,11 @@
super(config, isRtl);
mListener = l;
mDir = dir;
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "SingleAxisSwipeDetector.ctor "
+ + l.getClass().getSimpleName()
+ + " @ " + android.util.Log.getStackTraceString(new Throwable()));
+ }
}
public void setDetectableScrollConditions(int scrollDirectionFlags, boolean ignoreSlop) {
@@ -154,6 +161,10 @@
@Override
protected void reportDraggingInternal(PointF displacement, MotionEvent event) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "SingleAxisSwipeDetector "
+ + mListener.getClass().getSimpleName());
+ }
mListener.onDrag(mDir.extractDirection(displacement),
mDir.extractOrthogonalDirection(displacement), event);
}
diff --git a/src/com/android/launcher3/util/LogConfig.java b/src/com/android/launcher3/util/LogConfig.java
index b54074e..528a6e9 100644
--- a/src/com/android/launcher3/util/LogConfig.java
+++ b/src/com/android/launcher3/util/LogConfig.java
@@ -12,6 +12,8 @@
public class LogConfig {
// These are list of strings that can be used to replace TAGNAME.
+ public static final String STATSLOG = "StatsLog";
+
/**
* After this tag is turned on, whenever there is n user event, debug information is
* printed out to logcat.
diff --git a/src/com/android/launcher3/util/OnboardingPrefs.java b/src/com/android/launcher3/util/OnboardingPrefs.java
index baa1eee..1620289 100644
--- a/src/com/android/launcher3/util/OnboardingPrefs.java
+++ b/src/com/android/launcher3/util/OnboardingPrefs.java
@@ -21,7 +21,6 @@
import androidx.annotation.StringDef;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherStateManager;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -71,13 +70,10 @@
protected final T mLauncher;
protected final SharedPreferences mSharedPrefs;
- protected final LauncherStateManager mStateManager;
- public OnboardingPrefs(T launcher, SharedPreferences sharedPrefs,
- LauncherStateManager stateManager) {
+ public OnboardingPrefs(T launcher, SharedPreferences sharedPrefs) {
mLauncher = launcher;
mSharedPrefs = sharedPrefs;
- mStateManager = stateManager;
}
/** @return The number of times we have seen the given event. */
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index da874cf..a2c7d14 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -62,10 +62,10 @@
import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
-import com.android.launcher3.LauncherStateManager.StateListener;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.uioverrides.WallpaperColorInfo;
import com.android.launcher3.uioverrides.WallpaperColorInfo.OnChangeListener;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
@@ -116,7 +116,8 @@
private final AccessibilityManager mAM;
protected final int mEndScrim;
- private final StateListener mAccessibilityLauncherStateListener = new StateListener() {
+ private final StateListener<LauncherState> mAccessibilityLauncherStateListener =
+ new StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
setImportantForAccessibility(finalState == ALL_APPS
@@ -383,7 +384,7 @@
@Override
public void onAccessibilityStateChanged(boolean enabled) {
- LauncherStateManager stateManager = mLauncher.getStateManager();
+ StateManager<LauncherState> stateManager = mLauncher.getStateManager();
stateManager.removeStateListener(mAccessibilityLauncherStateListener);
if (enabled) {
diff --git a/src/com/android/launcher3/views/Snackbar.java b/src/com/android/launcher3/views/Snackbar.java
index dc0e2e0..513ce59 100644
--- a/src/com/android/launcher3/views/Snackbar.java
+++ b/src/com/android/launcher3/views/Snackbar.java
@@ -29,7 +29,7 @@
import android.widget.TextView;
import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Launcher;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -44,7 +44,7 @@
private static final long HIDE_DURATION_MS = 180;
private static final int TIMEOUT_DURATION_MS = 4000;
- private final Launcher mLauncher;
+ private final BaseDraggingActivity mActivity;
private Runnable mOnDismissed;
public Snackbar(Context context, AttributeSet attrs) {
@@ -53,25 +53,25 @@
public Snackbar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mLauncher = Launcher.getLauncher(context);
+ mActivity = BaseDraggingActivity.fromContext(context);
inflate(context, R.layout.snackbar, this);
}
- public static void show(Launcher launcher, int labelStringResId, int actionStringResId,
- Runnable onDismissed, Runnable onActionClicked) {
- closeOpenViews(launcher, true, TYPE_SNACKBAR);
- Snackbar snackbar = new Snackbar(launcher, null);
+ public static void show(BaseDraggingActivity activity, int labelStringResId,
+ int actionStringResId, Runnable onDismissed, Runnable onActionClicked) {
+ closeOpenViews(activity, true, TYPE_SNACKBAR);
+ Snackbar snackbar = new Snackbar(activity, null);
// Set some properties here since inflated xml only contains the children.
snackbar.setOrientation(HORIZONTAL);
snackbar.setGravity(Gravity.CENTER_VERTICAL);
- Resources res = launcher.getResources();
+ Resources res = activity.getResources();
snackbar.setElevation(res.getDimension(R.dimen.snackbar_elevation));
int padding = res.getDimensionPixelSize(R.dimen.snackbar_padding);
snackbar.setPadding(padding, padding, padding, padding);
snackbar.setBackgroundResource(R.drawable.round_rect_primary);
snackbar.mIsOpen = true;
- DragLayer dragLayer = launcher.getDragLayer();
+ BaseDragLayer dragLayer = activity.getDragLayer();
dragLayer.addView(snackbar);
DragLayer.LayoutParams params = (DragLayer.LayoutParams) snackbar.getLayoutParams();
@@ -80,7 +80,7 @@
int maxMarginLeftRight = res.getDimensionPixelSize(R.dimen.snackbar_max_margin_left_right);
int minMarginLeftRight = res.getDimensionPixelSize(R.dimen.snackbar_min_margin_left_right);
int marginBottom = res.getDimensionPixelSize(R.dimen.snackbar_margin_bottom);
- Rect insets = launcher.getDeviceProfile().getInsets();
+ Rect insets = activity.getDeviceProfile().getInsets();
int maxWidth = dragLayer.getWidth() - minMarginLeftRight * 2 - insets.left - insets.right;
int minWidth = dragLayer.getWidth() - maxMarginLeftRight * 2 - insets.left - insets.right;
params.width = minWidth;
@@ -135,7 +135,7 @@
.setDuration(SHOW_DURATION_MS)
.setInterpolator(Interpolators.ACCEL_DEACCEL)
.start();
- int timeout = AccessibilityManagerCompat.getRecommendedTimeoutMillis(launcher,
+ int timeout = AccessibilityManagerCompat.getRecommendedTimeoutMillis(activity,
TIMEOUT_DURATION_MS, FLAG_CONTENT_TEXT | FLAG_CONTENT_CONTROLS);
snackbar.postDelayed(() -> snackbar.close(true), timeout);
}
@@ -160,7 +160,7 @@
}
private void onClosed() {
- mLauncher.getDragLayer().removeView(this);
+ mActivity.getDragLayer().removeView(this);
if (mOnDismissed != null) {
mOnDismissed.run();
}
@@ -179,7 +179,7 @@
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- DragLayer dl = mLauncher.getDragLayer();
+ BaseDragLayer dl = mActivity.getDragLayer();
if (!dl.isEventOverView(this, ev)) {
close(true);
}
diff --git a/src/com/android/launcher3/views/WorkEduView.java b/src/com/android/launcher3/views/WorkEduView.java
index 859b9d0..d35a38f 100644
--- a/src/com/android/launcher3/views/WorkEduView.java
+++ b/src/com/android/launcher3/views/WorkEduView.java
@@ -32,19 +32,19 @@
import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
-import com.android.launcher3.LauncherStateManager.StateListener;
import com.android.launcher3.R;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsPagedView;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.userevent.nano.LauncherLogProto;
/**
* On boarding flow for users right after setting up work profile
*/
-public class WorkEduView extends AbstractSlideInView implements Insettable, StateListener {
+public class WorkEduView extends AbstractSlideInView
+ implements Insettable, StateListener<LauncherState> {
private static final int DEFAULT_CLOSE_DURATION = 200;
public static final String KEY_WORK_EDU_STEP = "showed_work_profile_edu";
@@ -185,8 +185,8 @@
/**
* Checks if user has not seen onboarding UI yet and shows it when user navigates to all apps
*/
- public static LauncherStateManager.StateListener showEduFlowIfNeeded(Launcher launcher,
- @Nullable LauncherStateManager.StateListener oldListener) {
+ public static StateListener<LauncherState> showEduFlowIfNeeded(Launcher launcher,
+ @Nullable StateListener<LauncherState> oldListener) {
if (oldListener != null) {
launcher.getStateManager().removeStateListener(oldListener);
}
@@ -195,7 +195,7 @@
return null;
}
- LauncherStateManager.StateListener listener = new LauncherStateManager.StateListener() {
+ StateListener<LauncherState> listener = new StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
if (finalState != LauncherState.ALL_APPS) return;
diff --git a/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java b/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java
index a4e7daa..ed42bc4 100644
--- a/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java
@@ -218,7 +218,7 @@
}
@Override
- public void getVisualDragBounds(Rect bounds) {
+ public void getWorkspaceVisualDragBounds(Rect bounds) {
int width = (int) (getMeasuredWidth() * mScaleToFit);
int height = (int) (getMeasuredHeight() * mScaleToFit);
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 4a0b4ef..bef91d2 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -55,7 +55,7 @@
private static final int FADE_IN_DURATION_MS = 90;
/** Widget cell width is calculated by multiplying this factor to grid cell width. */
- private static final float WIDTH_SCALE = 2.6f;
+ private static final float WIDTH_SCALE = 3f;
/** Widget preview width is calculated by multiplying this factor to the widget cell width. */
private static final float PREVIEW_SCALE = 0.8f;
@@ -104,7 +104,7 @@
}
private void setContainerWidth() {
- mCellSize = (int) (mDeviceProfile.cellWidthPx * WIDTH_SCALE);
+ mCellSize = (int) (mDeviceProfile.allAppsIconSizePx * WIDTH_SCALE);
mPresetPreviewSize = (int) (mCellSize * PREVIEW_SCALE);
}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 160daef..7cce044 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -37,6 +37,8 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.StrictMode;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
@@ -49,11 +51,11 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.Utilities;
import com.android.launcher3.common.WidgetUtils;
import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.tapl.LauncherInstrumentation.ContainerType;
import com.android.launcher3.tapl.TestHelpers;
@@ -276,6 +278,15 @@
mTargetContext = InstrumentationRegistry.getTargetContext();
mTargetPackage = mTargetContext.getPackageName();
mLauncherPid = mLauncher.getPid();
+
+ UserManager userManager = mTargetContext.getSystemService(UserManager.class);
+ if (userManager != null) {
+ for (UserHandle userHandle : userManager.getUserProfiles()) {
+ if (!userHandle.isSystem()) {
+ mDevice.executeShellCommand("pm remove-user " + userHandle.getIdentifier());
+ }
+ }
+ }
}
@After
@@ -297,6 +308,7 @@
clearPackageData(mDevice.getLauncherPackageName());
mLauncher.enableDebugTracing();
mLauncherPid = mLauncher.getPid();
+ mLauncher.waitForLauncherInitialized();
}
}
@@ -525,7 +537,7 @@
private static void checkLauncherIntegrity(
Launcher launcher, ContainerType expectedContainerType) {
if (launcher != null) {
- final LauncherStateManager stateManager = launcher.getStateManager();
+ final StateManager<LauncherState> stateManager = launcher.getStateManager();
final LauncherState stableState = stateManager.getCurrentStableState();
assertTrue("Stable state != state: " + stableState.getClass().getSimpleName() + ", "
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 240f515..6e9c5a0 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -428,7 +428,7 @@
if (sCheckingEvents) {
sCheckingEvents = false;
if (checkEvents) {
- final String eventMismatch = sEventChecker.verify(0);
+ final String eventMismatch = sEventChecker.verify(0, false);
if (eventMismatch != null) {
message = message + ", having produced " + eventMismatch;
}
@@ -625,6 +625,7 @@
mInstrumentation.getUiAutomation().setOnAccessibilityEventListener(
e -> Log.d("b/155926212", e.toString()));
try (LauncherInstrumentation.Closable e = eventsCheck()) {
+ waitForLauncherInitialized();
// Click home, then wait for any accessibility event, then wait until accessibility
// events stop.
// We need waiting for any accessibility event generated after pressing Home because
@@ -937,9 +938,9 @@
executeAndWaitForEvent(
command,
event -> isSwitchToStateEvent(event, expectedState, actualEvents),
- () -> "Failed to receive an event for the state change: expected "
+ () -> "Failed to receive an event for the state change: expected ["
+ TestProtocol.stateOrdinalToString(expectedState)
- + ", actual: " + eventListToString(actualEvents));
+ + "], actual: " + eventListToString(actualEvents));
}
private boolean isSwitchToStateEvent(
@@ -1310,7 +1311,7 @@
if (sCheckingEvents) {
sCheckingEvents = false;
if (mCheckEventsForSuccessfulGestures) {
- final String message = sEventChecker.verify(WAIT_TIME_MS);
+ final String message = sEventChecker.verify(WAIT_TIME_MS, true);
if (message != null) {
checkForAnomaly();
Assert.fail(formatSystemHealthMessage(
diff --git a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
index 053847c..ac90b1b 100644
--- a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
+++ b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
@@ -85,18 +85,27 @@
}
private void onRun() {
+ while (true) readEvents();
+ }
+
+ private void readEvents() {
try {
// Note that we use Runtime.exec to start the log reading process instead of running
// it via UIAutomation, so that we can directly access the "Process" object and
// ensure that the instrumentation is not stuck forever.
final String cmd = "logcat -s " + TestProtocol.TAPL_EVENTS_TAG;
+ final Process logcatProcess = Runtime.getRuntime().exec(cmd);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(
- Runtime.getRuntime().exec(cmd).getInputStream()))) {
- for (; ; ) {
+ logcatProcess.getInputStream()))) {
+ while (true) {
// Skip everything before the next start command.
for (; ; ) {
final String event = reader.readLine();
+ if (event == null) {
+ Log.d(SKIP_EVENTS_TAG, "Read a null line while waiting for start");
+ return;
+ }
if (event.contains(mStartCommand)) {
Log.d(SKIP_EVENTS_TAG, "Read start: " + event);
break;
@@ -106,6 +115,12 @@
// Store all actual events until the finish command.
for (; ; ) {
final String event = reader.readLine();
+ if (event == null) {
+ Log.d(SKIP_EVENTS_TAG, "Read a null line after waiting for start");
+ mEventsCounter.drainPermits();
+ mEvents.clear();
+ return;
+ }
if (event.contains(mFinishCommand)) {
mFinished.countDown();
Log.d(SKIP_EVENTS_TAG, "Read finish: " + event);
@@ -122,6 +137,8 @@
}
}
}
+ } finally {
+ logcatProcess.destroyForcibly();
}
} catch (IOException e) {
throw new RuntimeException(e);
@@ -151,7 +168,7 @@
Log.d(TestProtocol.TAPL_EVENTS_TAG, mFinishCommand);
}
- String verify(long waitForExpectedCountMs) {
+ String verify(long waitForExpectedCountMs, boolean successfulGesture) {
finishSync(waitForExpectedCountMs);
final StringBuilder sb = new StringBuilder();
@@ -162,7 +179,8 @@
List<String> actual = new ArrayList<>(mEvents.getNonNull(sequence));
Log.d(SKIP_EVENTS_TAG, "Verifying events");
final int mismatchPosition = getMismatchPosition(expectedEvents.getValue(), actual);
- hasMismatches = hasMismatches || mismatchPosition != -1;
+ hasMismatches = hasMismatches
+ || mismatchPosition != -1 && !ignoreMistatch(successfulGesture, sequence);
formatSequenceWithMismatch(
sb,
sequence,
@@ -173,7 +191,8 @@
// Check for unexpected event sequences in the actual data.
for (String actualNamedSequence : mEvents.keySet()) {
if (!mExpectedEvents.containsKey(actualNamedSequence)) {
- hasMismatches = true;
+ hasMismatches = hasMismatches
+ || !ignoreMistatch(successfulGesture, actualNamedSequence);
formatSequenceWithMismatch(
sb,
actualNamedSequence,
@@ -186,6 +205,11 @@
return hasMismatches ? "mismatching events: " + sb.toString() : null;
}
+ // Workaround for b/154157191
+ private static boolean ignoreMistatch(boolean successfulGesture, String sequence) {
+ return TestProtocol.SEQUENCE_TIS.equals(sequence) && successfulGesture;
+ }
+
// If the list of actual events matches the list of expected events, returns -1, otherwise
// the position of the mismatch.
private static int getMismatchPosition(List<Pattern> expected, List<String> actual) {