Merge "Restore hotseat when user turns off suggestions immediately after migration" into ub-launcher3-rvc-dev
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index 5f5fab0..d552daf 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -51,6 +51,7 @@
WidgetsContainer widgets_container = 5;
PredictionContainer prediction_container = 6;
SearchResultContainer search_result_container = 7;
+ ShortcutsContainer shortcuts_container = 8;
}
}
@@ -69,6 +70,11 @@
message SearchResultContainer {
}
+// Container for package specific shortcuts to deep links and notifications.
+// Typically shown as popup window by longpressing on an icon.
+message ShortcutsContainer {
+}
+
enum Origin {
UNKNOWN = 0;
DEFAULT_LAYOUT = 1; // icon automatically placed in workspace, folder, hotseat
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 a487869..79dc3e2 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
@@ -37,6 +37,7 @@
import static com.android.launcher3.anim.Interpolators.clampToProgress;
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_DEPTH;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
@@ -210,6 +211,7 @@
}
config.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
config.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
+ config.setInterpolator(ANIM_DEPTH, OVERSHOOT_1_2);
Interpolator translationInterpolator = ENABLE_OVERVIEW_ACTIONS.get()
&& removeShelfFromOverview(mActivity)
? OVERSHOOT_1_2
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index bf0690c..39bbfb9 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -116,8 +116,7 @@
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED,
"NavBarToHomeTouchController.canInterceptTouch true 2 "
- + AbstractFloatingView.getTopOpenView(mLauncher).getClass()
- .getSimpleName());
+ + AbstractFloatingView.getTopOpenView(mLauncher), new Exception());
}
return true;
}
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 c18a0fd..e5782e7 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
@@ -33,11 +33,11 @@
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.quickstep.util.RemoteAnimationProvider;
+import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.quickstep.util.TaskViewSimulator;
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;
/**
* Provider for the atomic (for 3-button mode) remote window animation from the app to the overview.
@@ -132,8 +132,7 @@
TransformParams params = new TransformParams()
.setTargetSet(targets)
- .setSyncTransactionApplier(
- new SyncRtSurfaceTransactionApplierCompat(mActivity.getRootView()));
+ .setSyncTransactionApplier(new SurfaceTransactionApplier(mActivity.getRootView()));
AnimatedFloat recentsAlpha = new AnimatedFloat(() -> { });
params.setBaseBuilderProxy((builder, app, p)
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 9171422..6cbe794 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
@@ -15,58 +15,39 @@
*/
package com.android.quickstep;
-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;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
-import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
-import android.animation.Animator;
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.Log;
import android.view.MotionEvent;
-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.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
-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.statemanager.StatefulActivity;
import com.android.launcher3.testing.TestProtocol;
-import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.util.WindowBounds;
-import com.android.launcher3.views.FloatingIconView;
import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.RectFSpringAnim;
-import com.android.quickstep.util.TaskViewSimulator;
+import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.quickstep.util.TransformParams;
-import com.android.quickstep.util.TransformParams.BuilderProxy;
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;
@@ -76,40 +57,13 @@
*/
@TargetApi(Build.VERSION_CODES.Q)
public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extends RecentsView>
- implements RecentsAnimationListener {
+ extends SwipeUpAnimationLogic implements RecentsAnimationListener {
private static final String TAG = "BaseSwipeUpHandler";
- protected static final Rect TEMP_RECT = new Rect();
- public static final float MIN_PROGRESS_FOR_OVERVIEW = 0.7f;
- private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL;
-
- // The distance needed to drag to reach the task size in recents.
- protected int mTransitionDragLength;
- // How much further we can drag past recents, as a factor of mTransitionDragLength.
- protected float mDragLengthFactor = 1;
- // Start resisting when swiping past this factor of mTransitionDragLength.
- private float mDragLengthFactorStartPullback = 1f;
- // This is how far down we can scale down, where 0f is full screen and 1f is recents.
- private float mDragLengthFactorMaxPullback = 1f;
-
- protected final Context mContext;
- protected final RecentsAnimationDeviceState mDeviceState;
- protected final GestureState mGestureState;
protected final BaseActivityInterface<?, T> mActivityInterface;
protected final InputConsumerController mInputConsumer;
- protected final TaskViewSimulator mTaskViewSimulator;
- private AnimatorPlaybackController mWindowTransitionController;
-
- protected final TransformParams mTransformParams = new TransformParams();
-
- // Shift in the range of [0, 1].
- // 0 => preview snapShot is completely visible, and hotseat is completely translated down
- // 1 => preview snapShot is completely aligned with the recents view and hotseat is completely
- // visible.
- protected final AnimatedFloat mCurrentShift = new AnimatedFloat(this::updateFinalShift);
-
protected final ActivityInitListener mActivityInitListener;
protected RecentsAnimationController mRecentsAnimationController;
@@ -120,7 +74,6 @@
protected T mActivity;
protected Q mRecentsView;
- protected DeviceProfile mDp;
protected Runnable mGestureEndCallback;
@@ -132,13 +85,10 @@
protected BaseSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState,
GestureState gestureState, InputConsumerController inputConsumer) {
- mContext = context;
- mDeviceState = deviceState;
- mGestureState = gestureState;
+ super(context, deviceState, gestureState, new TransformParams());
mActivityInterface = gestureState.getActivityInterface();
mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit);
mInputConsumer = inputConsumer;
- mTaskViewSimulator = new TaskViewSimulator(context, gestureState.getActivityInterface());
}
/**
@@ -158,28 +108,6 @@
return mRecentsView != null ? mRecentsView.getEventDispatcher(navbarRotation) : null;
}
- @UiThread
- public void updateDisplacement(float displacement) {
- // We are moving in the negative x/y direction
- displacement = -displacement;
- float shift;
- if (displacement > mTransitionDragLength * mDragLengthFactor && mTransitionDragLength > 0) {
- shift = mDragLengthFactor;
- } else {
- float translation = Math.max(displacement, 0);
- shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength;
- if (shift > mDragLengthFactorStartPullback) {
- float pullbackProgress = Utilities.getProgress(shift,
- mDragLengthFactorStartPullback, mDragLengthFactor);
- pullbackProgress = PULLBACK_INTERPOLATOR.getInterpolation(pullbackProgress);
- shift = mDragLengthFactorStartPullback + pullbackProgress
- * (mDragLengthFactorMaxPullback - mDragLengthFactorStartPullback);
- }
- }
-
- mCurrentShift.updateValue(shift);
- }
-
public void setGestureEndCallback(Runnable gestureEndCallback) {
mGestureEndCallback = gestureEndCallback;
}
@@ -187,10 +115,10 @@
public abstract Intent getLaunchIntent();
protected void linkRecentsViewScroll() {
- SyncRtSurfaceTransactionApplierCompat.create(mRecentsView, applier -> {
+ SurfaceTransactionApplier.create(mRecentsView, applier -> {
mTransformParams.setSyncTransactionApplier(applier);
runOnRecentsAnimationStart(() ->
- mRecentsAnimationTargets.addDependentTransactionApplier(applier));
+ mRecentsAnimationTargets.addReleaseCheck(applier));
});
mRecentsView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
@@ -276,6 +204,7 @@
RecentsAnimationTargets targets) {
mRecentsAnimationController = recentsAnimationController;
mRecentsAnimationTargets = targets;
+ mTransformParams.setTargetSet(mRecentsAnimationTargets);
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext).getDeviceProfile(mContext);
RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(
mGestureState.getRunningTaskId());
@@ -357,35 +286,6 @@
return mGestureState.getLastStartedTaskId() != -1;
}
- protected void initTransitionEndpoints(DeviceProfile dp) {
- mDp = dp;
-
- mTaskViewSimulator.setDp(dp);
- mTaskViewSimulator.setLayoutRotation(
- mDeviceState.getCurrentActiveRotation(),
- mDeviceState.getDisplayRotation());
- mTransitionDragLength = mActivityInterface.getSwipeUpDestinationAndLength(
- dp, mContext, TEMP_RECT,
- mTaskViewSimulator.getOrientationState().getOrientationHandler());
-
- if (mDeviceState.isFullyGesturalNavMode()) {
- // We can drag all the way to the top of the screen.
- mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength;
-
- float startScale = mTaskViewSimulator.getFullScreenScale();
- // Start pulling back when RecentsView scale is 0.75f, and let it go down to 0.5f.
- mDragLengthFactorStartPullback = (0.75f - startScale) / (1 - startScale);
- mDragLengthFactorMaxPullback = (0.5f - startScale) / (1 - startScale);
- } else {
- mDragLengthFactor = 1;
- mDragLengthFactorStartPullback = mDragLengthFactorMaxPullback = 1;
- }
-
- PendingAnimation pa = new PendingAnimation(mTransitionDragLength * 2);
- mTaskViewSimulator.addAppToOverviewAnim(pa, t -> t * mDragLengthFactor);
- mWindowTransitionController = pa.createPlaybackController();
- }
-
/**
* Return true if the window should be translated horizontally if the recents view scrolls
*/
@@ -457,8 +357,8 @@
if (mWindowTransitionController != null) {
float progress = mCurrentShift.value / mDragLengthFactor;
mWindowTransitionController.setPlayFraction(progress);
- mTransformParams.setTargetSet(mRecentsAnimationTargets);
-
+ }
+ if (mRecentsAnimationTargets != null) {
if (mRecentsViewScrollLinked) {
mTaskViewSimulator.setScroll(mRecentsView.getScrollOffset());
}
@@ -466,49 +366,14 @@
}
}
- protected PagedOrientationHandler getOrientationHandler() {
- return mTaskViewSimulator.getOrientationState().getOrientationHandler();
- }
-
- /**
- * 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.
- * @param homeAnimationFactory The home animation factory.
- */
+ @Override
protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
HomeAnimationFactory homeAnimationFactory) {
- final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
- 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) {
- anim.addAnimatorListener(fiv);
- fiv.setOnTargetChangeListener(anim::onTargetPositionChanged);
- fiv.setFastFinishRunnable(anim::end);
+ RectFSpringAnim anim =
+ super.createWindowAnimationToHome(startProgress, homeAnimationFactory);
+ if (mRecentsAnimationTargets != null) {
+ mRecentsAnimationTargets.addReleaseCheck(anim);
}
-
- SpringAnimationRunner runner = new SpringAnimationRunner(
- homeAnimationFactory, cropRectF, homeToWindowPositionMap);
- anim.addOnUpdateListener(runner);
- anim.addAnimatorListener(runner);
return anim;
}
@@ -517,166 +382,4 @@
BaseSwipeUpHandler newHandler(
GestureState gestureState, long touchTimeMs, boolean continuingLastGesture);
}
-
- protected interface RunningWindowAnim {
- void end();
-
- void cancel();
-
- static RunningWindowAnim wrap(Animator animator) {
- return new RunningWindowAnim() {
- @Override
- public void end() {
- animator.end();
- }
-
- @Override
- public void cancel() {
- animator.cancel();
- }
- };
- }
-
- static RunningWindowAnim wrap(RectFSpringAnim rectFSpringAnim) {
- return new RunningWindowAnim() {
- @Override
- public void end() {
- rectFSpringAnim.end();
- }
-
- @Override
- public void cancel() {
- rectFSpringAnim.cancel();
- }
- };
- }
- }
-
- /**
- * @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 onBuildTargetParams(
- Builder builder, RemoteAnimationTargetCompat app, TransformParams params) {
- 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/BaseSwipeUpHandlerV2.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
index 46799ff..92e10b1 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
@@ -29,6 +29,7 @@
import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK;
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_END_TARGET_SET;
import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
@@ -253,6 +254,10 @@
mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED | STATE_RESUME_LAST_TASK,
this::notifyTransitionCancelled);
+ mGestureState.runOnceAtState(STATE_END_TARGET_SET,
+ () -> mDeviceState.onEndTargetCalculated(mGestureState.getEndTarget(),
+ mActivityInterface));
+
if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) {
mStateCallback.addChangeListener(STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_PRESENT
| STATE_SCREENSHOT_VIEW_SHOWN | STATE_CAPTURE_SCREENSHOT,
@@ -1035,7 +1040,7 @@
}
// Make sure recents is in its final state
maybeUpdateRecentsAttachedState(false);
- mActivityInterface.onSwipeUpToHomeComplete();
+ mActivityInterface.onSwipeUpToHomeComplete(mDeviceState);
}
});
return anim;
@@ -1232,7 +1237,6 @@
}
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true);
doLogGesture(HOME);
- mDeviceState.enableMultipleRegions(false);
}
protected abstract void finishRecentsControllerToHome(Runnable callback);
@@ -1248,7 +1252,6 @@
SystemUiProxy.INSTANCE.get(mContext).onOverviewShown(false, TAG);
doLogGesture(RECENTS);
- mDeviceState.onSwipeUpToOverview(mActivityInterface);
reset();
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
index c9ff884..70be3ab 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
@@ -69,7 +69,7 @@
/** 4 */
@Override
- public void onSwipeUpToHomeComplete() {
+ public void onSwipeUpToHomeComplete(RecentsAnimationDeviceState deviceState) {
onSwipeUpToRecentsComplete();
}
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 13b84e0..62eb235 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
@@ -96,7 +96,7 @@
}
@Override
- public void onSwipeUpToHomeComplete() {
+ public void onSwipeUpToHomeComplete(RecentsAnimationDeviceState deviceState) {
Launcher launcher = getCreatedActivity();
if (launcher == null) {
return;
@@ -105,6 +105,7 @@
// recents, we assume the first task is invisible, making translation off by one task.
launcher.getStateManager().reapplyState();
launcher.getRootView().setForceHideBackArrow(false);
+ notifyRecentsOfOrientation(deviceState);
}
@Override
@@ -235,17 +236,20 @@
// Are we going from Recents to Workspace?
if (toState == LauncherState.NORMAL) {
exitRunnable.run();
-
- // reset layout on swipe to home
- RecentsView recentsView = getCreatedActivity().getOverviewPanel();
- recentsView.setLayoutRotation(deviceState.getCurrentActiveRotation(),
- deviceState.getDisplayRotation());
+ notifyRecentsOfOrientation(deviceState);
stateManager.removeStateListener(this);
}
}
});
}
+ private void notifyRecentsOfOrientation(RecentsAnimationDeviceState deviceState) {
+ // reset layout on swipe to home
+ RecentsView recentsView = getCreatedActivity().getOverviewPanel();
+ recentsView.setLayoutRotation(deviceState.getCurrentActiveRotation(),
+ deviceState.getDisplayRotation());
+ }
+
@Override
public Rect getOverviewWindowBounds(Rect homeBounds, RemoteAnimationTargetCompat target) {
return homeBounds;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 0d49b2b..a28dabc 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -79,12 +79,13 @@
@Override
protected Activity getCurrentActivity() {
- OverviewComponentObserver observer = new OverviewComponentObserver(mContext,
- new RecentsAnimationDeviceState(mContext));
+ RecentsAnimationDeviceState rads = new RecentsAnimationDeviceState(mContext);
+ OverviewComponentObserver observer = new OverviewComponentObserver(mContext, rads);
try {
return observer.getActivityInterface().getCreatedActivity();
} finally {
observer.onDestroy();
+ rads.destroy();
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java
new file mode 100644
index 0000000..b17730b
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -0,0 +1,350 @@
+/*
+ * 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.anim.Interpolators.ACCEL_1_5;
+import static com.android.launcher3.anim.Interpolators.DEACCEL;
+import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
+
+import android.animation.Animator;
+import android.content.Context;
+import android.graphics.Matrix;
+import android.graphics.Matrix.ScaleToFit;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.view.animation.Interpolator;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.UiThread;
+
+import com.android.launcher3.DeviceProfile;
+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.touch.PagedOrientationHandler;
+import com.android.launcher3.views.FloatingIconView;
+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.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder;
+
+public abstract class SwipeUpAnimationLogic {
+
+ protected static final Rect TEMP_RECT = new Rect();
+ private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL;
+
+ protected DeviceProfile mDp;
+
+ protected final Context mContext;
+ protected final RecentsAnimationDeviceState mDeviceState;
+ protected final GestureState mGestureState;
+ protected final TaskViewSimulator mTaskViewSimulator;
+
+ protected final TransformParams mTransformParams;
+
+ // Shift in the range of [0, 1].
+ // 0 => preview snapShot is completely visible, and hotseat is completely translated down
+ // 1 => preview snapShot is completely aligned with the recents view and hotseat is completely
+ // visible.
+ protected final AnimatedFloat mCurrentShift = new AnimatedFloat(this::updateFinalShift);
+
+ // The distance needed to drag to reach the task size in recents.
+ protected int mTransitionDragLength;
+ // How much further we can drag past recents, as a factor of mTransitionDragLength.
+ protected float mDragLengthFactor = 1;
+ // Start resisting when swiping past this factor of mTransitionDragLength.
+ private float mDragLengthFactorStartPullback = 1f;
+ // This is how far down we can scale down, where 0f is full screen and 1f is recents.
+ private float mDragLengthFactorMaxPullback = 1f;
+
+ protected AnimatorPlaybackController mWindowTransitionController;
+
+ public SwipeUpAnimationLogic(Context context, RecentsAnimationDeviceState deviceState,
+ GestureState gestureState, TransformParams transformParams) {
+ mContext = context;
+ mDeviceState = deviceState;
+ mGestureState = gestureState;
+ mTaskViewSimulator = new TaskViewSimulator(context, gestureState.getActivityInterface());
+ mTransformParams = transformParams;
+ }
+
+ protected void initTransitionEndpoints(DeviceProfile dp) {
+ mDp = dp;
+
+ mTaskViewSimulator.setDp(dp);
+ mTaskViewSimulator.setLayoutRotation(
+ mDeviceState.getCurrentActiveRotation(),
+ mDeviceState.getDisplayRotation());
+ mTransitionDragLength = mGestureState.getActivityInterface().getSwipeUpDestinationAndLength(
+ dp, mContext, TEMP_RECT,
+ mTaskViewSimulator.getOrientationState().getOrientationHandler());
+
+ if (mDeviceState.isFullyGesturalNavMode()) {
+ // We can drag all the way to the top of the screen.
+ mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength;
+
+ float startScale = mTaskViewSimulator.getFullScreenScale();
+ // Start pulling back when RecentsView scale is 0.75f, and let it go down to 0.5f.
+ mDragLengthFactorStartPullback = (0.75f - startScale) / (1 - startScale);
+ mDragLengthFactorMaxPullback = (0.5f - startScale) / (1 - startScale);
+ } else {
+ mDragLengthFactor = 1;
+ mDragLengthFactorStartPullback = mDragLengthFactorMaxPullback = 1;
+ }
+
+ PendingAnimation pa = new PendingAnimation(mTransitionDragLength * 2);
+ mTaskViewSimulator.addAppToOverviewAnim(pa, t -> t * mDragLengthFactor);
+ mWindowTransitionController = pa.createPlaybackController();
+ }
+
+ @UiThread
+ public void updateDisplacement(float displacement) {
+ // We are moving in the negative x/y direction
+ displacement = -displacement;
+ float shift;
+ if (displacement > mTransitionDragLength * mDragLengthFactor && mTransitionDragLength > 0) {
+ shift = mDragLengthFactor;
+ } else {
+ float translation = Math.max(displacement, 0);
+ shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength;
+ if (shift > mDragLengthFactorStartPullback) {
+ float pullbackProgress = Utilities.getProgress(shift,
+ mDragLengthFactorStartPullback, mDragLengthFactor);
+ pullbackProgress = PULLBACK_INTERPOLATOR.getInterpolation(pullbackProgress);
+ shift = mDragLengthFactorStartPullback + pullbackProgress
+ * (mDragLengthFactorMaxPullback - mDragLengthFactorStartPullback);
+ }
+ }
+
+ mCurrentShift.updateValue(shift);
+ }
+
+ /**
+ * Called when the value of {@link #mCurrentShift} changes
+ */
+ @UiThread
+ public abstract void updateFinalShift();
+
+ protected PagedOrientationHandler getOrientationHandler() {
+ return mTaskViewSimulator.getOrientationState().getOrientationHandler();
+ }
+
+ protected abstract class HomeAnimationFactory {
+
+ public 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
+ }
+ }
+
+ /**
+ * 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.
+ * @param homeAnimationFactory The home animation factory.
+ */
+ protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
+ HomeAnimationFactory homeAnimationFactory) {
+ final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
+ final FloatingIconView fiv = homeAnimationFactory.mIconView;
+ final boolean isFloatingIconView = fiv != null;
+
+ mWindowTransitionController.setPlayFraction(startProgress / mDragLengthFactor);
+ mTaskViewSimulator.apply(mTransformParams.setProgress(startProgress));
+ 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) {
+ anim.addAnimatorListener(fiv);
+ fiv.setOnTargetChangeListener(anim::onTargetPositionChanged);
+ fiv.setFastFinishRunnable(anim::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);
+ }
+
+ protected 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 onBuildTargetParams(
+ Builder builder, RemoteAnimationTargetCompat app, TransformParams params) {
+ 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();
+ }
+ }
+
+ public interface RunningWindowAnim {
+ void end();
+
+ void cancel();
+
+ static RunningWindowAnim wrap(Animator animator) {
+ return new RunningWindowAnim() {
+ @Override
+ public void end() {
+ animator.end();
+ }
+
+ @Override
+ public void cancel() {
+ animator.cancel();
+ }
+ };
+ }
+
+ static RunningWindowAnim wrap(RectFSpringAnim rectFSpringAnim) {
+ return new RunningWindowAnim() {
+ @Override
+ public void end() {
+ rectFSpringAnim.end();
+ }
+
+ @Override
+ public void cancel() {
+ rectFSpringAnim.cancel();
+ }
+ };
+ }
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java
index 021d39d..cdaa655 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java
@@ -18,6 +18,8 @@
import static android.view.Display.DEFAULT_DISPLAY;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_SPLIT_SCREEN_TAP;
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP;
import android.app.Activity;
@@ -35,6 +37,7 @@
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
import com.android.launcher3.model.WellbeingModel;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.SystemShortcut;
@@ -83,10 +86,12 @@
private final int mIconRes;
private final int mTextRes;
+ private final LauncherEvent mLauncherEvent;
- MultiWindowFactory(int iconRes, int textRes) {
+ MultiWindowFactory(int iconRes, int textRes, LauncherEvent launcherEvent) {
mIconRes = iconRes;
mTextRes = textRes;
+ mLauncherEvent = launcherEvent;
}
protected abstract boolean isAvailable(BaseDraggingActivity activity, int displayId);
@@ -102,7 +107,8 @@
if (!isAvailable(activity, task.key.displayId)) {
return null;
}
- return new MultiWindowSystemShortcut(mIconRes, mTextRes, activity, taskView, this);
+ return new MultiWindowSystemShortcut(mIconRes, mTextRes, activity, taskView, this,
+ mLauncherEvent);
}
}
@@ -114,11 +120,12 @@
private final TaskThumbnailView mThumbnailView;
private final TaskView mTaskView;
private final MultiWindowFactory mFactory;
+ private final LauncherEvent mLauncherEvent;
- public MultiWindowSystemShortcut(int iconRes, int textRes,
- BaseDraggingActivity activity, TaskView taskView, MultiWindowFactory factory) {
+ public MultiWindowSystemShortcut(int iconRes, int textRes, BaseDraggingActivity activity,
+ TaskView taskView, MultiWindowFactory factory, LauncherEvent launcherEvent) {
super(iconRes, textRes, activity, dummyInfo(taskView));
-
+ mLauncherEvent = launcherEvent;
mHandler = new Handler(Looper.getMainLooper());
mTaskView = taskView;
mRecentsView = activity.getOverviewPanel();
@@ -203,12 +210,13 @@
WindowManagerWrapper.getInstance().overridePendingAppTransitionMultiThumbFuture(
future, animStartedListener, mHandler, true /* scaleUp */,
taskKey.displayId);
+ mTarget.getStatsLogManager().log(mLauncherEvent, mTaskView.buildProto());
}
}
}
- TaskShortcutFactory SPLIT_SCREEN = new MultiWindowFactory(
- R.drawable.ic_split_screen, R.string.recent_task_option_split_screen) {
+ TaskShortcutFactory SPLIT_SCREEN = new MultiWindowFactory(R.drawable.ic_split_screen,
+ R.string.recent_task_option_split_screen, LAUNCHER_SYSTEM_SHORTCUT_SPLIT_SCREEN_TAP) {
@Override
protected boolean isAvailable(BaseDraggingActivity activity, int displayId) {
@@ -241,8 +249,8 @@
}
};
- TaskShortcutFactory FREE_FORM = new MultiWindowFactory(
- R.drawable.ic_split_screen, R.string.recent_task_option_freeform) {
+ TaskShortcutFactory FREE_FORM = new MultiWindowFactory(R.drawable.ic_split_screen,
+ R.string.recent_task_option_freeform, LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP) {
@Override
protected boolean isAvailable(BaseDraggingActivity activity, int displayId) {
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 c68d6e2..e2e25f3 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java
@@ -42,6 +42,7 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.util.DefaultDisplay;
+import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.views.RecentsView;
@@ -49,7 +50,6 @@
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
/**
* Utility class for helpful methods related to {@link TaskView} objects and their tasks.
@@ -128,11 +128,10 @@
RemoteAnimationTargetCompat[] wallpaperTargets, DepthController depthController,
PendingAnimation out) {
- SyncRtSurfaceTransactionApplierCompat applier =
- new SyncRtSurfaceTransactionApplierCompat(v);
+ SurfaceTransactionApplier applier = new SurfaceTransactionApplier(v);
final RemoteAnimationTargets targets =
new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_OPENING);
- targets.addDependentTransactionApplier(applier);
+ targets.addReleaseCheck(applier);
TransformParams params = new TransformParams()
.setSyncTransactionApplier(applier)
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 4954588..ac76968 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -81,6 +81,7 @@
import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer;
import com.android.quickstep.inputconsumers.ResetGestureInputConsumer;
import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
+import com.android.quickstep.inputconsumers.SysUiOverlayInputConsumer;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.AssistantUtilities;
import com.android.quickstep.util.ProtoTracer;
@@ -133,10 +134,10 @@
private static final int MAX_BACK_NOTIFICATION_COUNT = 3;
/**
- * System Action ID to show all apps. This ID should follow the ones in
- * com.android.systemui.accessibility.SystemActions.
+ * System Action ID to show all apps.
+ * TODO: Use AccessibilityService's corresponding global action constant in S
*/
- private static final int SYSTEM_ACTION_ID_ALL_APPS = 100;
+ private static final int SYSTEM_ACTION_ID_ALL_APPS = 14;
private int mBackGestureNotificationCounter = -1;
@Nullable
@@ -466,10 +467,17 @@
final int action = event.getAction();
if (action == ACTION_DOWN) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_SWIPE_TO_HOME, "TouchInteractionService.onInputEvent:DOWN");
+ }
mDeviceState.setOrientationTransformIfNeeded(event);
GestureState newGestureState;
if (mDeviceState.isInSwipeUpTouchRegion(event)) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_SWIPE_TO_HOME,
+ "TouchInteractionService.onInputEvent:isInSwipeUpTouchRegion");
+ }
// Clone the previous gesture state since onConsumerAboutToBeSwitched might trigger
// onConsumerInactive and wipe the previous gesture state
GestureState prevGestureState = new GestureState(mGestureState);
@@ -536,6 +544,9 @@
private InputConsumer newConsumer(GestureState previousGestureState,
GestureState newGestureState, MotionEvent event) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_SWIPE_TO_HOME, "newConsumer");
+ }
boolean canStartSystemGesture = mDeviceState.canStartSystemGesture();
if (!mDeviceState.isUserUnlocked()) {
@@ -547,6 +558,9 @@
return mResetGestureInputConsumer;
}
}
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_SWIPE_TO_HOME, "newConsumer:user is unlocked");
+ }
// When there is an existing recents animation running, bypass systemState check as this is
// a followup gesture and the first gesture started in a valid system state.
@@ -588,6 +602,13 @@
}
}
+ // If Bubbles is expanded, use the overlay input consumer, which will close Bubbles
+ // instead of going all the way home when a swipe up is detected.
+ if (mDeviceState.isBubblesExpanded()) {
+ base = new SysUiOverlayInputConsumer(
+ getBaseContext(), mDeviceState, mInputMonitorCompat);
+ }
+
if (mDeviceState.isScreenPinningActive()) {
// Note: we only allow accessibility to wrap this, and it replaces the previous
// base input consumer (which should be NO_OP anyway since topTaskLocked == true).
@@ -613,7 +634,7 @@
if (!isFixedRotationTransformEnabled()) {
return;
}
- mDeviceState.enableMultipleRegions(baseInputConsumer instanceof OtherActivityInputConsumer);
+ baseInputConsumer.notifyOrientationSetup();
}
private InputConsumer newBaseConsumer(GestureState previousGestureState,
@@ -725,12 +746,13 @@
if (!mDeviceState.isUserUnlocked()) {
return;
}
+
if (mDeviceState.isButtonNavMode() && !mOverviewComponentObserver.isHomeAndOverviewSame()) {
// Prevent the overview from being started before the real home on first boot.
return;
}
- if (RestoreDbTask.isPending(this)) {
+ if (RestoreDbTask.isPending(this) || !mDeviceState.isUserSetupComplete()) {
// Preloading while a restore is pending may cause launcher to start the restore
// too early.
return;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
index 6f919c1..be3fdde 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
@@ -15,6 +15,7 @@
*/
package com.android.quickstep.fallback;
+import android.graphics.PointF;
import android.view.MotionEvent;
import androidx.annotation.Nullable;
@@ -30,7 +31,8 @@
/**
* In 0-button mode, intercepts swipe up from the nav bar on FallbackRecentsView to go home.
*/
-public class FallbackNavBarTouchController implements TouchController {
+public class FallbackNavBarTouchController implements TouchController,
+ TriggerSwipeUpTouchTracker.OnSwipeUpListener {
private final RecentsActivity mActivity;
@Nullable
@@ -44,7 +46,7 @@
DefaultDisplay.INSTANCE.get(mActivity).getInfo());
mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(mActivity,
true /* disableHorizontalSwipe */, navBarPosition,
- null /* onInterceptTouch */, this::onSwipeUp);
+ null /* onInterceptTouch */, this);
} else {
mTriggerSwipeUpTracker = null;
}
@@ -72,7 +74,11 @@
return false;
}
- private void onSwipeUp(boolean wasFling) {
+ @Override
+ public void onSwipeUp(boolean wasFling, PointF finalVelocity) {
mActivity.<FallbackRecentsView>getOverviewPanel().startHome();
}
+
+ @Override
+ public void onSwipeUpCancelled() {}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 8b08ea7..14215a1 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -404,6 +404,11 @@
}
@Override
+ public void notifyOrientationSetup() {
+ mDeviceState.onStartGesture();
+ }
+
+ @Override
public void onConsumerAboutToBeSwitched() {
Preconditions.assertUIThread();
mMainThreadHandler.removeCallbacks(mCancelRecentsAnimationRunnable);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java
index ac1c3a8..4440a04 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java
@@ -17,6 +17,7 @@
import android.content.Context;
import android.content.Intent;
+import android.graphics.PointF;
import android.view.MotionEvent;
import com.android.launcher3.BaseActivity;
@@ -33,7 +34,8 @@
import com.android.quickstep.util.TriggerSwipeUpTouchTracker;
import com.android.systemui.shared.system.InputMonitorCompat;
-public class OverviewWithoutFocusInputConsumer implements InputConsumer {
+public class OverviewWithoutFocusInputConsumer implements InputConsumer,
+ TriggerSwipeUpTouchTracker.OnSwipeUpListener {
private final Context mContext;
private final InputMonitorCompat mInputMonitor;
@@ -45,7 +47,7 @@
mContext = context;
mInputMonitor = inputMonitor;
mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(context, disableHorizontalSwipe,
- deviceState.getNavBarPosition(), this::onInterceptTouch, this::onSwipeUp);
+ deviceState.getNavBarPosition(), this::onInterceptTouch, this);
}
@Override
@@ -70,7 +72,8 @@
}
}
- private void onSwipeUp(boolean wasFling) {
+ @Override
+ public void onSwipeUp(boolean wasFling, PointF finalVelocity) {
mContext.startActivity(new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
@@ -83,4 +86,7 @@
wasFling ? Touch.FLING : Touch.SWIPE, Direction.UP, containerType, pageIndex);
activity.getUserEventDispatcher().setPreviousHomeGesture(true);
}
+
+ @Override
+ public void onSwipeUpCancelled() {}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java
new file mode 100644
index 0000000..3f833c0
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java
@@ -0,0 +1,86 @@
+/*
+ * 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.inputconsumers;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.PointF;
+import android.view.MotionEvent;
+
+import com.android.launcher3.testing.TestLogging;
+import com.android.launcher3.testing.TestProtocol;
+import com.android.quickstep.InputConsumer;
+import com.android.quickstep.RecentsAnimationDeviceState;
+import com.android.quickstep.util.TriggerSwipeUpTouchTracker;
+import com.android.systemui.shared.system.InputMonitorCompat;
+
+/**
+ * Input consumer used when a fullscreen System UI overlay is showing (such as the expanded Bubbles
+ * UI).
+ *
+ * This responds to swipes up by sending a closeSystemDialogs broadcast (causing overlays to close)
+ * rather than closing the app behind the overlay and sending the user all the way home.
+ */
+public class SysUiOverlayInputConsumer implements InputConsumer,
+ TriggerSwipeUpTouchTracker.OnSwipeUpListener {
+
+ private final Context mContext;
+ private final InputMonitorCompat mInputMonitor;
+ private final TriggerSwipeUpTouchTracker mTriggerSwipeUpTracker;
+
+ public SysUiOverlayInputConsumer(
+ Context context,
+ RecentsAnimationDeviceState deviceState,
+ InputMonitorCompat inputMonitor) {
+ mContext = context;
+ mInputMonitor = inputMonitor;
+ mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(context, true,
+ deviceState.getNavBarPosition(), this::onInterceptTouch, this);
+ }
+
+ @Override
+ public int getType() {
+ return TYPE_SYSUI_OVERLAY;
+ }
+
+ @Override
+ public boolean allowInterceptByParent() {
+ return !mTriggerSwipeUpTracker.interceptedTouch();
+ }
+
+ @Override
+ public void onMotionEvent(MotionEvent ev) {
+ mTriggerSwipeUpTracker.onMotionEvent(ev);
+ }
+
+ private void onInterceptTouch() {
+ if (mInputMonitor != null) {
+ TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers");
+ mInputMonitor.pilferPointers();
+ }
+ }
+
+ @Override
+ public void onSwipeUp(boolean wasFling, PointF finalVelocity) {
+ // Close system dialogs when a swipe up is detected.
+ mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ }
+
+ @Override
+ public void onSwipeUpCancelled() {
+
+ }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
index 8a6c4a1..e5d2c53 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -29,6 +29,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.FlingSpringAnim;
import com.android.launcher3.util.DynamicResource;
+import com.android.quickstep.RemoteAnimationTargets.ReleaseCheck;
import com.android.systemui.plugins.ResourceProvider;
import java.util.ArrayList;
@@ -39,7 +40,7 @@
* Applies spring forces to animate from a starting rect to a target rect,
* while providing update callbacks to the caller.
*/
-public class RectFSpringAnim {
+public class RectFSpringAnim extends ReleaseCheck {
private static final FloatPropertyCompat<RectFSpringAnim> RECT_CENTER_X =
new FloatPropertyCompat<RectFSpringAnim>("rectCenterXSpring") {
@@ -116,6 +117,7 @@
ResourceProvider rp = DynamicResource.provider(context);
mMinVisChange = rp.getDimension(R.dimen.swipe_up_fling_min_visible_change);
mYOvershoot = rp.getDimension(R.dimen.swipe_up_y_overshoot);
+ setCanRelease(true);
}
public void onTargetPositionChanged() {
@@ -190,10 +192,12 @@
maybeOnEnd();
});
+ setCanRelease(false);
+ mAnimsStarted = true;
+
mRectXAnim.start();
mRectYAnim.start();
mRectScaleAnim.start();
- mAnimsStarted = true;
for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
animatorListener.onAnimationStart(null);
}
@@ -245,6 +249,7 @@
private void maybeOnEnd() {
if (mAnimsStarted && isEnded()) {
mAnimsStarted = false;
+ setCanRelease(true);
for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
animatorListener.onAnimationEnd(null);
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SurfaceTransactionApplier.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SurfaceTransactionApplier.java
new file mode 100644
index 0000000..0a3e3ec
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SurfaceTransactionApplier.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import static com.android.systemui.shared.system.TransactionCompat.deferTransactionUntil;
+import static com.android.systemui.shared.system.TransactionCompat.setEarlyWakeup;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Message;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
+import android.view.View;
+
+import com.android.quickstep.RemoteAnimationTargets.ReleaseCheck;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
+import com.android.systemui.shared.system.ViewRootImplCompat;
+
+import java.util.function.Consumer;
+
+
+/**
+ * Helper class to apply surface transactions in sync with RenderThread similar to
+ * android.view.SyncRtSurfaceTransactionApplier
+ * with some Launcher specific utility methods
+ */
+@TargetApi(Build.VERSION_CODES.R)
+public class SurfaceTransactionApplier extends ReleaseCheck {
+
+ private static final int MSG_UPDATE_SEQUENCE_NUMBER = 0;
+
+ private final SurfaceControl mBarrierSurfaceControl;
+ private final ViewRootImplCompat mTargetViewRootImpl;
+ private final Handler mApplyHandler;
+
+ private int mLastSequenceNumber = 0;
+
+ /**
+ * @param targetView The view in the surface that acts as synchronization anchor.
+ */
+ public SurfaceTransactionApplier(View targetView) {
+ mTargetViewRootImpl = new ViewRootImplCompat(targetView);
+ mBarrierSurfaceControl = mTargetViewRootImpl.getRenderSurfaceControl();
+ mApplyHandler = new Handler(this::onApplyMessage);
+ }
+
+ protected boolean onApplyMessage(Message msg) {
+ if (msg.what == MSG_UPDATE_SEQUENCE_NUMBER) {
+ setCanRelease(msg.arg1 == mLastSequenceNumber);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Schedules applying surface parameters on the next frame.
+ *
+ * @param params The surface parameters to apply. DO NOT MODIFY the list after passing into
+ * this method to avoid synchronization issues.
+ */
+ public void scheduleApply(final SurfaceParams... params) {
+ View view = mTargetViewRootImpl.getView();
+ if (view == null) {
+ return;
+ }
+
+ mLastSequenceNumber++;
+ final int toApplySeqNo = mLastSequenceNumber;
+ setCanRelease(false);
+ mTargetViewRootImpl.registerRtFrameCallback(frame -> {
+ if (mBarrierSurfaceControl == null || !mBarrierSurfaceControl.isValid()) {
+ Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
+ .sendToTarget();
+ return;
+ }
+ Transaction t = new Transaction();
+ for (int i = params.length - 1; i >= 0; i--) {
+ SurfaceParams surfaceParams = params[i];
+ if (surfaceParams.surface.isValid()) {
+ deferTransactionUntil(t, surfaceParams.surface, mBarrierSurfaceControl, frame);
+ surfaceParams.applyTo(t);
+ }
+ }
+ setEarlyWakeup(t);
+ t.apply();
+ Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
+ .sendToTarget();
+ });
+
+ // Make sure a frame gets scheduled.
+ view.invalidate();
+ }
+
+ /**
+ * Creates an instance of SyncRtSurfaceTransactionApplier, deferring until the target view is
+ * attached if necessary.
+ */
+ public static void create(
+ final View targetView, final Consumer<SurfaceTransactionApplier> callback) {
+ if (targetView == null) {
+ // No target view, no applier
+ callback.accept(null);
+ } else if (new ViewRootImplCompat(targetView).isValid()) {
+ // Already attached, we're good to go
+ callback.accept(new SurfaceTransactionApplier(targetView));
+ } else {
+ // Haven't been attached before we can get the view root
+ targetView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ targetView.removeOnAttachStateChangeListener(this);
+ callback.accept(new SurfaceTransactionApplier(targetView));
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ // Do nothing
+ }
+ });
+ }
+ }
+}
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 3b08675..3c9762b 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
@@ -23,6 +23,7 @@
import android.animation.TimeInterpolator;
import android.content.Context;
import android.graphics.Matrix;
+import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -74,7 +75,7 @@
private DeviceProfile mDp;
private final Matrix mMatrix = new Matrix();
- private RemoteAnimationTargetCompat mRunningTarget;
+ private final Point mRunningTargetWindowPosition = new Point();
// Thumbnail view properties
private final Rect mThumbnailPosition = new Rect();
@@ -139,13 +140,19 @@
* Sets the targets which the simulator will control
*/
public void setPreview(RemoteAnimationTargetCompat runningTarget) {
- mRunningTarget = runningTarget;
+ setPreviewBounds(runningTarget.screenSpaceBounds, runningTarget.contentInsets);
+ mRunningTargetWindowPosition.set(runningTarget.position.x, runningTarget.position.y);
+ }
- mThumbnailData.insets.set(mRunningTarget.contentInsets);
+ /**
+ * Sets the targets which the simulator will control
+ */
+ public void setPreviewBounds(Rect bounds, Rect insets) {
+ mThumbnailData.insets.set(insets);
// TODO: What is this?
mThumbnailData.windowingMode = WINDOWING_MODE_FULLSCREEN;
- mThumbnailPosition.set(runningTarget.screenSpaceBounds);
+ mThumbnailPosition.set(bounds);
mLayoutValid = false;
}
@@ -199,16 +206,14 @@
postDisplayRotation(deltaRotation(
mOrientationState.getLauncherRotation(), mOrientationState.getDisplayRotation()),
mDp.widthPx, mDp.heightPx, matrix);
- if (mRunningTarget != null) {
- matrix.postTranslate(-mRunningTarget.position.x, -mRunningTarget.position.y);
- }
+ matrix.postTranslate(-mRunningTargetWindowPosition.x, -mRunningTargetWindowPosition.y);
}
/**
* Applies the target to the previously set parameters
*/
public void apply(TransformParams params) {
- if (mDp == null || mRunningTarget == null) {
+ if (mDp == null || mThumbnailPosition.isEmpty()) {
return;
}
if (!mLayoutValid) {
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
index 9bb508e..7a62e83 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TransformParams.java
@@ -57,7 +57,7 @@
private float mTargetAlpha;
private float mCornerRadius;
private RemoteAnimationTargets mTargetSet;
- private SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier;
+ private SurfaceTransactionApplier mSyncTransactionApplier;
private BuilderProxy mHomeBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
private BuilderProxy mBaseBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
@@ -112,7 +112,7 @@
* are computed based on these TransformParams.
*/
public TransformParams setSyncTransactionApplier(
- SyncRtSurfaceTransactionApplierCompat applier) {
+ SurfaceTransactionApplier applier) {
mSyncTransactionApplier = applier;
return this;
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
index c71258b..29b9558 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
@@ -149,8 +149,12 @@
isSwipeUp = squaredHypot(displacementX, displacementY) >= mSquaredTouchSlop;
}
- if (isSwipeUp && mOnSwipeUp != null) {
- mOnSwipeUp.onSwipeUp(wasFling);
+ if (mOnSwipeUp != null) {
+ if (isSwipeUp) {
+ mOnSwipeUp.onSwipeUp(wasFling, new PointF(velocityX, velocityY));
+ } else {
+ mOnSwipeUp.onSwipeUpCancelled();
+ }
}
}
@@ -161,7 +165,11 @@
/**
* Called on touch up if a swipe up was detected.
* @param wasFling Whether the swipe was a fling, or just passed touch slop at low velocity.
+ * @param finalVelocity The final velocity of the swipe.
*/
- void onSwipeUp(boolean wasFling);
+ void onSwipeUp(boolean wasFling, PointF finalVelocity);
+
+ /** Called on touch up if a swipe up was not detected. */
+ void onSwipeUpCancelled();
}
}
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 ea33d00..83287c4 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
@@ -45,8 +45,6 @@
public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayout
implements OnClickListener {
- public static final long VISIBILITY_TRANSITION_DURATION_MS = 80;
-
@IntDef(flag = true, value = {
HIDDEN_UNSUPPORTED_NAVIGATION,
HIDDEN_DISABLED_FEATURE,
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 a506b7e..f27bedb 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
@@ -127,6 +127,7 @@
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.SplitScreenBounds;
+import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.quickstep.util.TransformParams;
import com.android.systemui.plugins.ResourceProvider;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
@@ -135,7 +136,6 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.LauncherEventUtil;
import com.android.systemui.shared.system.PackageManagerWrapper;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
import com.android.systemui.shared.system.TaskStackChangeListener;
import java.util.ArrayList;
@@ -211,7 +211,7 @@
protected final BaseActivityInterface mSizeStrategy;
protected RecentsAnimationController mRecentsAnimationController;
protected RecentsAnimationTargets mRecentsAnimationTargets;
- protected SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier;
+ protected SurfaceTransactionApplier mSyncTransactionApplier;
protected int mTaskWidth;
protected int mTaskHeight;
protected boolean mEnableDrawingLiveTile = false;
@@ -492,6 +492,7 @@
public void init(OverviewActionsView actionsView) {
mActionsView = actionsView;
+ mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, getTaskViewCount() == 0);
}
@Override
@@ -501,7 +502,7 @@
mModel.getThumbnailCache().getHighResLoadingState().addCallback(this);
mActivity.addMultiWindowModeChangedListener(mMultiWindowModeChangedListener);
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
- mSyncTransactionApplier = new SyncRtSurfaceTransactionApplierCompat(this);
+ mSyncTransactionApplier = new SurfaceTransactionApplier(this);
RecentsModel.INSTANCE.get(getContext()).addThumbnailChangeListener(this);
mIdp.addOnChangeListener(this);
mIPinnedStackAnimationListener.setActivity(mActivity);
@@ -1039,6 +1040,11 @@
}
private void animateRecentsRotationInPlace(int newRotation) {
+ if (mOrientationState.canLauncherRotate()) {
+ // Update the rotation but let system take care of the rotation animation
+ setLayoutRotation(newRotation, mOrientationState.getDisplayRotation());
+ return;
+ }
AnimatorSet pa = setRecentsChangedOrientation(true);
pa.addListener(AnimationSuccessListener.forRunnable(() -> {
setLayoutRotation(newRotation, mOrientationState.getDisplayRotation());
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 6b759ba..af9d7f7 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,6 +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.LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
import android.animation.Animator;
@@ -222,8 +223,8 @@
setOutlineProvider(mOutlineProvider);
}
- /* Builds proto for logging */
- protected LauncherAtom.ItemInfo buildProto() {
+ /** Builds proto for logging */
+ public LauncherAtom.ItemInfo buildProto() {
ComponentKey componentKey = TaskUtils.getLaunchComponentKeyForTask(getTask().key);
LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
itemBuilder.setIsWork(componentKey.user != Process.myUserHandle());
@@ -424,6 +425,7 @@
private boolean showTaskMenu(int action) {
getRecentsView().snapToPage(getRecentsView().indexOfChild(this));
mMenuView = TaskMenuView.showForTask(this);
+ mActivity.getStatsLogManager().log(LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS, buildProto());
UserEventDispatcher.newInstance(getContext()).logActionOnItem(action, Direction.NONE,
LauncherLogProto.ItemType.TASK_ICON);
if (mMenuView != null) {
diff --git a/quickstep/res/layout/gesture_tutorial_fragment.xml b/quickstep/res/layout/gesture_tutorial_fragment.xml
index 190290e..74197be 100644
--- a/quickstep/res/layout/gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/gesture_tutorial_fragment.xml
@@ -24,6 +24,13 @@
android:layout_height="match_parent"
android:background="@drawable/gesture_tutorial_ripple"/>
+ <View
+ android:id="@+id/gesture_tutorial_fake_task_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/gesture_tutorial_fake_task_view_color"
+ android:visibility="invisible" />
+
<ImageView
android:id="@+id/gesture_tutorial_fragment_hand_coaching"
android:layout_width="match_parent"
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index ac7ff2a..35ff792 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -89,7 +89,6 @@
<!-- content description for hotseat items -->
<string name="hotseat_prediction_content_description">Predicted app: <xliff:g id="title" example="Chrome">%1$s</xliff:g></string>
-
<!-- Title shown during interactive part of Back gesture tutorial for right edge. [CHAR LIMIT=30] -->
<string name="back_gesture_tutorial_playground_title_swipe_inward_right_edge" translatable="false">Try the back gesture</string>
<!-- Subtitle shown during interactive parts of Back gesture tutorial for right edge. [CHAR LIMIT=60] -->
@@ -113,7 +112,6 @@
<!-- Subtitle shown on the confirmation screen after successful gesture. [CHAR LIMIT=60] -->
<string name="back_gesture_tutorial_confirm_subtitle" translatable="false">To change the sensitivity of the back gesture, go to Settings</string>
-
<!-- Title shown during interactive part of Home gesture tutorial. [CHAR LIMIT=30] -->
<string name="home_gesture_tutorial_playground_title" translatable="false">Tutorial: Go Home</string>
<!-- Subtitle shown during interactive parts of Home gesture tutorial. [CHAR LIMIT=60] -->
@@ -125,6 +123,17 @@
<!-- Feedback shown during interactive parts of Home gesture tutorial when the gesture is horizontal instead of vertical. [CHAR LIMIT=100] -->
<string name="home_gesture_feedback_wrong_swipe_direction" translatable="false">Make sure you swipe straight up</string>
+ <!-- Title shown during interactive part of Overview gesture tutorial. [CHAR LIMIT=30] -->
+ <string name="overview_gesture_tutorial_playground_title" translatable="false">Tutorial: Switch Apps</string>
+ <!-- Subtitle shown during interactive parts of Overview gesture tutorial. [CHAR LIMIT=60] -->
+ <string name="overview_gesture_tutorial_playground_subtitle" translatable="false">Swipe up from the bottom of the screen and hold</string>
+ <!-- Feedback shown during interactive parts of Overview gesture tutorial when the gesture is started too far from the edge. [CHAR LIMIT=100] -->
+ <string name="overview_gesture_feedback_swipe_too_far_from_edge" translatable="false">Make sure you swipe from the bottom edge of the screen</string>
+ <!-- Feedback shown during interactive parts of Overview gesture tutorial when the Home gesture is detected. [CHAR LIMIT=100] -->
+ <string name="overview_gesture_feedback_home_detected" translatable="false">Try holding the window for longer before releasing</string>
+ <!-- Feedback shown during interactive parts of Overview gesture tutorial when the gesture is horizontal instead of vertical. [CHAR LIMIT=100] -->
+ <string name="overview_gesture_feedback_wrong_swipe_direction" translatable="false">Make sure you swipe straight up and pause</string>
+
<!-- Title shown on the confirmation screen after successful gesture. [CHAR LIMIT=30] -->
<string name="gesture_tutorial_confirm_title" translatable="false">All set</string>
<!-- Button text shown on a button on the confirm screen to leave the tutorial. [CHAR LIMIT=14] -->
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index 25c07f1..fe7b946 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -82,6 +82,7 @@
import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.quickstep.util.RemoteAnimationProvider;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
+import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.systemui.shared.system.ActivityCompat;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.QuickStepContract;
@@ -89,7 +90,6 @@
import com.android.systemui.shared.system.RemoteAnimationDefinitionCompat;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
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.WindowManagerWrapper;
@@ -455,9 +455,9 @@
RemoteAnimationTargets openingTargets = new RemoteAnimationTargets(appTargets,
wallpaperTargets, MODE_OPENING);
- SyncRtSurfaceTransactionApplierCompat surfaceApplier =
- new SyncRtSurfaceTransactionApplierCompat(floatingView);
- openingTargets.addDependentTransactionApplier(surfaceApplier);
+ SurfaceTransactionApplier surfaceApplier =
+ new SurfaceTransactionApplier(floatingView);
+ openingTargets.addReleaseCheck(surfaceApplier);
// Scale the app icon to take up the entire screen. This simplifies the math when
// animating the app window position / scale.
@@ -712,8 +712,7 @@
*/
private Animator getUnlockWindowAnimator(RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets) {
- SyncRtSurfaceTransactionApplierCompat surfaceApplier =
- new SyncRtSurfaceTransactionApplierCompat(mDragLayer);
+ SurfaceTransactionApplier surfaceApplier = new SurfaceTransactionApplier(mDragLayer);
ValueAnimator unlockAnimator = ValueAnimator.ofFloat(0, 1);
unlockAnimator.setDuration(CLOSING_TRANSITION_DURATION_MS);
float cornerRadius = mDeviceProfile.isMultiWindowMode ? 0 :
@@ -741,8 +740,7 @@
*/
private Animator getClosingWindowAnimators(RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets) {
- SyncRtSurfaceTransactionApplierCompat surfaceApplier =
- new SyncRtSurfaceTransactionApplierCompat(mDragLayer);
+ SurfaceTransactionApplier surfaceApplier = new SurfaceTransactionApplier(mDragLayer);
Matrix matrix = new Matrix();
Point tmpPos = new Point();
ValueAnimator closingAnimator = ValueAnimator.ofFloat(0, 1);
diff --git a/quickstep/src/com/android/launcher3/model/WellbeingModel.java b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
index 2181aa8..f42b124 100644
--- a/quickstep/src/com/android/launcher3/model/WellbeingModel.java
+++ b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
@@ -77,6 +77,7 @@
private static final String EXTRA_ACTION = "action";
private static final String EXTRA_MAX_NUM_ACTIONS_SHOWN = "max_num_actions_shown";
private static final String EXTRA_PACKAGES = "packages";
+ private static final String EXTRA_SUCCESS = "success";
public static final MainThreadInitializedObject<WellbeingModel> INSTANCE =
new MainThreadInitializedObject<>(WellbeingModel::new);
@@ -221,6 +222,7 @@
params.putInt(EXTRA_MAX_NUM_ACTIONS_SHOWN, 1);
// Perform wellbeing call .
remoteActionBundle = client.call(METHOD_GET_ACTIONS, null, params);
+ if (!remoteActionBundle.getBoolean(EXTRA_SUCCESS, true)) return false;
synchronized (mModelLock) {
// Remove the entries for requested packages, and then update the fist with what we
@@ -281,9 +283,9 @@
// Remove all existing messages
mWorkerHandler.removeCallbacksAndMessages(null);
final String[] packageNames = mContext.getSystemService(LauncherApps.class)
- .getActivityList(null, Process.myUserHandle()).stream()
- .map(li -> li.getApplicationInfo().packageName).distinct()
- .toArray(String[]::new);
+ .getActivityList(null, Process.myUserHandle()).stream()
+ .map(li -> li.getApplicationInfo().packageName).distinct()
+ .toArray(String[]::new);
if (!updateActions(packageNames)) {
scheduleRefreshRetry(msg);
}
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index 8292a92..ebe9e26 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -17,6 +17,7 @@
package com.android.launcher3.statehandlers;
import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_DEPTH;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
import android.os.IBinder;
@@ -102,11 +103,30 @@
*/
private float mDepth;
+ private View.OnAttachStateChangeListener mOnAttachListener;
+
public DepthController(Launcher l) {
mLauncher = l;
}
private void ensureDependencies() {
+ if (mLauncher.getRootView() != null && mOnAttachListener == null) {
+ mOnAttachListener = new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View view) {
+ // To handle the case where window token is invalid during last setDepth call.
+ IBinder windowToken = mLauncher.getRootView().getWindowToken();
+ if (windowToken != null) {
+ mWallpaperManager.setWallpaperZoomOut(windowToken, mDepth);
+ }
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View view) {
+ }
+ };
+ mLauncher.getRootView().addOnAttachStateChangeListener(mOnAttachListener);
+ }
if (mWallpaperManager != null) {
return;
}
@@ -172,11 +192,12 @@
float toDepth = toState.getDepth(mLauncher);
if (Float.compare(mDepth, toDepth) != 0) {
- animation.setFloat(this, DEPTH, toDepth, LINEAR);
+ animation.setFloat(this, DEPTH, toDepth, config.getInterpolator(ANIM_DEPTH, LINEAR));
}
}
private void setDepth(float depth) {
+ depth = Utilities.boundToRange(depth, 0, 1);
// Round out the depth to dedupe frequent, non-perceptable updates
int depthI = (int) (depth * 256);
float depthF = depthI / 256f;
@@ -184,10 +205,10 @@
return;
}
- mDepth = depthF;
if (mSurface == null || !mSurface.isValid()) {
return;
}
+ mDepth = depthF;
ensureDependencies();
IBinder windowToken = mLauncher.getRootView().getWindowToken();
if (windowToken != null) {
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 9124925..7122647 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -101,7 +101,7 @@
activity.getStateManager().reapplyState();
}
- public abstract void onSwipeUpToHomeComplete();
+ public abstract void onSwipeUpToHomeComplete(RecentsAnimationDeviceState deviceState);
public abstract void onAssistantVisibilityChanged(float visibility);
diff --git a/quickstep/src/com/android/quickstep/InputConsumer.java b/quickstep/src/com/android/quickstep/InputConsumer.java
index a4861dc..ec720d5 100644
--- a/quickstep/src/com/android/quickstep/InputConsumer.java
+++ b/quickstep/src/com/android/quickstep/InputConsumer.java
@@ -34,6 +34,7 @@
int TYPE_OVERVIEW_WITHOUT_FOCUS = 1 << 7;
int TYPE_RESET_GESTURE = 1 << 8;
int TYPE_OVERSCROLL = 1 << 9;
+ int TYPE_SYSUI_OVERLAY = 1 << 10;
String[] NAMES = new String[] {
"TYPE_NO_OP", // 0
@@ -46,6 +47,7 @@
"TYPE_OVERVIEW_WITHOUT_FOCUS", // 7
"TYPE_RESET_GESTURE", // 8
"TYPE_OVERSCROLL", // 9
+ "TYPE_SYSUI_OVERLAY" // 10
};
InputConsumer NO_OP = () -> TYPE_NO_OP;
@@ -70,6 +72,11 @@
}
/**
+ * Handle and specific setup necessary based on the orientation of the device
+ */
+ default void notifyOrientationSetup() {}
+
+ /**
* Returns the active input consumer is in the hierarchy of this input consumer.
*/
default InputConsumer getActiveConsumerInHierarchy() {
diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
index 4cf7aab..c3ff32f 100644
--- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
@@ -36,8 +36,8 @@
import com.android.launcher3.R;
import com.android.launcher3.ResourceUtils;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.DefaultDisplay;
-import com.android.quickstep.util.RecentsOrientedState.SurfaceRotation;
import java.io.PrintWriter;
@@ -67,6 +67,14 @@
private boolean mEnableMultipleRegions;
private Resources mResources;
private OrientationRectF mLastRectTouched;
+ /**
+ * The rotation of the last touched nav bar. Derived from {@link #mLastRectTouched}, but has a
+ * longer lifetime than the rect. Note this is different than {@link #mQuickStepStartingRotation}
+ * as it always updates its value on every touch whereas mQuickstepStartingRotation only
+ * updates when device rotation matches touch rotation. Maybe this will be only one necessary
+ * after TODO(b/154580671) is in. TBD.
+ */
+ private int mLastRectRotation;
private SysUINavigationMode.Mode mMode;
private QuickStepContractInfo mContractInfo;
@@ -143,15 +151,18 @@
* ALSO, you BETTER call this with {@param enableMultipleRegions} set to false once you're done.
*
* @param enableMultipleRegions Set to true to start tracking multiple nav bar regions
- * @param info The current displayInfo
+ * @param info The current displayInfo which will be the start of the quickswitch gesture
*/
void enableMultipleRegions(boolean enableMultipleRegions, DefaultDisplay.Info info) {
mEnableMultipleRegions = enableMultipleRegions &&
mMode != SysUINavigationMode.Mode.TWO_BUTTONS;
- if (!enableMultipleRegions) {
+ if (mEnableMultipleRegions) {
+ mQuickStepStartingRotation = info.rotation;
+ } else {
+ mLastRectRotation = 0;
mQuickStepStartingRotation = QUICKSTEP_ROTATION_UNINITIALIZED;
- resetSwipeRegions(info);
}
+ resetSwipeRegions(info);
}
/**
@@ -236,6 +247,10 @@
}
boolean touchInValidSwipeRegions(float x, float y) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_SWIPE_TO_HOME, "touchInValidSwipeRegions " + x + "," + y + " in "
+ + mLastRectTouched);
+ }
if (mLastRectTouched != null) {
return mLastRectTouched.contains(x, y);
}
@@ -243,11 +258,7 @@
}
int getCurrentActiveRotation() {
- if (mLastRectTouched == null) {
- return 0;
- } else {
- return mLastRectTouched.mRotation;
- }
+ return mLastRectRotation;
}
int getQuickStepStartingRotation() {
@@ -286,7 +297,9 @@
}
if (rect.applyTransform(event, false)) {
mLastRectTouched = rect;
- if (mCurrentDisplayRotation == mLastRectTouched.mRotation) {
+ mLastRectRotation = rect.mRotation;
+ if (mEnableMultipleRegions && mCurrentDisplayRotation == mLastRectRotation) {
+ // TODO(b/154580671) might make this block unnecessary
// Start a touch session for the default nav region for the display
mQuickStepStartingRotation = mLastRectTouched.mRotation;
resetSwipeRegions();
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 2d9c56f..70b4f20 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -40,21 +40,20 @@
/**
* Manages the recent task list from the system, caching it as necessary.
*/
-@TargetApi(Build.VERSION_CODES.P)
+@TargetApi(Build.VERSION_CODES.R)
public class RecentTasksList extends TaskStackChangeListener {
+ private static final TaskLoadResult INVALID_RESULT = new TaskLoadResult(-1, false, 0);
+
private final KeyguardManagerCompat mKeyguardManager;
private final LooperExecutor mMainThreadExecutor;
private final ActivityManagerWrapper mActivityManagerWrapper;
// The list change id, increments as the task list changes in the system
private int mChangeId;
- // The last change id when the list was last loaded completely, must be <= the list change id
- private int mLastLoadedId;
- // The last change id was loaded with keysOnly = true
- private boolean mLastLoadHadKeysOnly;
- ArrayList<Task> mTasks = new ArrayList<>();
+ private TaskLoadResult mResultsBg = INVALID_RESULT;
+ private TaskLoadResult mResultsUi = INVALID_RESULT;
public RecentTasksList(LooperExecutor mainThreadExecutor,
KeyguardManagerCompat keyguardManager, ActivityManagerWrapper activityManagerWrapper) {
@@ -71,7 +70,7 @@
public void getTaskKeys(int numTasks, Consumer<ArrayList<Task>> callback) {
// Kick off task loading in the background
UI_HELPER_EXECUTOR.execute(() -> {
- ArrayList<Task> tasks = loadTasksInBackground(numTasks, true /* loadKeysOnly */);
+ ArrayList<Task> tasks = loadTasksInBackground(numTasks, -1, true /* loadKeysOnly */);
mMainThreadExecutor.execute(() -> callback.accept(tasks));
});
}
@@ -85,26 +84,30 @@
*/
public synchronized int getTasks(boolean loadKeysOnly, Consumer<ArrayList<Task>> callback) {
final int requestLoadId = mChangeId;
- Runnable resultCallback = callback == null
- ? () -> { }
- : () -> callback.accept(copyOf(mTasks));
-
- if (mLastLoadedId == mChangeId && (!mLastLoadHadKeysOnly || loadKeysOnly)) {
+ if (mResultsUi.isValidForRequest(requestLoadId, loadKeysOnly)) {
// The list is up to date, send the callback on the next frame,
// so that requestID can be returned first.
- mMainThreadExecutor.post(resultCallback);
+ if (callback != null) {
+ // Copy synchronously as the changeId might change by next frame
+ ArrayList<Task> result = copyOf(mResultsUi);
+ mMainThreadExecutor.post(() -> callback.accept(result));
+ }
+
return requestLoadId;
}
// Kick off task loading in the background
UI_HELPER_EXECUTOR.execute(() -> {
- ArrayList<Task> tasks = loadTasksInBackground(Integer.MAX_VALUE, loadKeysOnly);
-
+ if (!mResultsBg.isValidForRequest(requestLoadId, loadKeysOnly)) {
+ mResultsBg = loadTasksInBackground(Integer.MAX_VALUE, requestLoadId, loadKeysOnly);
+ }
+ TaskLoadResult loadResult = mResultsBg;
mMainThreadExecutor.execute(() -> {
- mTasks = tasks;
- mLastLoadedId = requestLoadId;
- mLastLoadHadKeysOnly = loadKeysOnly;
- resultCallback.run();
+ mResultsUi = loadResult;
+ if (callback != null) {
+ ArrayList<Task> result = copyOf(mResultsUi);
+ callback.accept(result);
+ }
});
});
@@ -119,8 +122,8 @@
}
@Override
- public synchronized void onTaskStackChanged() {
- mChangeId++;
+ public void onTaskStackChanged() {
+ invalidateLoadedTasks();
}
@Override
@@ -131,22 +134,28 @@
// callback (those are for changes to the active tasks), but the task list is still updated,
// so we should also invalidate the change id to ensure we load a new list instead of
// reusing a stale list.
- mChangeId++;
+ invalidateLoadedTasks();
}
@Override
public void onTaskRemoved(int taskId) {
- mTasks = loadTasksInBackground(Integer.MAX_VALUE, false);
+ invalidateLoadedTasks();
}
+
@Override
- public synchronized void onActivityPinned(String packageName, int userId, int taskId,
- int stackId) {
- mChangeId++;
+ public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
+ invalidateLoadedTasks();
}
@Override
public synchronized void onActivityUnpinned() {
+ invalidateLoadedTasks();
+ }
+
+ private synchronized void invalidateLoadedTasks() {
+ UI_HELPER_EXECUTOR.execute(() -> mResultsBg = INVALID_RESULT);
+ mResultsUi = INVALID_RESULT;
mChangeId++;
}
@@ -154,9 +163,8 @@
* Loads and creates a list of all the recent tasks.
*/
@VisibleForTesting
- ArrayList<Task> loadTasksInBackground(int numTasks, boolean loadKeysOnly) {
+ TaskLoadResult loadTasksInBackground(int numTasks, int requestId, boolean loadKeysOnly) {
int currentUserId = Process.myUserHandle().getIdentifier();
- ArrayList<Task> allTasks = new ArrayList<>();
List<ActivityManager.RecentTaskInfo> rawTasks =
mActivityManagerWrapper.getRecentTasks(numTasks, currentUserId);
// The raw tasks are given in most-recent to least-recent order, we need to reverse it
@@ -173,6 +181,7 @@
}
};
+ TaskLoadResult allTasks = new TaskLoadResult(requestId, loadKeysOnly, rawTasks.size());
for (ActivityManager.RecentTaskInfo rawTask : rawTasks) {
Task.TaskKey taskKey = new Task.TaskKey(rawTask);
Task task;
@@ -197,4 +206,22 @@
}
return newTasks;
}
+
+ private static class TaskLoadResult extends ArrayList<Task> {
+
+ final int mId;
+
+ // If the result was loaded with keysOnly = true
+ final boolean mKeysOnly;
+
+ TaskLoadResult(int id, boolean keysOnly, int size) {
+ super(size);
+ mId = id;
+ mKeysOnly = keysOnly;
+ }
+
+ boolean isValidForRequest(int requestId, boolean loadKeysOnly) {
+ return mId == requestId && (!mKeysOnly || loadKeysOnly);
+ }
+ }
}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index b0a3cd2..4e9aa61 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -29,7 +29,6 @@
import android.view.MotionEvent;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import com.android.launcher3.util.Preconditions;
@@ -58,8 +57,7 @@
private boolean mUseLauncherSysBarFlags = false;
private boolean mSplitScreenMinimized = false;
private boolean mTouchInProgress;
- private boolean mFinishPending;
- private @Nullable Runnable mFinishPendingCallback;
+ private boolean mDisableInputProxyPending;
public RecentsAnimationController(RecentsAnimationControllerCompat controller,
boolean allowMinimizeSplitScreen,
@@ -138,12 +136,12 @@
@UiThread
public void finishAnimationToHome() {
- finishAndClear(true /* toRecents */, null, false /* sendUserLeaveHint */);
+ finishAndDisableInputProxy(true /* toRecents */, null, false /* sendUserLeaveHint */);
}
@UiThread
public void finishAnimationToApp() {
- finishAndClear(false /* toRecents */, null, false /* sendUserLeaveHint */);
+ finishAndDisableInputProxy(false /* toRecents */, null, false /* sendUserLeaveHint */);
}
/** See {@link #finish(boolean, Runnable, boolean)} */
@@ -162,19 +160,16 @@
@UiThread
public void finish(boolean toRecents, Runnable onFinishComplete, boolean sendUserLeaveHint) {
Preconditions.assertUIThread();
- if (!toRecents) {
- finishAndClear(false, onFinishComplete, sendUserLeaveHint);
+ if (toRecents && mTouchInProgress) {
+ // Finish the controller as requested, but don't disable input proxy yet.
+ mDisableInputProxyPending = true;
+ finishController(toRecents, onFinishComplete, sendUserLeaveHint);
} else {
- if (mTouchInProgress) {
- mFinishPending = true;
- mFinishPendingCallback = onFinishComplete;
- } else {
- finishAndClear(true, onFinishComplete, sendUserLeaveHint);
- }
+ finishAndDisableInputProxy(toRecents, onFinishComplete, sendUserLeaveHint);
}
}
- private void finishAndClear(boolean toRecents, Runnable onFinishComplete,
+ private void finishAndDisableInputProxy(boolean toRecents, Runnable onFinishComplete,
boolean sendUserLeaveHint) {
disableInputProxy();
finishController(toRecents, onFinishComplete, sendUserLeaveHint);
@@ -262,11 +257,9 @@
} else if (action == ACTION_CANCEL || action == ACTION_UP) {
// Finish any pending actions
mTouchInProgress = false;
- if (mFinishPending) {
- mFinishPending = false;
- finishAndClear(true /* toRecents */, mFinishPendingCallback,
- false /* sendUserLeaveHint */);
- mFinishPendingCallback = null;
+ if (mDisableInputProxyPending) {
+ mDisableInputProxyPending = false;
+ disableInputProxy();
}
}
if (mInputConsumer != null) {
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 6e7c423..7f9a8bd 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -18,6 +18,7 @@
import static android.content.Intent.ACTION_USER_UNLOCKED;
import static com.android.launcher3.util.DefaultDisplay.CHANGE_ALL;
+import static com.android.launcher3.util.DefaultDisplay.CHANGE_FRAME_DELAY;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
@@ -44,6 +45,7 @@
import android.graphics.Region;
import android.os.Process;
import android.os.UserManager;
+import android.provider.Settings;
import android.text.TextUtils;
import android.view.MotionEvent;
@@ -52,6 +54,7 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.DefaultDisplay;
+import com.android.launcher3.util.SecureSettingsObserver;
import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
import com.android.quickstep.util.NavBarPosition;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -103,7 +106,8 @@
private TaskStackChangeListener mFrozenTaskListener = new TaskStackChangeListener() {
@Override
public void onRecentTaskListFrozenChanged(boolean frozen) {
- if (frozen) {
+ mTaskListFrozen = frozen;
+ if (frozen || mInOverview) {
return;
}
enableMultipleRegions(false);
@@ -124,6 +128,9 @@
* TODO: (b/156984037) For when user rotates after entering overview
*/
private boolean mInOverview;
+ private boolean mTaskListFrozen;
+
+ private boolean mIsUserSetupComplete;
public RecentsAnimationDeviceState(Context context) {
mContext = context;
@@ -175,6 +182,17 @@
ComponentName.unflattenFromString(blockingActivity));
}
}
+
+ SecureSettingsObserver userSetupObserver = new SecureSettingsObserver(
+ context.getContentResolver(),
+ e -> mIsUserSetupComplete = e,
+ Settings.Secure.USER_SETUP_COMPLETE,
+ 0);
+ mIsUserSetupComplete = userSetupObserver.getValue();
+ if (!mIsUserSetupComplete) {
+ userSetupObserver.register();
+ runOnDestroy(userSetupObserver::unregister);
+ }
}
private void setupOrientationSwipeHandler() {
@@ -243,7 +261,8 @@
@Override
public void onDisplayInfoChanged(DefaultDisplay.Info info, int flags) {
- if (info.id != getDisplayId()) {
+ if (info.id != getDisplayId() || (flags & CHANGE_FRAME_DELAY) == CHANGE_FRAME_DELAY) {
+ // ignore displays that aren't running launcher and frame refresh rate changes
return;
}
@@ -314,6 +333,13 @@
return mIsUserUnlocked;
}
+ /**
+ * @return whether the user has completed setup wizard
+ */
+ public boolean isUserSetupComplete() {
+ return mIsUserSetupComplete;
+ }
+
private void notifyUserUnlocked() {
for (Runnable action : mUserUnlockedActions) {
action.run();
@@ -360,7 +386,6 @@
return (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0
&& (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0
&& (mSystemUiStateFlags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) == 0
- && (mSystemUiStateFlags & SYSUI_STATE_BUBBLES_EXPANDED) == 0
&& ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0
|| (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0);
}
@@ -381,6 +406,13 @@
}
/**
+ * @return whether the bubble stack is expanded
+ */
+ public boolean isBubblesExpanded() {
+ return (mSystemUiStateFlags & SYSUI_STATE_BUBBLES_EXPANDED) != 0;
+ }
+
+ /**
* @return whether lock-task mode is active
*/
public boolean isLockToAppActive() {
@@ -506,7 +538,7 @@
* *May* apply a transform on the motion event if it lies in the nav bar region for another
* orientation that is currently being tracked as a part of quickstep
*/
- public void setOrientationTransformIfNeeded(MotionEvent event) {
+ void setOrientationTransformIfNeeded(MotionEvent event) {
// negative coordinates bug b/143901881
if (event.getX() < 0 || event.getY() < 0) {
event.setLocation(Math.max(0, event.getX()), Math.max(0, event.getY()));
@@ -514,25 +546,54 @@
mOrientationTouchTransformer.transform(event);
}
- void onSwipeUpToOverview(BaseActivityInterface activityInterface) {
- mInOverview = true;
- activityInterface.onExitOverview(this, () -> {
- mInOverview = false;
- enableMultipleRegions(false);
- });
+ void enableMultipleRegions(boolean enable) {
+ mOrientationTouchTransformer.enableMultipleRegions(enable, mDefaultDisplay.getInfo());
+ notifySysuiForRotation(mOrientationTouchTransformer.getQuickStepStartingRotation());
}
- void enableMultipleRegions(boolean enable) {
- if (mInOverview) {
- return;
+ private void notifySysuiForRotation(int rotation) {
+ UI_HELPER_EXECUTOR.execute(() ->
+ SystemUiProxy.INSTANCE.get(mContext).onQuickSwitchToNewTask(rotation));
+ }
+
+ public void onStartGesture() {
+ if (mTaskListFrozen) {
+ // Prioritize whatever nav bar user touches once in quickstep
+ // This case is specifically when user changes what nav bar they are using mid
+ // quickswitch session before tasks list is unfrozen
+ notifySysuiForRotation(mOrientationTouchTransformer.getCurrentActiveRotation());
}
- mOrientationTouchTransformer.enableMultipleRegions(enable, mDefaultDisplay.getInfo());
- UI_HELPER_EXECUTOR.execute(() -> {
- int quickStepStartingRotation =
- mOrientationTouchTransformer.getQuickStepStartingRotation();
- SystemUiProxy.INSTANCE.get(mContext)
- .onQuickSwitchToNewTask(quickStepStartingRotation);
- });
+ }
+
+
+ void onEndTargetCalculated(GestureState.GestureEndTarget endTarget,
+ BaseActivityInterface activityInterface) {
+ if (endTarget == GestureState.GestureEndTarget.RECENTS) {
+ mInOverview = true;
+ if (!mTaskListFrozen) {
+ // If we're in landscape w/o ever quickswitching, show the navbar in landscape
+ enableMultipleRegions(true);
+ }
+ activityInterface.onExitOverview(this, () -> {
+ mInOverview = false;
+ enableMultipleRegions(false);
+ });
+ } else if (endTarget == GestureState.GestureEndTarget.HOME) {
+ enableMultipleRegions(false);
+ } else if (endTarget == GestureState.GestureEndTarget.NEW_TASK) {
+ if (mOrientationTouchTransformer.getQuickStepStartingRotation() == -1) {
+ // First gesture to start quickswitch
+ enableMultipleRegions(true);
+ } else {
+ notifySysuiForRotation(mOrientationTouchTransformer.getCurrentActiveRotation());
+ }
+ } else if (endTarget == GestureState.GestureEndTarget.LAST_TASK) {
+ if (!mTaskListFrozen) {
+ // touched nav bar but didn't go anywhere and not quickswitching, do nothing
+ return;
+ }
+ notifySysuiForRotation(mOrientationTouchTransformer.getCurrentActiveRotation());
+ }
}
public int getCurrentActiveRotation() {
diff --git a/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
index f90df45..ab5e3ba 100644
--- a/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
@@ -16,19 +16,16 @@
package com.android.quickstep;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
-import java.util.ArrayDeque;
import java.util.ArrayList;
-import java.util.Queue;
+import java.util.concurrent.CopyOnWriteArrayList;
/**
* Holds a collection of RemoteAnimationTargets, filtered by different properties.
*/
public class RemoteAnimationTargets {
- private final Queue<SyncRtSurfaceTransactionApplierCompat> mDependentTransactionAppliers =
- new ArrayDeque<>(1);
+ private final CopyOnWriteArrayList<ReleaseCheck> mReleaseChecks = new CopyOnWriteArrayList<>();
public final RemoteAnimationTargetCompat[] unfilteredApps;
public final RemoteAnimationTargetCompat[] apps;
@@ -36,6 +33,8 @@
public final int targetMode;
public final boolean hasRecents;
+ private boolean mReleased = false;
+
public RemoteAnimationTargets(RemoteAnimationTargetCompat[] apps,
RemoteAnimationTargetCompat[] wallpapers, int targetMode) {
ArrayList<RemoteAnimationTargetCompat> filteredApps = new ArrayList<>();
@@ -76,21 +75,65 @@
return false;
}
- public void addDependentTransactionApplier(SyncRtSurfaceTransactionApplierCompat delay) {
- mDependentTransactionAppliers.add(delay);
+ public void addReleaseCheck(ReleaseCheck check) {
+ mReleaseChecks.add(check);
}
public void release() {
- SyncRtSurfaceTransactionApplierCompat applier = mDependentTransactionAppliers.poll();
- if (applier == null) {
- for (RemoteAnimationTargetCompat target : unfilteredApps) {
- target.release();
+ if (mReleased) {
+ return;
+ }
+ for (ReleaseCheck check : mReleaseChecks) {
+ if (!check.mCanRelease) {
+ check.addOnSafeToReleaseCallback(this::release);
+ return;
}
- for (RemoteAnimationTargetCompat target : wallpapers) {
- target.release();
+ }
+ mReleaseChecks.clear();
+ mReleased = true;
+
+ for (RemoteAnimationTargetCompat target : unfilteredApps) {
+ target.release();
+ }
+ for (RemoteAnimationTargetCompat target : wallpapers) {
+ target.release();
+ }
+ }
+
+ /**
+ * Interface for intercepting surface release method
+ */
+ public static class ReleaseCheck {
+
+ boolean mCanRelease = false;
+ private Runnable mAfterApplyCallback;
+
+ protected void setCanRelease(boolean canRelease) {
+ mCanRelease = canRelease;
+ if (mCanRelease && mAfterApplyCallback != null) {
+ Runnable r = mAfterApplyCallback;
+ mAfterApplyCallback = null;
+ r.run();
}
- } else {
- applier.addAfterApplyCallback(this::release);
+ }
+
+ /**
+ * Adds a callback to notify when the surface can safely be released
+ */
+ void addOnSafeToReleaseCallback(Runnable callback) {
+ if (mCanRelease) {
+ callback.run();
+ } else {
+ if (mAfterApplyCallback == null) {
+ mAfterApplyCallback = callback;
+ } else {
+ final Runnable oldCallback = mAfterApplyCallback;
+ mAfterApplyCallback = () -> {
+ callback.run();
+ oldCallback.run();
+ };
+ }
+ }
}
}
}
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 20d133c..c727da9 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -31,6 +31,7 @@
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.recents.ISystemUiProxy;
+import com.android.systemui.shared.recents.model.Task;
/**
* Holds the reference to SystemUI.
@@ -344,4 +345,8 @@
}
}
}
+
+ public void handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen,
+ Insets visibleInsets, Task.TaskKey task) {
+ }
}
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index 58870ed..1f398fc 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -18,8 +18,11 @@
import static com.android.quickstep.interaction.TutorialController.TutorialType.BACK_NAVIGATION_COMPLETE;
import static com.android.quickstep.interaction.TutorialController.TutorialType.LEFT_EDGE_BACK_NAVIGATION;
+import android.graphics.PointF;
import android.view.View;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.R;
import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult;
@@ -32,14 +35,6 @@
}
@Override
- void transitToController() {
- super.transitToController();
- if (mTutorialType != BACK_NAVIGATION_COMPLETE) {
- showHandCoachingAnimation();
- }
- }
-
- @Override
Integer getTitleStringId() {
switch (mTutorialType) {
case RIGHT_EDGE_BACK_NAVIGATION:
@@ -154,11 +149,14 @@
}
@Override
- public void onNavBarGestureAttempted(NavBarGestureResult result) {
+ public void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity) {
if (mTutorialType == BACK_NAVIGATION_COMPLETE) {
if (result == NavBarGestureResult.HOME_GESTURE_COMPLETED) {
mTutorialFragment.closeTutorial();
}
}
}
+
+ @Override
+ public void setNavBarGestureProgress(@Nullable Float displacement) {}
}
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index 524cbaf..0edabd4 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -17,6 +17,9 @@
import static com.android.quickstep.interaction.TutorialController.TutorialType.HOME_NAVIGATION_COMPLETE;
+import android.annotation.TargetApi;
+import android.graphics.PointF;
+import android.os.Build;
import android.view.View;
import com.android.launcher3.R;
@@ -24,21 +27,14 @@
import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult;
/** A {@link TutorialController} for the Home tutorial. */
-final class HomeGestureTutorialController extends TutorialController {
+@TargetApi(Build.VERSION_CODES.R)
+final class HomeGestureTutorialController extends SwipeUpGestureTutorialController {
HomeGestureTutorialController(HomeGestureTutorialFragment fragment, TutorialType tutorialType) {
super(fragment, tutorialType);
}
@Override
- void transitToController() {
- super.transitToController();
- if (mTutorialType != HOME_NAVIGATION_COMPLETE) {
- showHandCoachingAnimation();
- }
- }
-
- @Override
Integer getTitleStringId() {
switch (mTutorialType) {
case HOME_NAVIGATION:
@@ -74,6 +70,14 @@
public void onBackGestureAttempted(BackGestureResult result) {
switch (mTutorialType) {
case HOME_NAVIGATION:
+ switch (result) {
+ case BACK_COMPLETED_FROM_LEFT:
+ case BACK_COMPLETED_FROM_RIGHT:
+ case BACK_CANCELLED_FROM_LEFT:
+ case BACK_CANCELLED_FROM_RIGHT:
+ showFeedback(R.string.home_gesture_feedback_swipe_too_far_from_edge);
+ break;
+ }
break;
case HOME_NAVIGATION_COMPLETE:
if (result == BackGestureResult.BACK_COMPLETED_FROM_LEFT
@@ -85,22 +89,26 @@
}
@Override
- public void onNavBarGestureAttempted(NavBarGestureResult result) {
+ public void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity) {
switch (mTutorialType) {
case HOME_NAVIGATION:
switch (result) {
- case HOME_GESTURE_COMPLETED:
- hideHandCoachingAnimation();
- mTutorialFragment.changeController(HOME_NAVIGATION_COMPLETE);
+ case HOME_GESTURE_COMPLETED: {
+ animateFakeTaskViewHome(finalVelocity, () ->
+ mTutorialFragment.changeController(HOME_NAVIGATION_COMPLETE));
break;
+ }
case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE:
showFeedback(R.string.home_gesture_feedback_swipe_too_far_from_edge);
break;
case OVERVIEW_GESTURE_COMPLETED:
- showFeedback(R.string.home_gesture_feedback_overview_detected);
+ fadeOutFakeTaskView(true, () ->
+ showFeedback(R.string.home_gesture_feedback_overview_detected));
break;
case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
+ case HOME_OR_OVERVIEW_CANCELLED:
+ fadeOutFakeTaskView(false, null);
showFeedback(R.string.home_gesture_feedback_wrong_swipe_direction);
break;
}
@@ -112,4 +120,5 @@
break;
}
}
+
}
diff --git a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
index 6d8caa2..4069c09 100644
--- a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
+++ b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
@@ -17,6 +17,7 @@
import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.HOME_GESTURE_COMPLETED;
import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.HOME_NOT_STARTED_TOO_FAR_FROM_EDGE;
+import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.HOME_OR_OVERVIEW_CANCELLED;
import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION;
import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.OVERVIEW_GESTURE_COMPLETED;
import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE;
@@ -24,19 +25,23 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Point;
+import android.graphics.PointF;
import android.view.Display;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.view.View.OnTouchListener;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.ResourceUtils;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.util.NavBarPosition;
import com.android.quickstep.util.TriggerSwipeUpTouchTracker;
/** Utility class to handle home gestures. */
-public class NavBarGestureHandler implements OnTouchListener {
+public class NavBarGestureHandler implements OnTouchListener,
+ TriggerSwipeUpTouchTracker.OnSwipeUpListener {
private static final String LOG_TAG = "NavBarGestureHandler";
@@ -44,6 +49,7 @@
private final TriggerSwipeUpTouchTracker mSwipeUpTouchTracker;
private int mBottomGestureHeight;
private boolean mTouchCameFromNavBar;
+ private float mDownY;
private NavBarGestureAttemptCallback mGestureCallback;
NavBarGestureHandler(Context context) {
@@ -55,10 +61,11 @@
displayRotation = display.getRotation();
display.getRealSize(mDisplaySize);
}
+ mDownY = mDisplaySize.y;
mSwipeUpTouchTracker =
new TriggerSwipeUpTouchTracker(context, true /*disableHorizontalSwipe*/,
new NavBarPosition(Mode.NO_BUTTON, displayRotation),
- null /*onInterceptTouch*/, this::onSwipeUp);
+ null /*onInterceptTouch*/, this);
final Resources resources = context.getResources();
mBottomGestureHeight =
@@ -73,16 +80,26 @@
mGestureCallback = null;
}
- private void onSwipeUp(boolean wasFling) {
+ @Override
+ public void onSwipeUp(boolean wasFling, PointF finalVelocity) {
if (mGestureCallback == null) {
return;
}
+ finalVelocity.set(finalVelocity.x / 1000, finalVelocity.y / 1000);
if (mTouchCameFromNavBar) {
mGestureCallback.onNavBarGestureAttempted(wasFling
- ? HOME_GESTURE_COMPLETED : OVERVIEW_GESTURE_COMPLETED);
+ ? HOME_GESTURE_COMPLETED : OVERVIEW_GESTURE_COMPLETED, finalVelocity);
} else {
mGestureCallback.onNavBarGestureAttempted(wasFling
- ? HOME_NOT_STARTED_TOO_FAR_FROM_EDGE : OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE);
+ ? HOME_NOT_STARTED_TOO_FAR_FROM_EDGE : OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE,
+ finalVelocity);
+ }
+ }
+
+ @Override
+ public void onSwipeUpCancelled() {
+ if (mGestureCallback != null) {
+ mGestureCallback.onNavBarGestureAttempted(HOME_OR_OVERVIEW_CANCELLED, new PointF());
}
}
@@ -91,15 +108,22 @@
int action = motionEvent.getAction();
boolean intercepted = mSwipeUpTouchTracker.interceptedTouch();
if (action == MotionEvent.ACTION_DOWN) {
- mTouchCameFromNavBar = motionEvent.getRawY() >= mDisplaySize.y - mBottomGestureHeight;
+ mDownY = motionEvent.getY();
+ mTouchCameFromNavBar = mDownY >= mDisplaySize.y - mBottomGestureHeight;
+ if (!mTouchCameFromNavBar) {
+ mGestureCallback.setNavBarGestureProgress(null);
+ }
mSwipeUpTouchTracker.init();
} else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
if (mGestureCallback != null && !intercepted && mTouchCameFromNavBar) {
mGestureCallback.onNavBarGestureAttempted(
- HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION);
+ HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION, new PointF());
intercepted = true;
}
}
+ if (mTouchCameFromNavBar && mGestureCallback != null) {
+ mGestureCallback.setNavBarGestureProgress(motionEvent.getY() - mDownY);
+ }
mSwipeUpTouchTracker.onMotionEvent(motionEvent);
return intercepted;
}
@@ -110,12 +134,16 @@
OVERVIEW_GESTURE_COMPLETED,
HOME_NOT_STARTED_TOO_FAR_FROM_EDGE,
OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE,
- HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION // Side swipe on nav bar.
+ HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION, // Side swipe on nav bar.
+ HOME_OR_OVERVIEW_CANCELLED
}
/** Callback to let the UI react to attempted nav bar gestures. */
interface NavBarGestureAttemptCallback {
/** Called whenever any touch is completed. */
- void onNavBarGestureAttempted(NavBarGestureResult result);
+ void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity);
+
+ /** Indicates how far a touch originating in the nav bar has moved from the nav bar. */
+ void setNavBarGestureProgress(@Nullable Float displacement);
}
}
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
new file mode 100644
index 0000000..c636eba
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -0,0 +1,124 @@
+/*
+ * 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.interaction;
+
+import static com.android.quickstep.interaction.TutorialController.TutorialType.OVERVIEW_NAVIGATION_COMPLETE;
+
+import android.annotation.TargetApi;
+import android.graphics.PointF;
+import android.os.Build;
+import android.view.View;
+
+import com.android.launcher3.R;
+import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
+import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult;
+
+/** A {@link TutorialController} for the Overview tutorial. */
+@TargetApi(Build.VERSION_CODES.R)
+final class OverviewGestureTutorialController extends SwipeUpGestureTutorialController {
+
+ OverviewGestureTutorialController(OverviewGestureTutorialFragment fragment,
+ TutorialType tutorialType) {
+ super(fragment, tutorialType);
+ }
+
+ @Override
+ Integer getTitleStringId() {
+ switch (mTutorialType) {
+ case OVERVIEW_NAVIGATION:
+ return R.string.overview_gesture_tutorial_playground_title;
+ case OVERVIEW_NAVIGATION_COMPLETE:
+ return R.string.gesture_tutorial_confirm_title;
+ }
+ return null;
+ }
+
+ @Override
+ Integer getSubtitleStringId() {
+ if (mTutorialType == TutorialType.OVERVIEW_NAVIGATION) {
+ return R.string.overview_gesture_tutorial_playground_subtitle;
+ }
+ return null;
+ }
+
+ @Override
+ Integer getActionButtonStringId() {
+ if (mTutorialType == OVERVIEW_NAVIGATION_COMPLETE) {
+ return R.string.gesture_tutorial_action_button_label_done;
+ }
+ return null;
+ }
+
+ @Override
+ void onActionButtonClicked(View button) {
+ mTutorialFragment.closeTutorial();
+ }
+
+ @Override
+ public void onBackGestureAttempted(BackGestureResult result) {
+ switch (mTutorialType) {
+ case OVERVIEW_NAVIGATION:
+ switch (result) {
+ case BACK_COMPLETED_FROM_LEFT:
+ case BACK_COMPLETED_FROM_RIGHT:
+ case BACK_CANCELLED_FROM_LEFT:
+ case BACK_CANCELLED_FROM_RIGHT:
+ showFeedback(R.string.overview_gesture_feedback_swipe_too_far_from_edge);
+ break;
+ }
+ break;
+ case OVERVIEW_NAVIGATION_COMPLETE:
+ if (result == BackGestureResult.BACK_COMPLETED_FROM_LEFT
+ || result == BackGestureResult.BACK_COMPLETED_FROM_RIGHT) {
+ mTutorialFragment.closeTutorial();
+ }
+ break;
+ }
+ }
+
+ @Override
+ public void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity) {
+ switch (mTutorialType) {
+ case OVERVIEW_NAVIGATION:
+ switch (result) {
+ case HOME_GESTURE_COMPLETED: {
+ animateFakeTaskViewHome(finalVelocity, () ->
+ showFeedback(R.string.overview_gesture_feedback_home_detected));
+ break;
+ }
+ case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
+ case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE:
+ showFeedback(R.string.overview_gesture_feedback_swipe_too_far_from_edge);
+ break;
+ case OVERVIEW_GESTURE_COMPLETED:
+ fadeOutFakeTaskView(true, () ->
+ mTutorialFragment.changeController(OVERVIEW_NAVIGATION_COMPLETE));
+ break;
+ case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
+ case HOME_OR_OVERVIEW_CANCELLED:
+ fadeOutFakeTaskView(false, null);
+ showFeedback(R.string.overview_gesture_feedback_wrong_swipe_direction);
+ break;
+ }
+ break;
+ case OVERVIEW_NAVIGATION_COMPLETE:
+ if (result == NavBarGestureResult.HOME_GESTURE_COMPLETED) {
+ mTutorialFragment.closeTutorial();
+ }
+ break;
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java
new file mode 100644
index 0000000..3357b70
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java
@@ -0,0 +1,37 @@
+/*
+ * 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.interaction;
+
+import com.android.launcher3.R;
+import com.android.quickstep.interaction.TutorialController.TutorialType;
+
+/** Shows the Overview gesture interactive tutorial. */
+public class OverviewGestureTutorialFragment extends TutorialFragment {
+ @Override
+ int getHandAnimationResId() {
+ return R.drawable.overview_gesture;
+ }
+
+ @Override
+ TutorialController createController(TutorialType type) {
+ return new OverviewGestureTutorialController(this, type);
+ }
+
+ @Override
+ Class<? extends TutorialController> getControllerClass() {
+ return OverviewGestureTutorialController.class;
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
new file mode 100644
index 0000000..14e00dc
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -0,0 +1,246 @@
+/*
+ * 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.interaction;
+
+import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
+import static com.android.quickstep.BaseSwipeUpHandlerV2.MAX_SWIPE_DURATION;
+import static com.android.quickstep.interaction.TutorialController.TutorialType.HOME_NAVIGATION_COMPLETE;
+import static com.android.quickstep.interaction.TutorialController.TutorialType.OVERVIEW_NAVIGATION_COMPLETE;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Insets;
+import android.graphics.Outline;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.os.Build;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.InvariantDeviceProfile;
+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.quickstep.AnimatedFloat;
+import com.android.quickstep.GestureState;
+import com.android.quickstep.OverviewComponentObserver;
+import com.android.quickstep.RecentsAnimationDeviceState;
+import com.android.quickstep.SwipeUpAnimationLogic;
+import com.android.quickstep.SwipeUpAnimationLogic.RunningWindowAnim;
+import com.android.quickstep.util.RectFSpringAnim;
+import com.android.quickstep.util.TransformParams;
+import com.android.systemui.shared.system.QuickStepContract;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
+
+@TargetApi(Build.VERSION_CODES.R)
+abstract class SwipeUpGestureTutorialController extends TutorialController {
+ private final ViewSwipeUpAnimation mViewSwipeUpAnimation;
+ private float mFakeTaskViewRadius;
+ private Rect mFakeTaskViewRect = new Rect();
+ private RunningWindowAnim mRunningWindowAnim;
+
+ SwipeUpGestureTutorialController(TutorialFragment tutorialFragment, TutorialType tutorialType) {
+ super(tutorialFragment, tutorialType);
+ RecentsAnimationDeviceState deviceState = new RecentsAnimationDeviceState(mContext);
+ OverviewComponentObserver observer = new OverviewComponentObserver(mContext, deviceState);
+ mViewSwipeUpAnimation = new ViewSwipeUpAnimation(mContext, deviceState,
+ new GestureState(observer, -1));
+ observer.onDestroy();
+ deviceState.destroy();
+
+ DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext)
+ .getDeviceProfile(mContext)
+ .copy(mContext);
+ Insets insets = mContext.getSystemService(WindowManager.class)
+ .getCurrentWindowMetrics()
+ .getWindowInsets()
+ .getInsets(WindowInsets.Type.systemBars());
+ dp.updateInsets(new Rect(insets.left, insets.top, insets.right, insets.bottom));
+ mViewSwipeUpAnimation.initDp(dp);
+
+ mFakeTaskViewRadius = QuickStepContract.getWindowCornerRadius(mContext.getResources());
+ mFakeTaskView.setClipToOutline(true);
+ mFakeTaskView.setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRoundRect(mFakeTaskViewRect, mFakeTaskViewRadius);
+ }
+ });
+ }
+
+ private void cancelRunningAnimation() {
+ if (mRunningWindowAnim != null) {
+ mRunningWindowAnim.cancel();
+ }
+ mRunningWindowAnim = null;
+ }
+
+ /** Fades the task view, optionally after animating to a fake Overview. */
+ void fadeOutFakeTaskView(boolean toOverviewFirst, @Nullable Runnable onEndRunnable) {
+ hideFeedback();
+ hideHandCoachingAnimation();
+ cancelRunningAnimation();
+ PendingAnimation anim = new PendingAnimation(300);
+ AnimatorListenerAdapter resetTaskView = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation, boolean isReverse) {
+ mFakeTaskView.setVisibility(View.INVISIBLE);
+ mFakeTaskView.setAlpha(1);
+ mRunningWindowAnim = null;
+ }
+ };
+ if (toOverviewFirst) {
+ anim.setFloat(mViewSwipeUpAnimation.getCurrentShift(), AnimatedFloat.VALUE, 1, ACCEL);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation, boolean isReverse) {
+ PendingAnimation fadeAnim = new PendingAnimation(300);
+ fadeAnim.setViewAlpha(mFakeTaskView, 0, ACCEL);
+ fadeAnim.addListener(resetTaskView);
+ AnimatorSet animset = fadeAnim.buildAnim();
+ animset.setStartDelay(100);
+ animset.start();
+ mRunningWindowAnim = RunningWindowAnim.wrap(animset);
+ }
+ });
+ } else {
+ anim.setViewAlpha(mFakeTaskView, 0, ACCEL);
+ anim.addListener(resetTaskView);
+ }
+ if (onEndRunnable != null) {
+ anim.addListener(AnimationSuccessListener.forRunnable(onEndRunnable));
+ }
+ AnimatorSet animset = anim.buildAnim();
+ animset.start();
+ mRunningWindowAnim = RunningWindowAnim.wrap(animset);
+ }
+
+ void animateFakeTaskViewHome(PointF finalVelocity, @Nullable Runnable onEndRunnable) {
+ hideFeedback();
+ hideHandCoachingAnimation();
+ cancelRunningAnimation();
+ RectFSpringAnim rectAnim =
+ mViewSwipeUpAnimation.handleSwipeUpToHome(finalVelocity);
+ // After home animation finishes, fade out and run onEndRunnable.
+ rectAnim.addAnimatorListener(AnimationSuccessListener.forRunnable(
+ () -> fadeOutFakeTaskView(false, onEndRunnable)));
+ mRunningWindowAnim = RunningWindowAnim.wrap(rectAnim);
+ }
+
+ @Override
+ public void setNavBarGestureProgress(@Nullable Float displacement) {
+ if (displacement == null || mTutorialType == HOME_NAVIGATION_COMPLETE
+ || mTutorialType == OVERVIEW_NAVIGATION_COMPLETE) {
+ mFakeTaskView.setVisibility(View.INVISIBLE);
+ } else {
+ mFakeTaskView.setVisibility(View.VISIBLE);
+ if (mRunningWindowAnim == null) {
+ mViewSwipeUpAnimation.updateDisplacement(displacement);
+ }
+ }
+ }
+
+ class ViewSwipeUpAnimation extends SwipeUpAnimationLogic {
+
+ ViewSwipeUpAnimation(Context context, RecentsAnimationDeviceState deviceState,
+ GestureState gestureState) {
+ super(context, deviceState, gestureState, new FakeTransformParams());
+ }
+
+ void initDp(DeviceProfile dp) {
+ initTransitionEndpoints(dp);
+ mTaskViewSimulator.setPreviewBounds(
+ new Rect(0, 0, dp.widthPx, dp.heightPx), dp.getInsets());
+ }
+
+ @Override
+ public void updateFinalShift() {
+ float progress = mCurrentShift.value / mDragLengthFactor;
+ mWindowTransitionController.setPlayFraction(progress);
+ mTaskViewSimulator.apply(mTransformParams);
+ }
+
+ AnimatedFloat getCurrentShift() {
+ return mCurrentShift;
+ }
+
+ RectFSpringAnim handleSwipeUpToHome(PointF velocity) {
+ PointF velocityPxPerMs = new PointF(velocity.x, velocity.y);
+ float currentShift = mCurrentShift.value;
+ final float startShift = Utilities.boundToRange(currentShift - velocityPxPerMs.y
+ * getSingleFrameMs(mContext) / mTransitionDragLength, 0, mDragLengthFactor);
+ float distanceToTravel = (1 - currentShift) * mTransitionDragLength;
+
+ // we want the page's snap velocity to approximately match the velocity at
+ // which the user flings, so we scale the duration by a value near to the
+ // derivative of the scroll interpolator at zero, ie. 2.
+ long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs.y));
+ long duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
+ HomeAnimationFactory homeAnimFactory = new HomeAnimationFactory(null) {
+ @Override
+ public AnimatorPlaybackController createActivityAnimationToHome() {
+ return AnimatorPlaybackController.wrap(new AnimatorSet(), duration);
+ }
+
+ @NonNull
+ @Override
+ public RectF getWindowTargetRect() {
+ int fakeHomeIconSizePx = mDp.allAppsIconSizePx;
+ int fakeHomeIconLeft = (mDp.widthPx - fakeHomeIconSizePx) / 2;
+ int fakeHomeIconTop = mDp.heightPx - (mDp.allAppsCellHeightPx * 3);
+ return new RectF(fakeHomeIconLeft, fakeHomeIconTop,
+ fakeHomeIconLeft + fakeHomeIconSizePx,
+ fakeHomeIconTop + fakeHomeIconSizePx);
+ }
+ };
+ RectFSpringAnim windowAnim = createWindowAnimationToHome(startShift, homeAnimFactory);
+ windowAnim.start(mContext, velocityPxPerMs);
+ return windowAnim;
+ }
+ }
+
+ private class FakeTransformParams extends TransformParams {
+
+ @Override
+ public SurfaceParams[] createSurfaceParams(BuilderProxy proxy) {
+ SurfaceParams.Builder builder = new SurfaceParams.Builder((SurfaceControl) null);
+ proxy.onBuildTargetParams(builder, null, this);
+ return new SurfaceParams[] {builder.build()};
+ }
+
+ @Override
+ public void applySurfaceParams(SurfaceParams[] params) {
+ SurfaceParams p = params[0];
+ mFakeTaskView.setAnimationMatrix(p.matrix);
+ mFakeTaskViewRect.set(p.windowCrop);
+ mFakeTaskViewRadius = p.cornerRadius;
+ mFakeTaskView.invalidateOutline();
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 1e29f44..511c8b6 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -15,6 +15,7 @@
*/
package com.android.quickstep.interaction;
+import android.content.Context;
import android.graphics.drawable.RippleDrawable;
import android.view.View;
import android.view.View.OnClickListener;
@@ -39,11 +40,13 @@
final TutorialFragment mTutorialFragment;
TutorialType mTutorialType;
+ final Context mContext;
final ImageButton mCloseButton;
final TextView mTitleTextView;
final TextView mSubtitleTextView;
final TextView mFeedbackView;
+ final View mFakeTaskView;
final View mRippleView;
final RippleDrawable mRippleDrawable;
final TutorialHandAnimation mHandCoachingAnimation;
@@ -55,6 +58,7 @@
TutorialController(TutorialFragment tutorialFragment, TutorialType tutorialType) {
mTutorialFragment = tutorialFragment;
mTutorialType = tutorialType;
+ mContext = mTutorialFragment.getContext();
View rootView = tutorialFragment.getRootView();
mCloseButton = rootView.findViewById(R.id.gesture_tutorial_fragment_close_button);
@@ -62,6 +66,7 @@
mTitleTextView = rootView.findViewById(R.id.gesture_tutorial_fragment_title_view);
mSubtitleTextView = rootView.findViewById(R.id.gesture_tutorial_fragment_subtitle_view);
mFeedbackView = rootView.findViewById(R.id.gesture_tutorial_fragment_feedback_view);
+ mFakeTaskView = rootView.findViewById(R.id.gesture_tutorial_fake_task_view);
mRippleView = rootView.findViewById(R.id.gesture_tutorial_ripple_view);
mRippleDrawable = (RippleDrawable) mRippleView.getBackground();
mHandCoachingAnimation = tutorialFragment.getHandAnimation();
@@ -135,6 +140,9 @@
void onActionTextButtonClicked(View button) {}
void showHandCoachingAnimation() {
+ if (isComplete()) {
+ return;
+ }
mHandCoachingAnimation.startLoopedAnimation(mTutorialType);
}
@@ -148,6 +156,12 @@
hideFeedback();
updateTitles();
updateActionButtons();
+
+ if (isComplete()) {
+ hideHandCoachingAnimation();
+ } else {
+ showHandCoachingAnimation();
+ }
}
private void updateTitles() {
@@ -185,12 +199,20 @@
button.setOnClickListener(listener);
}
+ private boolean isComplete() {
+ return mTutorialType == TutorialType.BACK_NAVIGATION_COMPLETE
+ || mTutorialType == TutorialType.HOME_NAVIGATION_COMPLETE
+ || mTutorialType == TutorialType.OVERVIEW_NAVIGATION_COMPLETE;
+ }
+
/** Denotes the type of the tutorial. */
enum TutorialType {
RIGHT_EDGE_BACK_NAVIGATION,
LEFT_EDGE_BACK_NAVIGATION,
BACK_NAVIGATION_COMPLETE,
HOME_NAVIGATION,
- HOME_NAVIGATION_COMPLETE
+ HOME_NAVIGATION_COMPLETE,
+ OVERVIEW_NAVIGATION,
+ OVERVIEW_NAVIGATION_COMPLETE
}
}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
index 44c1a5d..da6815d 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
@@ -37,11 +37,6 @@
abstract class TutorialFragment extends Fragment implements OnTouchListener {
private static final String LOG_TAG = "TutorialFragment";
- private static final String SYSTEM_NAVIGATION_SETTING_INTENT =
- "#Intent;action=com.android.settings.SEARCH_RESULT_TRAMPOLINE;S"
- + ".:settings:fragment_args_key=gesture_system_navigation_input_summary;S"
- + ".:settings:show_fragment=com.android.settings.gestures"
- + ".SystemNavigationGestureSettings;end";
static final String KEY_TUTORIAL_TYPE = "tutorial_type";
TutorialType mTutorialType;
@@ -73,6 +68,9 @@
case HOME_NAVIGATION:
case HOME_NAVIGATION_COMPLETE:
return new HomeGestureTutorialFragment();
+ case OVERVIEW_NAVIGATION:
+ case OVERVIEW_NAVIGATION_COMPLETE:
+ return new OverviewGestureTutorialFragment();
default:
Log.e(LOG_TAG, "Failed to find an appropriate fragment for " + tutorialType.name());
}
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index 69812b6..d4d46fb 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -65,10 +65,10 @@
}
/**
- * Logs a {@link LauncherEvent}.
+ * Logs a {@link EventEnum}.
*/
@Override
- public void log(LauncherEvent event) {
+ public void log(EventEnum event) {
log(event, DEFAULT_INSTANCE_ID, LauncherAtom.ItemInfo.getDefaultInstance());
}
@@ -76,7 +76,7 @@
* Logs an event and accompanying {@link InstanceId}.
*/
@Override
- public void log(LauncherEvent event, InstanceId instanceId) {
+ public void log(EventEnum event, InstanceId instanceId) {
log(event, instanceId, LauncherAtom.ItemInfo.getDefaultInstance());
}
@@ -84,7 +84,7 @@
* Logs an event and accompanying {@link ItemInfo}.
*/
@Override
- public void log(LauncherEvent event, @Nullable LauncherAtom.ItemInfo info) {
+ public void log(EventEnum event, @Nullable LauncherAtom.ItemInfo info) {
log(event, DEFAULT_INSTANCE_ID, info);
}
@@ -92,7 +92,7 @@
* Logs an event and accompanying {@link InstanceId} and {@link LauncherAtom.ItemInfo}.
*/
@Override
- public void log(LauncherEvent event, InstanceId instanceId,
+ public void log(EventEnum event, InstanceId instanceId,
@Nullable LauncherAtom.ItemInfo info) {
logInternal(event, instanceId, info,
LAUNCHER_UICHANGED__DST_STATE__HOME,
@@ -102,14 +102,17 @@
/**
* Logs an event and accompanying {@link InstanceId} and {@link LauncherAtom.ItemInfo}.
*/
- private void logInternal(LauncherEvent event, InstanceId instanceId,
+ private void logInternal(EventEnum event, InstanceId instanceId,
@Nullable LauncherAtom.ItemInfo info, int startState, int endState) {
info = info == null ? LauncherAtom.ItemInfo.getDefaultInstance() : info;
if (IS_VERBOSE) {
+ String name = (event instanceof LauncherEvent) ? ((LauncherEvent) event).name() :
+ event.getId() + "";
+
Log.d(TAG, instanceId == DEFAULT_INSTANCE_ID
- ? String.format("\n%s\n%s", event.name(), info)
- : String.format("%s(InstanceId:%s)\n%s", event.name(), instanceId, info));
+ ? String.format("\n%s\n%s", name, info)
+ : String.format("%s(InstanceId:%s)\n%s", name, instanceId, info));
}
if (!Utilities.ATLEAST_R) {
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index 5745990..498c232 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -208,7 +208,7 @@
mDisplayRotation = displayRotation;
mTouchRotation = touchRotation;
- if (mLauncherRotation == mTouchRotation) {
+ if (mLauncherRotation == mTouchRotation || canLauncherRotate()) {
mOrientationHandler = PagedOrientationHandler.HOME_ROTATED;
if (DEBUG) {
Log.d(TAG, "current RecentsOrientedState: " + this);
@@ -240,7 +240,7 @@
private void setFlag(int mask, boolean enabled) {
boolean wasRotationEnabled = !TestProtocol.sDisableSensorRotation
- && mFlags == VALUE_ROTATION_WATCHER_ENABLED;
+ && (mFlags & VALUE_ROTATION_WATCHER_ENABLED) == VALUE_ROTATION_WATCHER_ENABLED;
if (enabled) {
mFlags |= mask;
} else {
@@ -248,7 +248,7 @@
}
boolean isRotationEnabled = !TestProtocol.sDisableSensorRotation
- && mFlags == VALUE_ROTATION_WATCHER_ENABLED;
+ && (mFlags & VALUE_ROTATION_WATCHER_ENABLED) == VALUE_ROTATION_WATCHER_ENABLED;
if (wasRotationEnabled != isRotationEnabled) {
UI_HELPER_EXECUTOR.execute(() -> {
if (isRotationEnabled) {
diff --git a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
index 34eb7f8..79ddf7a 100644
--- a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
+++ b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
@@ -58,9 +58,9 @@
}
@Test
- public void onTaskRemoved_reloadsAllTasks() {
+ public void onTaskRemoved_doesNotFetchTasks() {
mRecentTasksList.onTaskRemoved(0);
- verify(mockActivityManagerWrapper, times(1))
+ verify(mockActivityManagerWrapper, times(0))
.getRecentTasks(anyInt(), anyInt());
}
@@ -77,7 +77,7 @@
when(mockActivityManagerWrapper.getRecentTasks(anyInt(), anyInt()))
.thenReturn(Collections.singletonList(recentTaskInfo));
- List<Task> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, true);
+ List<Task> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, -1, true);
assertEquals(1, taskList.size());
assertNull(taskList.get(0).taskDescription.getLabel());
@@ -91,7 +91,7 @@
when(mockActivityManagerWrapper.getRecentTasks(anyInt(), anyInt()))
.thenReturn(Collections.singletonList(recentTaskInfo));
- List<Task> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, false);
+ List<Task> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, -1, false);
assertEquals(1, taskList.size());
assertEquals(taskDescription, taskList.get(0).taskDescription.getLabel());
diff --git a/res/values/colors.xml b/res/values/colors.xml
index c9c893e..c4ec7dd 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -43,6 +43,7 @@
<color name="gesture_tutorial_subtitle_color">#99000000</color> <!-- 60% black -->
<color name="gesture_tutorial_feedback_color">#FF000000</color>
<color name="gesture_tutorial_ripple_color">#A0C2F9</color> <!-- Light Blue -->
+ <color name="gesture_tutorial_fake_task_view_color">#6DA1FF</color> <!-- Light Blue -->
<color name="gesture_tutorial_action_button_label_color">#FFFFFFFF</color>
<color name="gesture_tutorial_primary_color">#1A73E8</color> <!-- Blue -->
diff --git a/robolectric_tests/config/robolectric.properties b/robolectric_tests/config/robolectric.properties
index c162255..b171712 100644
--- a/robolectric_tests/config/robolectric.properties
+++ b/robolectric_tests/config/robolectric.properties
@@ -13,6 +13,6 @@
com.android.launcher3.shadows.ShadowLooperExecutor \
com.android.launcher3.shadows.ShadowMainThreadInitializedObject \
com.android.launcher3.shadows.ShadowOverrides \
- com.android.launcher3.shadows.ShadowSyncRtSurfaceTransactionApplierCompat \
+ com.android.launcher3.shadows.ShadowSurfaceTransactionApplier \
application=com.android.launcher3.util.LauncherTestApplication
\ No newline at end of file
diff --git a/robolectric_tests/src/com/android/launcher3/shadows/ShadowSyncRtSurfaceTransactionApplierCompat.java b/robolectric_tests/src/com/android/launcher3/shadows/ShadowSurfaceTransactionApplier.java
similarity index 83%
rename from robolectric_tests/src/com/android/launcher3/shadows/ShadowSyncRtSurfaceTransactionApplierCompat.java
rename to robolectric_tests/src/com/android/launcher3/shadows/ShadowSurfaceTransactionApplier.java
index 238926c..a9f2f27 100644
--- a/robolectric_tests/src/com/android/launcher3/shadows/ShadowSyncRtSurfaceTransactionApplierCompat.java
+++ b/robolectric_tests/src/com/android/launcher3/shadows/ShadowSurfaceTransactionApplier.java
@@ -26,11 +26,11 @@
import org.robolectric.annotation.RealObject;
/**
- * Shadow for SyncRtSurfaceTransactionApplierCompat to override default functionality
+ * Shadow for SurfaceTransactionApplier to override default functionality
*/
-@Implements(className = "com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat",
+@Implements(className = "com.android.quickstep.util.SurfaceTransactionApplier",
isInAndroidSdk = false)
-public class ShadowSyncRtSurfaceTransactionApplierCompat {
+public class ShadowSurfaceTransactionApplier {
@RealObject
private Object mRealObject;
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 8951674..60abc66 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -200,7 +200,7 @@
DefaultDisplay.INSTANCE.get(context).getInfo(),
getPredefinedDeviceProfiles(context, gridName));
- Info myInfo = new Info(display);
+ Info myInfo = new Info(context, display);
DisplayOption myDisplayOption = invDistWeightedInterpolate(
myInfo, getPredefinedDeviceProfiles(context, gridName));
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index c30c401..2a5ee00 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -159,9 +159,9 @@
public static final int CONTAINER_HOTSEAT_PREDICTION = -103;
public static final int CONTAINER_ALL_APPS = -104;
public static final int CONTAINER_WIDGETS_TRAY = -105;
-
// Represents search results view.
public static final int CONTAINER_SEARCH_RESULTS = -106;
+ public static final int CONTAINER_SHORTCUTS = -107;
public static final String containerToString(int container) {
switch (container) {
@@ -171,6 +171,7 @@
case CONTAINER_ALL_APPS: return "all_apps";
case CONTAINER_WIDGETS_TRAY: return "widgets_tray";
case CONTAINER_SEARCH_RESULTS: return "search_result";
+ case CONTAINER_SHORTCUTS: return "shortcuts";
default: return String.valueOf(container);
}
}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index f7fe535..fdf0ea4 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -466,6 +466,7 @@
if (!isEmpty(firstLabel)) {
mFolderName.setHint("");
mFolderName.setText(firstLabel);
+ mFolderName.selectAll();
}
}
mFolderName.showKeyboard();
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 4c2c79d..85013d7 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -32,7 +32,7 @@
*/
public class StatsLogManager implements ResourceBasedOverride {
- interface EventEnum {
+ public interface EventEnum {
int getId();
}
@@ -63,6 +63,18 @@
+ "new/same value.")
LAUNCHER_FOLDER_LABEL_UPDATED(460),
+ @UiEvent(doc = "User long pressed on the workspace empty space.")
+ LAUNCHER_WORKSPACE_LONGPRESS(461),
+
+ @UiEvent(doc = "User tapped or long pressed on a wallpaper icon inside launcher settings.")
+ LAUNCHER_WALLPAPER_BUTTON_TAP_OR_LONGPRESS(462),
+
+ @UiEvent(doc = "User tapped or long pressed on settings icon inside launcher settings.")
+ LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS(463),
+
+ @UiEvent(doc = "User tapped or long pressed on widget tray icon inside launcher settings.")
+ LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS(464),
+
@UiEvent(doc = "A dragged item is dropped on 'Remove' button in the target bar")
LAUNCHER_ITEM_DROPPED_ON_REMOVE(465),
@@ -82,7 +94,25 @@
@UiEvent(doc = "User cancelled uninstalling the package after dropping on "
+ "the icon onto 'Uninstall' button in the target bar")
- LAUNCHER_ITEM_UNINSTALL_CANCELLED(470);
+ LAUNCHER_ITEM_UNINSTALL_CANCELLED(470),
+
+ @UiEvent(doc = "User tapped or long pressed on the task icon(aka package icon) "
+ + "from overview to open task menu.")
+ LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS(517),
+
+ @UiEvent(doc = "User opened package specific widgets list by tapping on widgets system "
+ + "shortcut within longpress popup window.")
+ LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP(514),
+
+ @UiEvent(doc = "User opened app info of the package by tapping on appinfo system shortcut "
+ + "within longpress popup window.")
+ LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP(515),
+
+ @UiEvent(doc = "User tapped on split screen icon on a task menu.")
+ LAUNCHER_SYSTEM_SHORTCUT_SPLIT_SCREEN_TAP(518),
+
+ @UiEvent(doc = "User tapped on free form icon on a task menu.")
+ LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP(519);
// ADD MORE
private final int mId;
@@ -113,27 +143,27 @@
}
/**
- * Logs a {@link LauncherEvent}.
+ * Logs a {@link EventEnum}.
*/
- public void log(LauncherEvent event) {
+ public void log(EventEnum event) {
}
/**
* Logs an event and accompanying {@link InstanceId}.
*/
- public void log(LauncherEvent event, InstanceId instanceId) {
+ public void log(EventEnum event, InstanceId instanceId) {
}
/**
* Logs an event and accompanying {@link ItemInfo}.
*/
- public void log(LauncherEvent event, @Nullable ItemInfo info) {
+ public void log(EventEnum event, @Nullable ItemInfo itemInfo) {
}
/**
* Logs an event and accompanying {@link InstanceId} and {@link ItemInfo}.
*/
- public void log(LauncherEvent event, InstanceId instanceId, @Nullable ItemInfo info) {
+ public void log(EventEnum event, InstanceId instanceId, @Nullable ItemInfo itemInfo) {
}
/**
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 3a89236..0c815d1 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -22,6 +22,7 @@
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SEARCH_RESULTS;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
@@ -45,6 +46,7 @@
import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
import com.android.launcher3.logger.LauncherAtom.PredictionContainer;
import com.android.launcher3.logger.LauncherAtom.SearchResultContainer;
+import com.android.launcher3.logger.LauncherAtom.ShortcutsContainer;
import com.android.launcher3.util.ContentWriter;
import java.util.Optional;
@@ -363,6 +365,10 @@
return ContainerInfo.newBuilder()
.setSearchResultContainer(SearchResultContainer.getDefaultInstance())
.build();
+ case CONTAINER_SHORTCUTS:
+ return ContainerInfo.newBuilder()
+ .setShortcutsContainer(ShortcutsContainer.getDefaultInstance())
+ .build();
}
return ContainerInfo.getDefaultInstance();
}
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 331298f..614cf14 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -16,6 +16,7 @@
package com.android.launcher3.popup;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.Utilities.squaredTouchSlop;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
@@ -61,6 +62,7 @@
import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.notification.NotificationInfo;
import com.android.launcher3.notification.NotificationItemView;
import com.android.launcher3.notification.NotificationKeyData;
@@ -675,8 +677,10 @@
iconShift.y = mIconLastTouchPos.y - mLauncher.getDeviceProfile().iconSizePx;
DraggableView draggableView = DraggableView.ofType(DraggableView.DRAGGABLE_ICON);
+ WorkspaceItemInfo itemInfo = sv.getFinalInfo();
+ itemInfo.container = CONTAINER_SHORTCUTS;
DragView dv = mLauncher.getWorkspace().beginDragShared(sv.getIconView(), draggableView,
- mContainer, sv.getFinalInfo(),
+ mContainer, itemInfo,
new ShortcutDragPreviewProvider(sv.getIconView(), iconShift),
new DragOptions());
dv.animateShift(-iconShift.x, -iconShift.y);
diff --git a/src/com/android/launcher3/popup/PopupPopulator.java b/src/com/android/launcher3/popup/PopupPopulator.java
index 7da86cc..6d3bc14 100644
--- a/src/com/android/launcher3/popup/PopupPopulator.java
+++ b/src/com/android/launcher3/popup/PopupPopulator.java
@@ -16,6 +16,8 @@
package com.android.launcher3.popup;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS;
+
import android.content.ComponentName;
import android.content.pm.ShortcutInfo;
import android.os.Handler;
@@ -160,6 +162,7 @@
final WorkspaceItemInfo si = new WorkspaceItemInfo(shortcut, launcher);
cache.getUnbadgedShortcutIcon(si, shortcut);
si.rank = i;
+ si.container = CONTAINER_SHORTCUTS;
final DeepShortcutView view = shortcutViews.get(i);
uiHandler.post(() -> view.applyShortcutInfo(si, shortcut, container));
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index ae35d4c..58ed5e8 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -1,5 +1,7 @@
package com.android.launcher3.popup;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP;
import android.app.ActivityOptions;
import android.content.Context;
@@ -103,7 +105,6 @@
};
public static class Widgets extends SystemShortcut<Launcher> {
-
public Widgets(Launcher target, ItemInfo itemInfo) {
super(R.drawable.ic_widget, R.string.widget_button_text, target, itemInfo);
}
@@ -117,6 +118,9 @@
widgetsBottomSheet.populateAndShow(mItemInfo);
mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
ControlType.WIDGETS_BUTTON, view);
+ // TODO(thiruram): Fix missing container info when item is inside folder.
+ mTarget.getStatsLogManager().log(LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP,
+ mItemInfo.buildProto());
}
}
@@ -137,6 +141,9 @@
mItemInfo, sourceBounds, ActivityOptions.makeBasic().toBundle());
mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
ControlType.APPINFO_TARGET, view);
+ // TODO(thiruram): Fix missing container info when item is inside folder.
+ mTarget.getStatsLogManager().log(LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP,
+ mItemInfo.buildProto());
}
}
diff --git a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
index 5bf9173..e80ee2c 100644
--- a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
+++ b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
@@ -237,6 +237,15 @@
return true;
});
sandboxCategory.addPreference(launchHomeTutorialPreference);
+ Preference launchOverviewTutorialPreference = new Preference(context);
+ launchOverviewTutorialPreference.setKey("launchOverviewTutorial");
+ launchOverviewTutorialPreference.setTitle("Launch Overview Tutorial");
+ launchOverviewTutorialPreference.setSummary("Learn how to use the Overview gesture");
+ launchOverviewTutorialPreference.setOnPreferenceClickListener(preference -> {
+ startActivity(launchSandboxIntent.putExtra("tutorial_type", "OVERVIEW_NAVIGATION"));
+ return true;
+ });
+ sandboxCategory.addPreference(launchOverviewTutorialPreference);
}
private String toName(String action) {
diff --git a/src/com/android/launcher3/states/StateAnimationConfig.java b/src/com/android/launcher3/states/StateAnimationConfig.java
index 1c49867..f90ad3c 100644
--- a/src/com/android/launcher3/states/StateAnimationConfig.java
+++ b/src/com/android/launcher3/states/StateAnimationConfig.java
@@ -69,7 +69,8 @@
ANIM_ALL_APPS_FADE,
ANIM_OVERVIEW_SCRIM_FADE,
ANIM_ALL_APPS_HEADER_FADE,
- ANIM_OVERVIEW_MODAL
+ ANIM_OVERVIEW_MODAL,
+ ANIM_DEPTH,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AnimType {}
@@ -87,8 +88,9 @@
public static final int ANIM_OVERVIEW_SCRIM_FADE = 11;
public static final int ANIM_ALL_APPS_HEADER_FADE = 12; // e.g. predictions
public static final int ANIM_OVERVIEW_MODAL = 13;
+ public static final int ANIM_DEPTH = 14;
- private static final int ANIM_TYPES_COUNT = 14;
+ private static final int ANIM_TYPES_COUNT = 15;
private final Interpolator[] mInterpolators = new Interpolator[ANIM_TYPES_COUNT];
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 44eae56..519b1b9 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -101,4 +101,5 @@
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";
+ public static final String NO_SWIPE_TO_HOME = "b/158017601";
}
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index e6de06d..7270ce2 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -22,6 +22,7 @@
import static android.view.MotionEvent.ACTION_UP;
import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORKSPACE_LONGPRESS;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -41,8 +42,6 @@
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.views.OptionsPopupView;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
/**
* Helper class to handle touch on empty space in workspace and show options popup on long press
@@ -175,9 +174,7 @@
mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
- mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS,
- Action.Direction.NONE, ContainerType.WORKSPACE,
- mWorkspace.getCurrentPage());
+ mLauncher.getStatsLogManager().log(LAUNCHER_WORKSPACE_LONGPRESS);
OptionsPopupView.showDefaultOptions(mLauncher, mTouchDownPoint.x, mTouchDownPoint.y);
} else {
cancelLongPress();
diff --git a/src/com/android/launcher3/util/DefaultDisplay.java b/src/com/android/launcher3/util/DefaultDisplay.java
index fabdb4e..150fb5b 100644
--- a/src/com/android/launcher3/util/DefaultDisplay.java
+++ b/src/com/android/launcher3/util/DefaultDisplay.java
@@ -145,10 +145,11 @@
}
private Info(Context context) {
- this(context.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY));
+ this(context, context.getSystemService(DisplayManager.class)
+ .getDisplay(DEFAULT_DISPLAY));
}
- public Info(Display display) {
+ public Info(Context context, Display display) {
id = display.getDisplayId();
rotation = display.getRotation();
@@ -161,8 +162,8 @@
display.getRealSize(realSize);
display.getCurrentSizeRange(smallestSize, largestSize);
- metrics = new DisplayMetrics();
- display.getMetrics(metrics);
+ Context defaultDisplayContext = context.createDisplayContext(display);
+ metrics = defaultDisplayContext.getResources().getDisplayMetrics();
}
private boolean hasDifferentSize(Info info) {
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index 6915953..c37c47c 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -181,6 +181,11 @@
}
private TouchController findControllerToHandleTouch(MotionEvent ev) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "findControllerToHandleTouch ev=" + ev
+ + ", isEventInLauncher=" + isEventInLauncher(ev)
+ + ", topOpenView=" + AbstractFloatingView.getTopOpenView(mActivity));
+ }
if (isEventInLauncher(ev)) {
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
if (topView != null && topView.onControllerInterceptTouchEvent(ev)) {
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index bd12e06..177aff4 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -59,6 +59,7 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.shortcuts.DeepShortcutView;
+import com.android.launcher3.testing.TestProtocol;
/**
* A view that is created to look like another view with the purpose of creating fluid animations.
@@ -560,6 +561,11 @@
view.setVisibility(INVISIBLE);
parent.addView(view);
dragLayer.addView(view.mListenerView);
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "getFloatingIconView. listenerView "
+ + "added to dragLayer. listenerView=" + view.mListenerView + ", fiv=" + view,
+ new Exception());
+ }
view.mListenerView.setListener(view::fastFinish);
view.mEndRunnable = () -> {
@@ -639,6 +645,10 @@
private void finish(DragLayer dragLayer) {
((ViewGroup) dragLayer.getParent()).removeView(this);
dragLayer.removeView(mListenerView);
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "listenerView removed from dragLayer. "
+ + "listenerView=" + mListenerView + ", fiv=" + this, new Exception());
+ }
recycle();
mLauncher.getViewCache().recycleView(R.layout.floating_icon_view, this);
}
diff --git a/src/com/android/launcher3/views/ListenerView.java b/src/com/android/launcher3/views/ListenerView.java
index 263f7c4..575f864 100644
--- a/src/com/android/launcher3/views/ListenerView.java
+++ b/src/com/android/launcher3/views/ListenerView.java
@@ -17,18 +17,20 @@
import android.content.Context;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.testing.TestProtocol;
/**
* An invisible AbstractFloatingView that can run a callback when it is being closed.
*/
public class ListenerView extends AbstractFloatingView {
- public Runnable mCloseListener;
+ private Runnable mCloseListener;
public ListenerView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -36,12 +38,20 @@
}
public void setListener(Runnable listener) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "ListenerView setListener lv=" + this
+ + ", listener=" + listener, new Exception());
+ }
mCloseListener = listener;
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "ListenerView onAttachedToWindow lv=" + this,
+ new Exception());
+ }
mIsOpen = true;
}
@@ -49,10 +59,19 @@
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mIsOpen = false;
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "ListenerView onDetachedFromView lv=" + this,
+ new Exception());
+ }
}
@Override
protected void handleClose(boolean animate) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "ListenerView handeClose lv=" + this
+ + ", mIsOpen=" + mIsOpen + ", mCloseListener=" + mCloseListener
+ + ", getParent()=" + getParent(), new Exception());
+ }
if (mIsOpen) {
if (mCloseListener != null) {
mCloseListener.run();
@@ -77,6 +96,10 @@
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PAUSE_NOT_DETECTED, "ListenerView touchEvent lv=" + this
+ + ", ev=" + ev, new Exception());
+ }
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
handleClose(false);
}
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index d5c3c1d..7467186 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -17,6 +17,9 @@
import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_FLAVOR;
import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_OFFSET;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WALLPAPER_BUTTON_TAP_OR_LONGPRESS;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS;
import android.content.Context;
import android.content.Intent;
@@ -37,13 +40,12 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.logging.StatsLogManager.EventEnum;
import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.popup.ArrowPopup;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
import com.android.launcher3.widget.WidgetsFullSheet;
import java.util.ArrayList;
@@ -68,21 +70,21 @@
@Override
public void onClick(View view) {
- handleViewClick(view, Action.Touch.TAP);
+ handleViewClick(view);
}
@Override
public boolean onLongClick(View view) {
- return handleViewClick(view, Action.Touch.LONGPRESS);
+ return handleViewClick(view);
}
- private boolean handleViewClick(View view, int action) {
+ private boolean handleViewClick(View view) {
OptionItem item = mItemMap.get(view);
if (item == null) {
return false;
}
- if (item.mControlTypeForLog > 0) {
- logTap(action, item.mControlTypeForLog);
+ if (item.mEventId.getId() > 0) {
+ mLauncher.getStatsLogManager().log(item.mEventId);
}
if (item.mClickListener.onLongClick(view)) {
close(true);
@@ -91,10 +93,6 @@
return false;
}
- private void logTap(int action, int controlType) {
- mLauncher.getUserEventDispatcher().logActionOnControl(action, controlType);
- }
-
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() != MotionEvent.ACTION_DOWN) {
@@ -159,13 +157,16 @@
int resDrawable = Utilities.existsStyleWallpapers(launcher) ?
R.drawable.ic_palette : R.drawable.ic_wallpaper;
options.add(new OptionItem(resString, resDrawable,
- ControlType.WALLPAPER_BUTTON, OptionsPopupView::startWallpaperPicker));
+ LAUNCHER_WALLPAPER_BUTTON_TAP_OR_LONGPRESS,
+ OptionsPopupView::startWallpaperPicker));
if (!WidgetsModel.GO_DISABLE_WIDGETS) {
options.add(new OptionItem(R.string.widget_button_text, R.drawable.ic_widget,
- ControlType.WIDGETS_BUTTON, OptionsPopupView::onWidgetsClicked));
+ LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS,
+ OptionsPopupView::onWidgetsClicked));
}
options.add(new OptionItem(R.string.settings_button_text, R.drawable.ic_setting,
- ControlType.SETTINGS_BUTTON, OptionsPopupView::startSettings));
+ LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS,
+ OptionsPopupView::startSettings));
show(launcher, target, options);
}
@@ -224,14 +225,14 @@
private final int mLabelRes;
private final int mIconRes;
- private final int mControlTypeForLog;
+ private final EventEnum mEventId;
private final OnLongClickListener mClickListener;
- public OptionItem(int labelRes, int iconRes, int controlTypeForLog,
+ public OptionItem(int labelRes, int iconRes, EventEnum eventId,
OnLongClickListener clickListener) {
mLabelRes = labelRes;
mIconRes = iconRes;
- mControlTypeForLog = controlTypeForLog;
+ mEventId = eventId;
mClickListener = clickListener;
}
}