Adding TaskViewSimulator for simulating taskView layout on a remote target

1. Tanslating contents of RecentsView instead of recentsView itself. When
   translating, we keep the current TaskView from moving. This allows
   the remoteTarget to follow an individual taskView.
2. Removing translationY in recentsView and setting the pivot instead
3. Using TaskViewSimulator for swipe handler. This allows using similar
   animation creation as Launcher window animation.

Change-Id: I0b7b16c367d9d8cd8dd0ed59061e46853e2f8c83
This commit is contained in:
Sunny Goyal
2020-04-01 20:13:12 -07:00
parent 0755ac908c
commit f2393f1d20
27 changed files with 796 additions and 540 deletions
@@ -30,6 +30,7 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRA
import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
import static com.android.quickstep.TaskViewUtils.getRecentsWindowAnimator;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -37,7 +38,6 @@ import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.util.FloatProperty;
import android.view.View;
import androidx.annotation.NonNull;
@@ -49,7 +49,6 @@ import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -199,11 +198,10 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti
return ObjectAnimator.ofFloat(mLauncher.getOverviewPanel(),
RecentsView.CONTENT_ALPHA, values);
case INDEX_RECENTS_TRANSLATE_X_ANIM:
PagedOrientationHandler orientationHandler =
((RecentsView)mLauncher.getOverviewPanel()).getPagedViewOrientedState()
.getOrientationHandler();
FloatProperty<View> translate = orientationHandler.getPrimaryViewTranslate();
return new SpringAnimationBuilder<>(mLauncher.getOverviewPanel(), translate)
// TODO: Do not assume motion across X axis for adjacent page
return new SpringAnimationBuilder<>(
mLauncher.getOverviewPanel(), ADJACENT_PAGE_OFFSET)
.setMinimumVisibleChange(1f / mLauncher.getOverviewPanel().getWidth())
.setDampingRatio(0.8f)
.setStiffness(250)
.setValues(values)
@@ -61,13 +61,16 @@ public class BackgroundAppState extends OverviewState {
}
@Override
public ScaleAndTranslation getOverviewScaleAndTranslation(Launcher launcher) {
public float[] getOverviewScaleAndOffset(Launcher launcher) {
return new float[] {getOverviewScale(launcher), NO_OFFSET};
}
private float getOverviewScale(Launcher launcher) {
// Initialize the recents view scale to what it would be when starting swipe up
RecentsView recentsView = launcher.getOverviewPanel();
int taskCount = recentsView.getTaskViewCount();
if (taskCount == 0) {
return super.getOverviewScaleAndTranslation(launcher);
}
if (taskCount == 0) return 1;
TaskView dummyTask;
if (recentsView.getCurrentPage() >= recentsView.getTaskViewStartIndex()) {
if (recentsView.getCurrentPage() <= taskCount - 1) {
@@ -78,8 +81,8 @@ public class BackgroundAppState extends OverviewState {
} else {
dummyTask = recentsView.getTaskViewAt(0);
}
return recentsView.getTempAppWindowAnimationHelper().updateForFullscreenOverview(dummyTask)
.getScaleAndTranslation();
return recentsView.getTempAppWindowAnimationHelper()
.updateForFullscreenOverview(dummyTask).getSrcToTargetScale();
}
@Override
@@ -24,24 +24,18 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TR
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.states.StateAnimationConfig;
public class OverviewPeekState extends OverviewState {
private static final float OVERVIEW_OFFSET = 0.7f;
public OverviewPeekState(int id) {
super(id);
}
@Override
public ScaleAndTranslation getOverviewScaleAndTranslation(Launcher launcher) {
ScaleAndTranslation result = super.getOverviewScaleAndTranslation(launcher);
result.translationX = NORMAL.getOverviewScaleAndTranslation(launcher).translationX
- launcher.getResources().getDimension(R.dimen.overview_peek_distance);
if (Utilities.isRtl(launcher.getResources())) {
result.translationX = -result.translationX;
}
return result;
public float[] getOverviewScaleAndOffset(Launcher launcher) {
return new float[] {NO_SCALE, OVERVIEW_OFFSET};
}
@Override
@@ -24,7 +24,6 @@ import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7;
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
@@ -123,8 +122,8 @@ public class OverviewState extends LauncherState {
}
@Override
public ScaleAndTranslation getOverviewScaleAndTranslation(Launcher launcher) {
return new ScaleAndTranslation(1f, 0f, 0f);
public float[] getOverviewScaleAndOffset(Launcher launcher) {
return new float[] {NO_SCALE, NO_OFFSET};
}
@Override
@@ -40,17 +40,15 @@ import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.CANCEL;
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.HIDE;
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.PEEK;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.graphics.PointF;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
import com.android.launcher3.BaseQuickstepLauncher;
@@ -59,6 +57,7 @@ import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.OverviewScrim;
import com.android.launcher3.states.StateAnimationConfig;
@@ -237,58 +236,32 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
private void setupOverviewAnimators() {
final LauncherState fromState = QUICK_SWITCH;
final LauncherState toState = OVERVIEW;
LauncherState.ScaleAndTranslation fromScaleAndTranslation = fromState
.getOverviewScaleAndTranslation(mLauncher);
LauncherState.ScaleAndTranslation toScaleAndTranslation = toState
.getOverviewScaleAndTranslation(mLauncher);
// Update RecentView's translationX to have it start offscreen.
float startScale = Utilities.mapRange(
SCALE_DOWN_INTERPOLATOR.getInterpolation(Y_ANIM_MIN_PROGRESS),
fromScaleAndTranslation.scale,
toScaleAndTranslation.scale);
fromScaleAndTranslation.translationX = mRecentsView.getOffscreenTranslationX(startScale);
// Set RecentView's initial properties.
mRecentsView.setScaleX(fromScaleAndTranslation.scale);
mRecentsView.setScaleY(fromScaleAndTranslation.scale);
mRecentsView.setTranslationX(fromScaleAndTranslation.translationX);
mRecentsView.setTranslationY(fromScaleAndTranslation.translationY);
SCALE_PROPERTY.set(mRecentsView, fromState.getOverviewScaleAndOffset(mLauncher)[0]);
ADJACENT_PAGE_OFFSET.set(mRecentsView, 1f);
mRecentsView.setContentAlpha(1);
mRecentsView.setFullscreenProgress(fromState.getOverviewFullscreenProgress());
float[] scaleAndOffset = toState.getOverviewScaleAndOffset(mLauncher);
// As we drag right, animate the following properties:
// - RecentsView translationX
// - OverviewScrim
AnimatorSet xOverviewAnim = new AnimatorSet();
xOverviewAnim.play(ObjectAnimator.ofFloat(mRecentsView, View.TRANSLATION_X,
toScaleAndTranslation.translationX));
xOverviewAnim.play(ObjectAnimator.ofFloat(
mLauncher.getDragLayer().getOverviewScrim(), OverviewScrim.SCRIM_PROGRESS,
toState.getOverviewScrimAlpha(mLauncher)));
long xAccuracy = (long) (mXRange * 2);
xOverviewAnim.setDuration(xAccuracy);
mXOverviewAnim = AnimatorPlaybackController.wrap(xOverviewAnim, xAccuracy);
PendingAnimation xAnim = new PendingAnimation((long) (mXRange * 2));
xAnim.setFloat(mRecentsView, ADJACENT_PAGE_OFFSET, scaleAndOffset[1], LINEAR);
xAnim.setFloat(mLauncher.getDragLayer().getOverviewScrim(), OverviewScrim.SCRIM_PROGRESS,
toState.getOverviewScrimAlpha(mLauncher), LINEAR);
mXOverviewAnim = xAnim.createPlaybackController();
mXOverviewAnim.dispatchOnStart();
// As we drag up, animate the following properties:
// - RecentsView translationY
// - RecentsView scale
// - RecentsView fullscreenProgress
AnimatorSet yAnimation = new AnimatorSet();
Animator translateYAnim = ObjectAnimator.ofFloat(mRecentsView, View.TRANSLATION_Y,
toScaleAndTranslation.translationY);
Animator scaleAnim = ObjectAnimator.ofFloat(mRecentsView, SCALE_PROPERTY,
toScaleAndTranslation.scale);
Animator fullscreenProgressAnim = ObjectAnimator.ofFloat(mRecentsView, FULLSCREEN_PROGRESS,
fromState.getOverviewFullscreenProgress(), toState.getOverviewFullscreenProgress());
scaleAnim.setInterpolator(SCALE_DOWN_INTERPOLATOR);
fullscreenProgressAnim.setInterpolator(SCALE_DOWN_INTERPOLATOR);
yAnimation.play(translateYAnim);
yAnimation.play(scaleAnim);
yAnimation.play(fullscreenProgressAnim);
long yAccuracy = (long) (mYRange * 2);
yAnimation.setDuration(yAccuracy);
mYOverviewAnim = AnimatorPlaybackController.wrap(yAnimation, yAccuracy);
PendingAnimation yAnim = new PendingAnimation((long) (mYRange * 2));
yAnim.setFloat(mRecentsView, SCALE_PROPERTY, scaleAndOffset[0], SCALE_DOWN_INTERPOLATOR);
yAnim.setFloat(mRecentsView, FULLSCREEN_PROGRESS,
toState.getOverviewFullscreenProgress(), SCALE_DOWN_INTERPOLATOR);
mYOverviewAnim = yAnim.createPlaybackController();
mYOverviewAnim.dispatchOnStart();
}
@@ -135,8 +135,15 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
mInputConsumer = inputConsumer;
mAppWindowAnimationHelper = new AppWindowAnimationHelper(context);
mPageSpacing = context.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing);
}
/**
* To be called at the end of constructor of subclasses. This calls various methods which can
* depend on proper class initialization.
*/
protected void initAfterSubclassConstructor() {
initTransitionEndpoints(InvariantDeviceProfile.INSTANCE.get(mContext)
.getDeviceProfile(mContext));
.getDeviceProfile(mContext));
}
protected void performHapticFeedback() {
@@ -241,6 +248,10 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
return mRecentsAnimationTargets != null && mRecentsAnimationTargets.hasTargets();
}
protected void updateSource(Rect stackBounds, RemoteAnimationTargetCompat runningTarget) {
mAppWindowAnimationHelper.updateSource(stackBounds, runningTarget);
}
@Override
public void onRecentsAnimationStart(RecentsAnimationController recentsAnimationController,
RecentsAnimationTargets targets) {
@@ -264,7 +275,7 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
dp.updateInsets(targets.homeContentInsets);
dp.updateIsSeascape(mContext);
if (runningTaskTarget != null) {
mAppWindowAnimationHelper.updateSource(overviewStackBounds, runningTaskTarget);
updateSource(overviewStackBounds, runningTaskTarget);
}
mAppWindowAnimationHelper.prepareAnimation(dp, false /* isOpening */);
@@ -314,6 +325,7 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
mTransitionDragLength = mActivityInterface.getSwipeUpDestinationAndLength(
dp, mContext, TEMP_RECT);
if (!dp.isMultiWindowMode) {
// When updating the target rect, also update the home bounds since the location on
// screen of the launcher window may be stale (position is not updated until first
@@ -409,11 +421,12 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
*/
protected void applyTransformUnchecked() {
float shift = mCurrentShift.value;
float offset = mRecentsView == null ? 0 : mRecentsView.getScrollOffset();
float offset = mRecentsView == null ? 0 : mRecentsView.getScrollOffsetScaled();
float taskSize = getOrientationHandler()
.getPrimarySize(mAppWindowAnimationHelper.getTargetRect());
float offsetScale = getTaskCurveScaleForOffset(offset, taskSize);
mTransformParams.setProgress(shift)
mTransformParams
.setProgress(shift)
.setOffset(offset)
.setOffsetScale(offsetScale)
.setTargetSet(mRecentsAnimationTargets)
@@ -129,6 +129,7 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
mEndTargetAnimationParams.put(LAST_TASK, new EndTargetAnimationParams(0, 150, 1));
mEndTargetAnimationParams.put(NEW_TASK, new EndTargetAnimationParams(0, 150, 1));
initAfterSubclassConstructor();
initStateCallbacks();
}
@@ -15,8 +15,6 @@
*/
package com.android.quickstep;
import static android.view.View.TRANSLATION_Y;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_RECENTS_FADE_ANIM;
import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_RECENTS_TRANSLATE_X_ANIM;
@@ -25,15 +23,14 @@ import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.launcher3.anim.Interpolators.INSTANT;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.LauncherSwipeHandler.RECENTS_ATTACH_DURATION;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -57,7 +54,6 @@ import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.appprediction.PredictionUiStateManager;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statehandlers.DepthController.ClampedDepthProperty;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.views.FloatingIconView;
import com.android.quickstep.SysUINavigationMode.Mode;
@@ -81,7 +77,6 @@ import java.util.function.Predicate;
*/
public final class LauncherActivityInterface implements BaseActivityInterface<Launcher> {
private Runnable mAdjustInterpolatorsRunnable;
private Pair<Float, Float> mSwipeUpPullbackStartAndMaxProgress =
BaseActivityInterface.super.getSwipeUpPullbackStartAndMaxProgress();
@@ -242,14 +237,6 @@ public final class LauncherActivityInterface implements BaseActivityInterface<La
}
}
@Override
public void adjustActivityControllerInterpolators() {
if (mAdjustInterpolatorsRunnable != null) {
mAdjustInterpolatorsRunnable.run();
mAdjustInterpolatorsRunnable = null;
}
}
@Override
public void onTransitionCancelled() {
launcher.getStateManager().goToState(startState, false /* animate */);
@@ -272,42 +259,24 @@ public final class LauncherActivityInterface implements BaseActivityInterface<La
.createStateElementAnimation(
INDEX_RECENTS_FADE_ANIM, attached ? 1 : 0);
int runningTaskIndex = recentsView.getRunningTaskIndex();
if (runningTaskIndex == recentsView.getTaskViewStartIndex()) {
// If we are on the first task (we haven't quick switched), translate recents in
// from the side. Calculate the start translation based on current scale/scroll.
float currScale = recentsView.getScaleX();
float scrollOffsetX = recentsView.getScrollOffset();
float offscreenX = recentsView.getOffscreenTranslationX(currScale);
float fromTranslation = attached ? offscreenX - scrollOffsetX : 0;
float toTranslation = attached ? 0 : offscreenX - scrollOffsetX;
launcher.getStateManager()
.cancelStateElementAnimation(INDEX_RECENTS_TRANSLATE_X_ANIM);
PagedOrientationHandler pagedOrientationHandler =
recentsView.getPagedViewOrientedState().getOrientationHandler();
if (!recentsView.isShown() && animate) {
pagedOrientationHandler
.getPrimaryViewTranslate().set(recentsView, fromTranslation);
} else {
fromTranslation =
pagedOrientationHandler.getPrimaryViewTranslate().get(recentsView);
}
if (!animate) {
pagedOrientationHandler
.getPrimaryViewTranslate().set(recentsView, toTranslation);
} else {
launcher.getStateManager().createStateElementAnimation(
INDEX_RECENTS_TRANSLATE_X_ANIM,
fromTranslation, toTranslation).start();
}
fadeAnim.setInterpolator(attached ? INSTANT : ACCEL_2);
float fromTranslation = attached ? 1 : 0;
float toTranslation = attached ? 0 : 1;
launcher.getStateManager()
.cancelStateElementAnimation(INDEX_RECENTS_TRANSLATE_X_ANIM);
if (!recentsView.isShown() && animate) {
ADJACENT_PAGE_OFFSET.set(recentsView, fromTranslation);
} else {
fadeAnim.setInterpolator(ACCEL_DEACCEL);
fromTranslation = ADJACENT_PAGE_OFFSET.get(recentsView);
}
if (!animate) {
ADJACENT_PAGE_OFFSET.set(recentsView, toTranslation);
} else {
launcher.getStateManager().createStateElementAnimation(
INDEX_RECENTS_TRANSLATE_X_ANIM,
fromTranslation, toTranslation).start();
}
fadeAnim.setInterpolator(attached ? INSTANT : ACCEL_2);
fadeAnim.setDuration(animate ? RECENTS_ATTACH_DURATION : 0).start();
}
};
@@ -365,51 +334,20 @@ public final class LauncherActivityInterface implements BaseActivityInterface<La
return;
}
LauncherState.ScaleAndTranslation fromScaleAndTranslation
= fromState.getOverviewScaleAndTranslation(launcher);
LauncherState.ScaleAndTranslation endScaleAndTranslation
= endState.getOverviewScaleAndTranslation(launcher);
float fromTranslationY = fromScaleAndTranslation.translationY;
float endTranslationY = endScaleAndTranslation.translationY;
float fromFullscreenProgress = fromState.getOverviewFullscreenProgress();
float endFullscreenProgress = endState.getOverviewFullscreenProgress();
Animator scale = ObjectAnimator.ofFloat(recentsView, SCALE_PROPERTY,
fromScaleAndTranslation.scale, endScaleAndTranslation.scale);
Animator translateY = ObjectAnimator.ofFloat(recentsView, TRANSLATION_Y,
fromTranslationY, endTranslationY);
float fromScale = fromState.getOverviewScaleAndOffset(launcher)[0];
float endScale = endState.getOverviewScaleAndOffset(launcher)[0];
Animator scale = ObjectAnimator.ofFloat(recentsView, SCALE_PROPERTY, fromScale, endScale);
Animator applyFullscreenProgress = ObjectAnimator.ofFloat(recentsView,
RecentsView.FULLSCREEN_PROGRESS, fromFullscreenProgress, endFullscreenProgress);
anim.playTogether(scale, translateY, applyFullscreenProgress);
mAdjustInterpolatorsRunnable = () -> {
// Adjust the translateY interpolator to account for the running task's top inset.
// When progress <= 1, this is handled by each task view as they set their fullscreen
// progress. However, once we go to progress > 1, fullscreen progress stays at 0, so
// recents as a whole needs to translate further to keep up with the app window.
TaskView runningTaskView = recentsView.getRunningTaskView();
if (runningTaskView == null) {
runningTaskView = recentsView.getCurrentPageTaskView();
if (runningTaskView == null) {
// There are no task views in LockTask mode when Overview is enabled.
return;
}
}
TimeInterpolator oldInterpolator = translateY.getInterpolator();
Rect fallbackInsets = launcher.getDeviceProfile().getInsets();
float extraTranslationY = runningTaskView.getThumbnail().getInsets(fallbackInsets).top;
float normalizedTranslationY = extraTranslationY / (fromTranslationY - endTranslationY);
translateY.setInterpolator(t -> {
float newT = oldInterpolator.getInterpolation(t);
return newT <= 1f ? newT : newT + normalizedTranslationY * (newT - 1);
});
};
anim.playTogether(scale, applyFullscreenProgress);
// Start pulling back when RecentsView scale is 0.75f, and let it go down to 0.5f.
float pullbackStartProgress = (0.75f - fromScaleAndTranslation.scale)
/ (endScaleAndTranslation.scale - fromScaleAndTranslation.scale);
float pullbackMaxProgress = (0.5f - fromScaleAndTranslation.scale)
/ (endScaleAndTranslation.scale - fromScaleAndTranslation.scale);
float pullbackStartProgress = (0.75f - fromScale) / (endScale - fromScale);
float pullbackMaxProgress = (0.5f - fromScale) / (endScale - fromScale);
mSwipeUpPullbackStartAndMaxProgress = new Pair<>(
pullbackStartProgress, pullbackMaxProgress);
}
@@ -17,6 +17,8 @@ package com.android.quickstep;
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
@@ -39,16 +41,17 @@ import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHO
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.view.View.OnApplyWindowInsetsListener;
import android.view.ViewTreeObserver.OnDrawListener;
@@ -67,7 +70,6 @@ import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -78,9 +80,11 @@ import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.inputconsumers.OverviewInputConsumer;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.AppWindowAnimationHelper.TargetAlphaProvider;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.ShelfPeekAnim;
import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.views.LiveTileOverlay;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -177,6 +181,9 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
private AnimatorPlaybackController mLauncherTransitionController;
private boolean mHasLauncherTransitionControllerStarted;
private final TaskViewSimulator mTaskViewSimulator;
private AnimatorPlaybackController mWindowTransitionController;
private AnimationFactory mAnimationFactory = (t) -> { };
private boolean mWasLauncherAlreadyVisible;
@@ -201,6 +208,9 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
mTaskAnimationManager = taskAnimationManager;
mTouchTimeMs = touchTimeMs;
mContinuingLastGesture = continuingLastGesture;
mTaskViewSimulator = new TaskViewSimulator(context, LayoutUtils::calculateLauncherTaskSize);
initAfterSubclassConstructor();
initStateCallbacks();
}
@@ -473,23 +483,11 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
} else if (mContinuingLastGesture
&& mRecentsView.getRunningTaskIndex() != mRecentsView.getNextPage()) {
recentsAttachedToAppWindow = true;
animate = false;
} else if (runningTaskTarget != null && isNotInRecents(runningTaskTarget)) {
// The window is going away so make sure recents is always visible in this case.
recentsAttachedToAppWindow = true;
animate = false;
} else {
recentsAttachedToAppWindow = mIsShelfPeeking || mIsLikelyToStartNewTask;
if (animate) {
// Only animate if an adjacent task view is visible on screen.
TaskView adjacentTask1 = mRecentsView.getNextTaskView();
TaskView adjacentTask2 = mRecentsView.getPreviousTaskView();
float prevTranslationX = mRecentsView.getTranslationX();
mRecentsView.setTranslationX(0);
animate = (adjacentTask1 != null && adjacentTask1.getGlobalVisibleRect(TEMP_RECT))
|| (adjacentTask2 != null && adjacentTask2.getGlobalVisibleRect(TEMP_RECT));
mRecentsView.setTranslationX(prevTranslationX);
}
}
mAnimationFactory.setRecentsAttachedToAppWindow(recentsAttachedToAppWindow, animate);
}
@@ -523,6 +521,34 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
mAnimationFactory.createActivityInterface(mTransitionDragLength);
}
@Override
protected void updateSource(Rect stackBounds, RemoteAnimationTargetCompat runningTarget) {
super.updateSource(stackBounds, runningTarget);
mTaskViewSimulator.setPreview(runningTarget, mRecentsAnimationTargets);
}
@Override
protected void initTransitionEndpoints(DeviceProfile dp) {
super.initTransitionEndpoints(dp);
mTaskViewSimulator.setDp(dp, false /* isOpening */);
mTaskViewSimulator.setLayoutRotation(
mDeviceState.getCurrentActiveRotation(),
mDeviceState.getDisplayRotation());
AnimatorSet anim = new AnimatorSet();
anim.setDuration(mTransitionDragLength * 2);
anim.setInterpolator(t -> t * mDragLengthFactor);
anim.play(ObjectAnimator.ofFloat(mTaskViewSimulator.recentsViewScale,
AnimatedFloat.VALUE,
mTaskViewSimulator.getFullScreenScale(), 1));
anim.play(ObjectAnimator.ofFloat(mTaskViewSimulator.fullScreenProgress,
AnimatedFloat.VALUE,
BACKGROUND_APP.getOverviewFullscreenProgress(),
OVERVIEW.getOverviewFullscreenProgress()));
mWindowTransitionController =
AnimatorPlaybackController.wrap(anim, mTransitionDragLength * 2);
}
/**
* We don't want to change mLauncherTransitionController if mGestureState.getEndTarget() == HOME
* (it has its own animation) or if we're already animating the current controller.
@@ -542,7 +568,6 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
private void onAnimatorPlaybackControllerCreated(AnimatorPlaybackController anim) {
mLauncherTransitionController = anim;
mLauncherTransitionController.dispatchSetInterpolator(t -> t * mDragLengthFactor);
mAnimationFactory.adjustActivityControllerInterpolators();
mLauncherTransitionController.dispatchOnStart();
updateLauncherTransitionProgress();
}
@@ -555,7 +580,9 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
@Override
public void updateFinalShift() {
if (mRecentsAnimationTargets != null) {
applyTransformUnchecked();
// Base class expects applyTransformUnchecked to be called here.
// TODO: Remove this dependency for swipe-up animation.
// applyTransformUnchecked();
updateSysUiFlags(mCurrentShift.value);
}
@@ -575,6 +602,16 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
}
}
if (mWindowTransitionController != null) {
float progress = mCurrentShift.value / mDragLengthFactor;
mWindowTransitionController.setPlayFraction(progress);
mTransformParams
.setTargetSet(mRecentsAnimationTargets)
.setLauncherOnTop(true);
mTaskViewSimulator.setScroll(mRecentsView == null ? 0 : mRecentsView.getScrollOffset());
mTaskViewSimulator.apply(mTransformParams);
}
updateLauncherTransitionProgress();
}
@@ -1020,7 +1057,6 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
mLauncherTransitionController.dispatchSetInterpolator(t -> end);
} else {
mLauncherTransitionController.dispatchSetInterpolator(adjustedInterpolator);
mAnimationFactory.adjustActivityControllerInterpolators();
}
mLauncherTransitionController.getAnimationPlayer().setDuration(Math.max(0, duration));
@@ -1296,6 +1332,7 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
private void setTargetAlphaProvider(TargetAlphaProvider provider) {
mAppWindowAnimationHelper.setTaskAlphaCallback(provider);
mTaskViewSimulator.setTaskAlphaCallback(provider);
updateFinalShift();
}
@@ -26,7 +26,6 @@ import android.util.FloatProperty;
import android.view.View;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherState.ScaleAndTranslation;
import com.android.launcher3.Utilities;
import com.android.quickstep.RecentsActivity;
import com.android.quickstep.util.LayoutUtils;
@@ -58,7 +57,6 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity> {
private boolean mInOverviewState = true;
private float mZoomScale = 1f;
private float mZoomTranslationY = 0f;
private RunningTaskInfo mRunningTaskInfo;
@@ -145,14 +143,11 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity> {
if (getTaskViewCount() == 0) {
mZoomScale = 1f;
mZoomTranslationY = 0f;
} else {
TaskView dummyTask = getTaskViewAt(0);
ScaleAndTranslation sat = getTempAppWindowAnimationHelper()
mZoomScale = getTempAppWindowAnimationHelper()
.updateForFullscreenOverview(dummyTask)
.getScaleAndTranslation();
mZoomScale = sat.scale;
mZoomTranslationY = sat.translationY;
.getSrcToTargetScale();
}
setZoomProgress(mZoomInProgress);
@@ -161,7 +156,6 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity> {
public void setZoomProgress(float progress) {
mZoomInProgress = progress;
SCALE_PROPERTY.set(this, Utilities.mapRange(mZoomInProgress, 1, mZoomScale));
TRANSLATION_Y.set(this, Utilities.mapRange(mZoomInProgress, 0, mZoomTranslationY));
FULLSCREEN_PROGRESS.set(this, mZoomInProgress);
}
@@ -30,13 +30,11 @@ import android.graphics.Matrix.ScaleToFit;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.view.Surface;
import androidx.annotation.Nullable;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
@@ -60,7 +58,7 @@ import com.android.systemui.shared.system.WindowManagerWrapper;
public class AppWindowAnimationHelper {
// The bounds of the source app in device coordinates
private final Rect mSourceStackBounds = new Rect();
private final RectF mSourceStackBounds = new RectF();
// The insets of the source app
private final Rect mSourceInsets = new Rect();
// The source app bounds with the source insets applied, in the device coordinates
@@ -159,14 +157,10 @@ public class AppWindowAnimationHelper {
mSourceRect.set(scaledTargetRect);
}
private float getSrcToTargetScale() {
if (mOrientedState == null
|| mOrientedState.isHomeRotationAllowed()
|| mOrientedState.isDisplayPhoneNatural()) {
return mSourceRect.width() / mTargetRect.width();
} else {
return mSourceRect.height() / mTargetRect.height();
}
public float getSrcToTargetScale() {
return LayoutUtils.getTaskScale(mOrientedState,
mSourceRect.width(), mSourceRect.height(),
mTargetRect.width(), mTargetRect.height());
}
public void prepareAnimation(DeviceProfile dp, boolean isOpening) {
@@ -378,15 +372,6 @@ public class AppWindowAnimationHelper {
return this;
}
/**
* @return The source rect's scale and translation relative to the target rect.
*/
public LauncherState.ScaleAndTranslation getScaleAndTranslation() {
float scale = getSrcToTargetScale();
float translationY = mSourceRect.centerY() - mSourceRect.top - mTargetRect.centerY();
return new LauncherState.ScaleAndTranslation(scale, 0, translationY);
}
private void updateStackBoundsToMultiWindowTaskSize(BaseDraggingActivity activity) {
SystemUiProxy proxy = SystemUiProxy.INSTANCE.get(activity);
if (proxy.isActive()) {
@@ -0,0 +1,284 @@
/*
* 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.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.touch.PagedOrientationHandler.MATRIX_POST_TRANSLATE;
import static com.android.quickstep.util.AppWindowAnimationHelper.applySurfaceParams;
import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_FULLSCREEN;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.RecentsAnimationTargets;
import com.android.quickstep.util.AppWindowAnimationHelper.TargetAlphaProvider;
import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams;
import com.android.quickstep.views.RecentsView.ScrollState;
import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper;
import com.android.quickstep.views.TaskView;
import com.android.quickstep.views.TaskView.FullscreenDrawParams;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
/**
* A utility class which emulates the layout behavior of TaskView and RecentsView
*/
public class TaskViewSimulator {
private final Rect mTmpCropRect = new Rect();
private final RectF mTempRectF = new RectF();
private final RecentsOrientedState mOrientationState;
private final Context mContext;
private final TaskSizeProvider mSizeProvider;
private final Rect mTaskRect = new Rect();
private final PointF mPivot = new PointF();
private DeviceProfile mDp;
private final Matrix mMatrix = new Matrix();
private RemoteAnimationTargetCompat mRunningTarget;
private RecentsAnimationTargets mAllTargets;
// Whether to boost the opening animation target layers, or the closing
private int mBoostModeTargetLayers = -1;
private TargetAlphaProvider mTaskAlphaCallback = (t, a) -> a;
// Thumbnail view properties
private final Rect mThumbnailPosition = new Rect();
private final ThumbnailData mThumbnailData = new ThumbnailData();
private final PreviewPositionHelper mPositionHelper;
private final Matrix mInversePositionMatrix = new Matrix();
// TaskView properties
private final FullscreenDrawParams mCurrentFullscreenParams;
private float mCurveScale = 1;
// RecentsView properties
public final AnimatedFloat recentsViewScale = new AnimatedFloat(() -> { });
public final AnimatedFloat fullScreenProgress = new AnimatedFloat(() -> { });
private final ScrollState mScrollState = new ScrollState();
private final int mPageSpacing;
// Cached calculations
private boolean mLayoutValid = false;
private boolean mScrollValid = false;
public TaskViewSimulator(Context context, TaskSizeProvider sizeProvider) {
mContext = context;
mSizeProvider = sizeProvider;
mPositionHelper = new PreviewPositionHelper(context);
mOrientationState = new RecentsOrientedState(context);
mCurrentFullscreenParams = new FullscreenDrawParams(context);
mPageSpacing = context.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing);
}
/**
* Sets the device profile for the current state
*/
public void setDp(DeviceProfile dp, boolean isOpening) {
mDp = dp;
mBoostModeTargetLayers = isOpening ? MODE_OPENING : MODE_CLOSING;
mLayoutValid = false;
}
/**
* @see com.android.quickstep.views.RecentsView#setLayoutRotation(int, int)
*/
public void setLayoutRotation(int touchRotation, int displayRotation) {
if (!FeatureFlags.ENABLE_FIXED_ROTATION_TRANSFORM.get()) {
return;
}
mOrientationState.update(touchRotation, displayRotation,
mOrientationState.getLauncherRotation());
mLayoutValid = false;
}
/**
* @see com.android.quickstep.views.RecentsView#FULLSCREEN_PROGRESS
*/
public float getFullScreenScale() {
if (mDp == null) {
return 1;
}
mSizeProvider.calculateTaskSize(mContext, mDp, mTaskRect);
return mOrientationState.getFullScreenScaleAndPivot(mTaskRect, mDp, mPivot);
}
/**
* Sets the targets which the simulator will control
*/
public void setPreview(
RemoteAnimationTargetCompat runningTarget, RecentsAnimationTargets allTargets) {
mRunningTarget = runningTarget;
mAllTargets = allTargets;
mThumbnailData.insets.set(mRunningTarget.contentInsets);
// TODO: What is this?
mThumbnailData.windowingMode = WINDOWING_MODE_FULLSCREEN;
mThumbnailPosition.set(runningTarget.screenSpaceBounds);
// TODO: Should sourceContainerBounds already have this offset?
mThumbnailPosition.offsetTo(mRunningTarget.position.x, mRunningTarget.position.y);
mLayoutValid = false;
}
/**
* Updates the scroll for RecentsView
*/
public void setScroll(int scroll) {
if (mScrollState.scroll != scroll) {
mScrollState.scroll = scroll;
mScrollValid = false;
}
}
/**
* Sets an alternate function which can be used to control the alpha
*/
public void setTaskAlphaCallback(TargetAlphaProvider callback) {
mTaskAlphaCallback = callback;
}
/**
* Applies the target to the previously set parameters
*/
public void apply(TransformParams params) {
if (mDp == null || mRunningTarget == null) {
return;
}
if (!mLayoutValid) {
mLayoutValid = true;
getFullScreenScale();
mThumbnailData.rotation = FeatureFlags.ENABLE_FIXED_ROTATION_TRANSFORM.get()
? mOrientationState.getDisplayRotation() : mPositionHelper.getCurrentRotation();
mPositionHelper.updateThumbnailMatrix(mThumbnailPosition, mThumbnailData,
mDp.isMultiWindowMode, mTaskRect.width(), mTaskRect.height());
mPositionHelper.getMatrix().invert(mInversePositionMatrix);
PagedOrientationHandler poh = mOrientationState.getOrientationHandler();
mScrollState.halfPageSize =
poh.getPrimaryValue(mTaskRect.width(), mTaskRect.height()) / 2;
mScrollState.halfScreenSize = poh.getPrimaryValue(mDp.widthPx, mDp.heightPx) / 2;
mScrollValid = false;
}
if (!mScrollValid) {
mScrollValid = true;
int start = mOrientationState.getOrientationHandler()
.getPrimaryValue(mTaskRect.left, mTaskRect.top);
mScrollState.screenCenter = start + mScrollState.scroll + mScrollState.halfPageSize;
mScrollState.updateInterpolation(start, mPageSpacing);
mCurveScale = TaskView.getCurveScaleForInterpolation(mScrollState.linearInterpolation);
}
float progress = Utilities.boundToRange(fullScreenProgress.value, 0, 1);
mCurrentFullscreenParams.setProgress(
progress, recentsViewScale.value, mTaskRect.width(), mDp, mPositionHelper);
// Apply thumbnail matrix
RectF insets = mCurrentFullscreenParams.mCurrentDrawnInsets;
float scale = mCurrentFullscreenParams.mScale;
float taskWidth = mTaskRect.width();
float taskHeight = mTaskRect.height();
mMatrix.set(mPositionHelper.getMatrix());
mMatrix.postScale(scale, scale);
mMatrix.postTranslate(insets.left, insets.top);
// Apply TaskView matrix: scale, translate, scroll
mMatrix.postScale(mCurveScale, mCurveScale, taskWidth / 2, taskHeight / 2);
mMatrix.postTranslate(mTaskRect.left, mTaskRect.top);
mOrientationState.getOrientationHandler().set(
mMatrix, MATRIX_POST_TRANSLATE, mScrollState.scroll);
// Apply recensView matrix
mMatrix.postScale(recentsViewScale.value, recentsViewScale.value, mPivot.x, mPivot.y);
postDisplayRotation(mOrientationState.getDisplayRotation(),
mDp.widthPx, mDp.heightPx, mMatrix);
// Crop rect is the inverse of thumbnail matrix
mTempRectF.set(-insets.left, -insets.top,
taskWidth + insets.right, taskHeight + insets.bottom);
mInversePositionMatrix.mapRect(mTempRectF);
mTempRectF.roundOut(mTmpCropRect);
SurfaceParams[] surfaceParams = new SurfaceParams[mAllTargets.unfilteredApps.length];
for (int i = 0; i < mAllTargets.unfilteredApps.length; i++) {
RemoteAnimationTargetCompat app = mAllTargets.unfilteredApps[i];
SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash)
.withLayer(RemoteAnimationProvider.getLayer(app, mBoostModeTargetLayers));
if (app.mode == mAllTargets.targetMode) {
float alpha = mTaskAlphaCallback.getAlpha(app, params.getTargetAlpha());
if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
// Fade out Assistant overlay.
if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT
&& app.isNotInRecents) {
alpha = Interpolators.ACCEL_2.getInterpolation(fullScreenProgress.value);
}
builder.withAlpha(alpha)
.withMatrix(mMatrix)
.withWindowCrop(mTmpCropRect)
.withCornerRadius(mCurrentFullscreenParams.mCurrentDrawnCornerRadius);
} else if (params.getTargetSet().hasRecents) {
// If home has a different target then recents, reverse anim the home target.
builder.withAlpha(fullScreenProgress.value * params.getTargetAlpha());
}
} else {
builder.withAlpha(1);
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && params.isLauncherOnTop()) {
builder.withLayer(Integer.MAX_VALUE);
}
}
surfaceParams[i] = builder.build();
}
applySurfaceParams(params.getSyncTransactionApplier(), surfaceParams);
}
/**
* Interface for calculating taskSize
*/
public interface TaskSizeProvider {
/**
* Sets the outRect to the expected taskSize
*/
void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect);
}
}
@@ -183,27 +183,6 @@ public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
LayoutUtils.calculateLauncherTaskSize(getContext(), dp, outRect);
}
/**
* @return The translationX to apply to this view so that the first task is just offscreen.
*/
public float getOffscreenTranslationX(float recentsScale) {
LauncherState.ScaleAndTranslation overviewScaleAndTranslation =
NORMAL.getOverviewScaleAndTranslation(mActivity);
float offscreen = mOrientationHandler.getTranslationValue(overviewScaleAndTranslation);
// Offset since scale pushes tasks outwards.
getTaskSize(sTempRect);
int taskSize = mOrientationHandler.getPrimarySize(sTempRect);
offscreen += taskSize * (recentsScale - 1) / 2;
if (mRunningTaskTileHidden) {
// The first task is hidden, so offset by its width.
offscreen -= (taskSize + getPageSpacing()) * recentsScale;
}
if (isRtl()) {
offscreen = -offscreen;
}
return offscreen;
}
@Override
protected void onTaskLaunchAnimationUpdate(float progress, TaskView tv) {
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
@@ -56,6 +56,7 @@ import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
@@ -90,7 +91,6 @@ import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherState;
import com.android.launcher3.PagedView;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -123,7 +123,6 @@ import com.android.quickstep.TaskThumbnailCache;
import com.android.quickstep.TaskUtils;
import com.android.quickstep.ViewUtils;
import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.systemui.plugins.ResourceProvider;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
@@ -175,8 +174,23 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
}
};
protected RecentsOrientedState mOrientationState;
public static final FloatProperty<RecentsView> ADJACENT_PAGE_OFFSET =
new FloatProperty<RecentsView>("adjacentPageOffset") {
@Override
public void setValue(RecentsView recentsView, float v) {
if (recentsView.mAdjacentPageOffset != v) {
recentsView.mAdjacentPageOffset = v;
recentsView.updateAdjacentPageOffset();
}
}
@Override
public Float get(RecentsView recentsView) {
return recentsView.mAdjacentPageOffset;
}
};
protected final RecentsOrientedState mOrientationState;
private OrientationEventListener mOrientationListener;
private int mPreviousRotation;
protected RecentsAnimationController mRecentsAnimationController;
@@ -188,6 +202,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
protected boolean mEnableDrawingLiveTile = false;
protected final Rect mTempRect = new Rect();
protected final RectF mTempRectF = new RectF();
private final PointF mTempPointF = new PointF();
private static final int DISMISS_TASK_DURATION = 300;
private static final int ADDITION_TASK_DURATION = 200;
@@ -198,7 +213,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
private final float mFastFlingVelocity;
private final RecentsModel mModel;
private final int mTaskTopMargin;
private final int mTaskBottomMargin;
private final ClearAllButton mClearAllButton;
private final Rect mClearAllButtonDeadZoneRect = new Rect();
private final Rect mTaskViewDeadZoneRect = new Rect();
@@ -217,6 +231,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
private boolean mOverlayEnabled;
protected boolean mFreezeViewVisibility;
private float mAdjacentPageOffset = 0;
/**
* TODO: Call reloadIdNeeded in onTaskStackChanged.
*/
@@ -352,7 +368,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
mFastFlingVelocity = getResources()
.getDimensionPixelSize(R.dimen.recents_fast_fling_velocity);
mActivity = (T) BaseActivity.fromContext(context);
mActivity = BaseActivity.fromContext(context);
mModel = RecentsModel.INSTANCE.get(context);
mIdp = InvariantDeviceProfile.INSTANCE.get(context);
mTempAppWindowAnimationHelper =
@@ -368,7 +384,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
mTaskTopMargin = getResources()
.getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
mTaskBottomMargin = LayoutUtils.thumbnailBottomMargin(context);
mSquaredTouchSlop = squaredTouchSlop(context);
mEmptyIcon = context.getDrawable(R.drawable.ic_empty_recents);
@@ -830,7 +845,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
mTaskHeight = mTempRect.height();
mTempRect.top -= mTaskTopMargin;
mTempRect.bottom += mTaskBottomMargin;
setPadding(mTempRect.left - mInsets.left, mTempRect.top - mInsets.top,
dp.widthPx - mInsets.right - mTempRect.right,
dp.heightPx - mInsets.bottom - mTempRect.bottom);
@@ -1621,11 +1635,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
return getTaskViewAtByAbsoluteIndex(getRunningTaskIndex() + 1);
}
@Nullable
public TaskView getPreviousTaskView() {
return getTaskViewAtByAbsoluteIndex(getRunningTaskIndex() - 1);
}
@Nullable
public TaskView getCurrentPageTaskView() {
return getTaskViewAtByAbsoluteIndex(getCurrentPage());
@@ -1685,11 +1694,29 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
updateEmptyStateUi(changed);
// Set the pivot points to match the task preview center
setPivotY(((mInsets.top + getPaddingTop() + mTaskTopMargin)
+ (getHeight() - mInsets.bottom - getPaddingBottom() - mTaskBottomMargin)) / 2);
setPivotX(((mInsets.left + getPaddingLeft())
+ (getWidth() - mInsets.right - getPaddingRight())) / 2);
// Update the pivots such that when the task is scaled, it fills the full page
getTaskSize(mTempRect);
getPagedViewOrientedState().getFullScreenScaleAndPivot(
mTempRect, mActivity.getDeviceProfile(), mTempPointF);
setPivotX(mTempPointF.x);
setPivotY(mTempPointF.y);
updateAdjacentPageOffset();
}
private void updateAdjacentPageOffset() {
float offset = mAdjacentPageOffset * getWidth();
if (mIsRtl) {
offset = -offset;
}
int count = getChildCount();
TaskView runningTask = mRunningTaskId == -1 ? null : getTaskView(mRunningTaskId);
int midPoint = runningTask == null ? -1 : indexOfChild(runningTask);
for (int i = 0; i < count; i++) {
getChildAt(i).setTranslationX(i == midPoint ? 0 : (i < midPoint ? -offset : offset));
}
updateCurveProperties();
}
private void updateDeadZoneRects() {
@@ -1771,14 +1798,10 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
int centerTaskIndex = getCurrentPage();
boolean launchingCenterTask = taskIndex == centerTaskIndex;
LauncherState.ScaleAndTranslation toScaleAndTranslation = appWindowAnimationHelper
.getScaleAndTranslation();
float toScale = toScaleAndTranslation.scale;
float toTranslationY = toScaleAndTranslation.translationY;
float toScale = appWindowAnimationHelper.getSrcToTargetScale();
if (launchingCenterTask) {
RecentsView recentsView = tv.getRecentsView();
anim.play(ObjectAnimator.ofFloat(recentsView, SCALE_PROPERTY, toScale));
anim.play(ObjectAnimator.ofFloat(recentsView, TRANSLATION_Y, toTranslationY));
anim.play(ObjectAnimator.ofFloat(recentsView, FULLSCREEN_PROGRESS, 1));
} else {
// We are launching an adjacent task, so parallax the center and other adjacent task.
@@ -2038,17 +2061,23 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
return mClearAllButton;
}
/**
* @return How many pixels the running task is offset on the x-axis due to the current scrollX.
*/
public float getScrollOffset() {
public int getScrollOffset() {
if (getRunningTaskIndex() == -1) {
return 0;
}
int startScroll = getScrollForPage(getRunningTaskIndex());
int offsetX = startScroll - mOrientationHandler.getPrimaryScroll(this);
offsetX *= mOrientationHandler.getPrimaryScale(this);
return offsetX;
return getScrollForPage(getRunningTaskIndex()) - mOrientationHandler.getPrimaryScroll(this);
}
/**
* @return How many pixels the running task is offset on the x-axis due to the current scrollX
* and parent scale.
*/
public float getScrollOffsetScaled() {
return getScrollOffset() * mOrientationHandler.getPrimaryScale(this);
}
public Consumer<MotionEvent> getEventDispatcher(float navbarRotation) {
@@ -36,11 +36,9 @@ import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.Log;
import android.util.Property;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.R;
@@ -50,7 +48,7 @@ import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
import com.android.quickstep.TaskOverlayFactory;
import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
import com.android.quickstep.util.TaskCornerRadius;
import com.android.quickstep.views.TaskView.FullscreenDrawParams;
import com.android.systemui.plugins.OverviewScreenshotActions;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.shared.recents.model.Task;
@@ -66,6 +64,8 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
private static final ColorMatrix SATURATION_COLOR_MATRIX = new ColorMatrix();
private static final RectF EMPTY_RECT_F = new RectF();
private static final FullscreenDrawParams TEMP_PARAMS = new FullscreenDrawParams();
public static final Property<TaskThumbnailView, Float> DIM_ALPHA =
new FloatProperty<TaskThumbnailView>("dimAlpha") {
@Override
@@ -87,12 +87,11 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
private final Paint mClearPaint = new Paint();
private final Paint mDimmingPaintAfterClearing = new Paint();
private final Matrix mMatrix = new Matrix();
private float mClipBottom = -1;
// Contains the portion of the thumbnail that is clipped when fullscreen progress = 0.
private RectF mClippedInsets = new RectF();
private TaskView.FullscreenDrawParams mFullscreenParams;
private final Rect mPreviewRect = new Rect();
private final PreviewPositionHelper mPreviewPositionHelper;
// Initialize with dummy value. It is overridden later by TaskView
private TaskView.FullscreenDrawParams mFullscreenParams = TEMP_PARAMS;
private Task mTask;
private ThumbnailData mThumbnailData;
@@ -103,7 +102,6 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
private float mSaturation = 1f;
private boolean mOverlayEnabled;
private boolean mIsOrientationChanged;
private OverviewScreenshotActions mOverviewScreenshotActionsPlugin;
public TaskThumbnailView(Context context) {
@@ -123,7 +121,7 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
mDimmingPaintAfterClearing.setColor(Color.BLACK);
mActivity = BaseActivity.fromContext(context);
mIsDarkTextTheme = Themes.getAttrBoolean(mActivity, R.attr.isWorkspaceDarkText);
mFullscreenParams = new TaskView.FullscreenDrawParams(TaskCornerRadius.get(context));
mPreviewPositionHelper = new PreviewPositionHelper(context);
}
public void bind(Task task) {
@@ -172,8 +170,7 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
mOverlay.reset();
}
if (mOverviewScreenshotActionsPlugin != null) {
mOverviewScreenshotActionsPlugin
.setupActions((ViewGroup) getTaskView(), getThumbnail(), mActivity);
mOverviewScreenshotActionsPlugin.setupActions(getTaskView(), getThumbnail(), mActivity);
}
updateThumbnailPaintFilter();
}
@@ -270,9 +267,8 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
PluginManagerWrapper.INSTANCE.get(getContext()).removePluginListener(this);
}
public RectF getInsetsToDrawInFullscreen(boolean isMultiWindowMode) {
// Don't show insets in multi window mode.
return isMultiWindowMode ? EMPTY_RECT_F : mClippedInsets;
public PreviewPositionHelper getPreviewPositionHelper() {
return mPreviewPositionHelper;
}
public void setFullscreenParams(TaskView.FullscreenDrawParams fullscreenParams) {
@@ -294,16 +290,17 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
// Draw the background in all cases, except when the thumbnail data is opaque
final boolean drawBackgroundOnly = mTask == null || mTask.isLocked || mBitmapShader == null
|| mThumbnailData == null;
if (drawBackgroundOnly || mClipBottom > 0 || mThumbnailData.isTranslucent) {
if (drawBackgroundOnly || mPreviewPositionHelper.mClipBottom > 0
|| mThumbnailData.isTranslucent) {
canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mBackgroundPaint);
if (drawBackgroundOnly) {
return;
}
}
if (mClipBottom > 0) {
if (mPreviewPositionHelper.mClipBottom > 0) {
canvas.save();
canvas.clipRect(x, y, width, mClipBottom);
canvas.clipRect(x, y, width, mPreviewPositionHelper.mClipBottom);
canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mPaint);
canvas.restore();
} else {
@@ -324,8 +321,9 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
private void updateOverlay() {
// The overlay doesn't really work when the screenshot is rotated, so don't add it.
if (mOverlayEnabled && !mIsOrientationChanged && mBitmapShader != null && mThumbnailData != null) {
mOverlay.initOverlay(mTask, mThumbnailData, mMatrix);
if (mOverlayEnabled && !mPreviewPositionHelper.mIsOrientationChanged
&& mBitmapShader != null && mThumbnailData != null) {
mOverlay.initOverlay(mTask, mThumbnailData, mPreviewPositionHelper.mMatrix);
} else {
mOverlay.reset();
}
@@ -346,76 +344,17 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
}
private void updateThumbnailMatrix() {
boolean isRotated = false;
boolean isOrientationDifferent = false;
mClipBottom = -1;
mPreviewPositionHelper.mClipBottom = -1;
mPreviewPositionHelper.mIsOrientationChanged = false;
if (mBitmapShader != null && mThumbnailData != null) {
float scale = mThumbnailData.scale;
Rect thumbnailInsets = mThumbnailData.insets;
final float thumbnailWidth = mThumbnailData.thumbnail.getWidth() -
(thumbnailInsets.left + thumbnailInsets.right) * scale;
final float thumbnailHeight = mThumbnailData.thumbnail.getHeight() -
(thumbnailInsets.top + thumbnailInsets.bottom) * scale;
mPreviewRect.set(0, 0, mThumbnailData.thumbnail.getWidth(),
mThumbnailData.thumbnail.getHeight());
mPreviewPositionHelper.updateThumbnailMatrix(mPreviewRect, mThumbnailData,
mActivity.isInMultiWindowMode(), getMeasuredWidth(), getMeasuredHeight());
final float thumbnailScale;
int thumbnailRotation = mThumbnailData.rotation;
int currentRotation = ConfigurationCompat.getWindowConfigurationRotation(
getResources().getConfiguration());
int deltaRotate = getRotationDelta(currentRotation, thumbnailRotation);
// Landscape vs portrait change
boolean windowingModeSupportsRotation = !mActivity.isInMultiWindowMode()
&& mThumbnailData.windowingMode == WINDOWING_MODE_FULLSCREEN;
isOrientationDifferent = isOrientationChange(deltaRotate)
&& windowingModeSupportsRotation;
if (getMeasuredWidth() == 0) {
// If we haven't measured , skip the thumbnail drawing and only draw the background
// color
thumbnailScale = 0f;
} else {
// Rotate the screenshot if not in multi-window mode
isRotated = deltaRotate > 0 && windowingModeSupportsRotation;
// Scale the screenshot to always fit the width of the card.
thumbnailScale = isOrientationDifferent
? getMeasuredWidth() / thumbnailHeight
: getMeasuredWidth() / thumbnailWidth;
}
if (!isRotated) {
// No Rotation
mClippedInsets.offsetTo(thumbnailInsets.left * scale,
thumbnailInsets.top * scale);
mMatrix.setTranslate(-mClippedInsets.left, -mClippedInsets.top);
} else {
setThumbnailRotation(deltaRotate, thumbnailInsets, scale);
}
final float widthWithInsets;
final float heightWithInsets;
if (isOrientationDifferent) {
widthWithInsets = mThumbnailData.thumbnail.getHeight() * thumbnailScale;
heightWithInsets = mThumbnailData.thumbnail.getWidth() * thumbnailScale;
} else {
widthWithInsets = mThumbnailData.thumbnail.getWidth() * thumbnailScale;
heightWithInsets = mThumbnailData.thumbnail.getHeight() * thumbnailScale;
}
mClippedInsets.left *= thumbnailScale;
mClippedInsets.top *= thumbnailScale;
mClippedInsets.right = widthWithInsets - mClippedInsets.left - getMeasuredWidth();
mClippedInsets.bottom = heightWithInsets - mClippedInsets.top - getMeasuredHeight();
mMatrix.postScale(thumbnailScale, thumbnailScale);
mBitmapShader.setLocalMatrix(mMatrix);
float bitmapHeight = Math.max((isOrientationDifferent ? thumbnailWidth : thumbnailHeight)
* thumbnailScale, 0);
if (Math.round(bitmapHeight) < getMeasuredHeight()) {
mClipBottom = bitmapHeight;
}
mBitmapShader.setLocalMatrix(mPreviewPositionHelper.mMatrix);
mPaint.setShader(mBitmapShader);
}
mIsOrientationChanged = isOrientationDifferent;
invalidate();
// Update can be called from {@link #onSizeChanged} during layout, post handling of overlay
@@ -423,51 +362,6 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
post(this::updateOverlay);
}
private int getRotationDelta(int oldRotation, int newRotation) {
int delta = newRotation - oldRotation;
if (delta < 0) delta += 4;
return delta;
}
/**
* @param deltaRotation the number of 90 degree turns from the current orientation
* @return {@code true} if the change in rotation results in a shift from landscape to portrait
* or vice versa, {@code false} otherwise
*/
private boolean isOrientationChange(int deltaRotation) {
return deltaRotation == Surface.ROTATION_90 || deltaRotation == Surface.ROTATION_270;
}
private void setThumbnailRotation(int deltaRotate, Rect thumbnailInsets, float scale) {
int newLeftInset = 0;
int newTopInset = 0;
int translateX = 0;
int translateY = 0;
mMatrix.setRotate(90 * deltaRotate);
switch (deltaRotate) { /* Counter-clockwise */
case Surface.ROTATION_90:
newLeftInset = thumbnailInsets.bottom;
newTopInset = thumbnailInsets.left;
translateX = mThumbnailData.thumbnail.getHeight();
break;
case Surface.ROTATION_270:
newLeftInset = thumbnailInsets.top;
newTopInset = thumbnailInsets.right;
translateY = mThumbnailData.thumbnail.getWidth();
break;
case Surface.ROTATION_180:
newLeftInset = -thumbnailInsets.top;
newTopInset = -thumbnailInsets.left;
translateX = mThumbnailData.thumbnail.getWidth();
translateY = mThumbnailData.thumbnail.getHeight();
break;
}
mClippedInsets.offsetTo(newLeftInset * scale, newTopInset * scale);
mMatrix.postTranslate(translateX - mClippedInsets.left,
translateY - mClippedInsets.top);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
@@ -511,4 +405,158 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
}
return mThumbnailData.thumbnail;
}
/**
* Utility class to position the thumbnail in the TaskView
*/
public static class PreviewPositionHelper {
// Contains the portion of the thumbnail that is clipped when fullscreen progress = 0.
private final RectF mClippedInsets = new RectF();
private final Matrix mMatrix = new Matrix();
private float mClipBottom = -1;
private boolean mIsOrientationChanged;
private final Context mContext;
public PreviewPositionHelper(Context context) {
mContext = context;
}
public int getCurrentRotation() {
return ConfigurationCompat.getWindowConfigurationRotation(
mContext.getResources().getConfiguration());
}
public Matrix getMatrix() {
return mMatrix;
}
/**
* Updates the matrix based on the provided parameters
*/
public void updateThumbnailMatrix(Rect thumbnailPosition, ThumbnailData thumbnailData,
boolean isInMultiWindowMode, int canvasWidth, int canvasHeight) {
boolean isRotated = false;
boolean isOrientationDifferent;
mClipBottom = -1;
float scale = thumbnailData.scale;
Rect thumbnailInsets = thumbnailData.insets;
final float thumbnailWidth = thumbnailPosition.width()
- (thumbnailInsets.left + thumbnailInsets.right) * scale;
final float thumbnailHeight = thumbnailPosition.height()
- (thumbnailInsets.top + thumbnailInsets.bottom) * scale;
final float thumbnailScale;
int thumbnailRotation = thumbnailData.rotation;
int currentRotation = getCurrentRotation();
int deltaRotate = getRotationDelta(currentRotation, thumbnailRotation);
// Landscape vs portrait change
boolean windowingModeSupportsRotation = !isInMultiWindowMode
&& thumbnailData.windowingMode == WINDOWING_MODE_FULLSCREEN;
isOrientationDifferent = isOrientationChange(deltaRotate)
&& windowingModeSupportsRotation;
if (canvasWidth == 0) {
// If we haven't measured , skip the thumbnail drawing and only draw the background
// color
thumbnailScale = 0f;
} else {
// Rotate the screenshot if not in multi-window mode
isRotated = deltaRotate > 0 && windowingModeSupportsRotation;
// Scale the screenshot to always fit the width of the card.
thumbnailScale = isOrientationDifferent
? canvasWidth / thumbnailHeight
: canvasWidth / thumbnailWidth;
}
if (!isRotated) {
// No Rotation
mClippedInsets.offsetTo(thumbnailInsets.left * scale,
thumbnailInsets.top * scale);
mMatrix.setTranslate(-mClippedInsets.left, -mClippedInsets.top);
} else {
setThumbnailRotation(deltaRotate, thumbnailInsets, scale, thumbnailPosition);
}
mMatrix.postTranslate(-thumbnailPosition.left, -thumbnailPosition.top);
final float widthWithInsets;
final float heightWithInsets;
if (isOrientationDifferent) {
widthWithInsets = thumbnailPosition.height() * thumbnailScale;
heightWithInsets = thumbnailPosition.width() * thumbnailScale;
} else {
widthWithInsets = thumbnailPosition.width() * thumbnailScale;
heightWithInsets = thumbnailPosition.height() * thumbnailScale;
}
mClippedInsets.left *= thumbnailScale;
mClippedInsets.top *= thumbnailScale;
mClippedInsets.right = widthWithInsets - mClippedInsets.left - canvasWidth;
mClippedInsets.bottom = heightWithInsets - mClippedInsets.top - canvasHeight;
mMatrix.postScale(thumbnailScale, thumbnailScale);
float bitmapHeight = Math.max(0,
(isOrientationDifferent ? thumbnailWidth : thumbnailHeight) * thumbnailScale);
if (Math.round(bitmapHeight) < canvasHeight) {
mClipBottom = bitmapHeight;
}
mIsOrientationChanged = isOrientationDifferent;
}
private int getRotationDelta(int oldRotation, int newRotation) {
int delta = newRotation - oldRotation;
if (delta < 0) delta += 4;
return delta;
}
/**
* @param deltaRotation the number of 90 degree turns from the current orientation
* @return {@code true} if the change in rotation results in a shift from landscape to
* portrait or vice versa, {@code false} otherwise
*/
private boolean isOrientationChange(int deltaRotation) {
return deltaRotation == Surface.ROTATION_90 || deltaRotation == Surface.ROTATION_270;
}
private void setThumbnailRotation(int deltaRotate, Rect thumbnailInsets, float scale,
Rect thumbnailPosition) {
int newLeftInset = 0;
int newTopInset = 0;
int translateX = 0;
int translateY = 0;
mMatrix.setRotate(90 * deltaRotate);
switch (deltaRotate) { /* Counter-clockwise */
case Surface.ROTATION_90:
newLeftInset = thumbnailInsets.bottom;
newTopInset = thumbnailInsets.left;
translateX = thumbnailPosition.height();
break;
case Surface.ROTATION_270:
newLeftInset = thumbnailInsets.top;
newTopInset = thumbnailInsets.right;
translateY = thumbnailPosition.width();
break;
case Surface.ROTATION_180:
newLeftInset = -thumbnailInsets.top;
newTopInset = -thumbnailInsets.left;
translateX = thumbnailPosition.width();
translateY = thumbnailPosition.height();
break;
}
mClippedInsets.offsetTo(newLeftInset * scale, newTopInset * scale);
mMatrix.postTranslate(translateX - mClippedInsets.left,
translateY - mClippedInsets.top);
}
/**
* Insets to used for clipping the thumbnail (in case it is drawing outside its own space)
*/
public RectF getInsetsToDrawInFullscreen(boolean isMultiWindowMode) {
// Don't show insets in multi window mode.
return isMultiWindowMode ? EMPTY_RECT_F : mClippedInsets;
}
}
}
@@ -56,6 +56,7 @@ import android.widget.FrameLayout;
import android.widget.Toast;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
@@ -77,11 +78,11 @@ import com.android.quickstep.TaskIconCache;
import com.android.quickstep.TaskOverlayFactory;
import com.android.quickstep.TaskThumbnailCache;
import com.android.quickstep.TaskUtils;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.TaskCornerRadius;
import com.android.quickstep.views.RecentsView.PageCallbacks;
import com.android.quickstep.views.RecentsView.ScrollState;
import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.ActivityOptionsCompat;
@@ -157,8 +158,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
private float mCurveScale;
private float mFullscreenProgress;
private final FullscreenDrawParams mCurrentFullscreenParams;
private final float mCornerRadius;
private final float mWindowCornerRadius;
private final BaseDraggingActivity mActivity;
private ObjectAnimator mIconAndDimAnimator;
@@ -211,9 +210,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
TaskUtils.getLaunchComponentKeyForTask(getTask().key));
mActivity.getStatsLogManager().log(TASK_LAUNCH_TAP, buildProto());
});
mCornerRadius = TaskCornerRadius.get(context);
mWindowCornerRadius = QuickStepContract.getWindowCornerRadius(context.getResources());
mCurrentFullscreenParams = new FullscreenDrawParams(mCornerRadius);
mCurrentFullscreenParams = new FullscreenDrawParams(context);
mDigitalWellBeingToast = new DigitalWellBeingToast(mActivity, this);
mOutlineProvider = new TaskOutlineProvider(getContext(), mCurrentFullscreenParams);
@@ -236,11 +234,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
super.onFinishInflate();
mSnapshotView = findViewById(R.id.snapshot);
mIconView = findViewById(R.id.icon);
final Context context = getContext();
TaskView.LayoutParams thumbnailParams = (LayoutParams) mSnapshotView.getLayoutParams();
thumbnailParams.bottomMargin = LayoutUtils.thumbnailBottomMargin(context);
mSnapshotView.setLayoutParams(thumbnailParams);
}
public boolean isTaskOverlayModal() {
@@ -473,8 +466,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
int iconRotation = orientationState.getTouchRotation();
PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
boolean isRtl = orientationHandler.getRecentsRtlSetting(getResources());
LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
snapshotParams.bottomMargin = LayoutUtils.thumbnailBottomMargin(getContext());
int thumbnailPadding = (int) getResources().getDimension(R.dimen.task_thumbnail_top_margin);
LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
int rotation = orientationState.getTouchRotationDegrees();
@@ -501,7 +492,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
iconParams.bottomMargin = 0;
break;
}
mSnapshotView.setLayoutParams(snapshotParams);
mIconView.setLayoutParams(iconParams);
mIconView.setRotation(rotation);
}
@@ -699,21 +689,16 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
return 1 - curveInterpolation * EDGE_SCALE_DOWN_FACTOR;
}
public void setCurveScale(float curveScale) {
private void setCurveScale(float curveScale) {
mCurveScale = curveScale;
onScaleChanged();
setScaleX(mCurveScale);
setScaleY(mCurveScale);
}
public float getCurveScale() {
return mCurveScale;
}
private void onScaleChanged() {
float scale = mCurveScale;
setScaleX(scale);
setScaleY(scale);
}
@Override
public boolean hasOverlappingRendering() {
// TODO: Clip-out the icon region from the thumbnail, since they are overlapping.
@@ -723,13 +708,11 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
private static final class TaskOutlineProvider extends ViewOutlineProvider {
private final int mMarginTop;
private final int mMarginBottom;
private FullscreenDrawParams mFullscreenParams;
TaskOutlineProvider(Context context, FullscreenDrawParams fullscreenParams) {
mMarginTop = context.getResources().getDimensionPixelSize(
R.dimen.task_thumbnail_top_margin);
mMarginBottom = LayoutUtils.thumbnailBottomMargin(context);
mFullscreenParams = fullscreenParams;
}
@@ -744,7 +727,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
outline.setRoundRect(0,
(int) (mMarginTop * scale),
(int) ((insets.left + view.getWidth() + insets.right) * scale),
(int) ((insets.top + view.getHeight() + insets.bottom - mMarginBottom) * scale),
(int) ((insets.top + view.getHeight() + insets.bottom) * scale),
mFullscreenParams.mCurrentDrawnCornerRadius);
}
}
@@ -917,23 +900,11 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
setClipToPadding(!isFullscreen);
TaskThumbnailView thumbnail = getThumbnail();
boolean isMultiWindowMode = mActivity.getDeviceProfile().isMultiWindowMode;
RectF insets = thumbnail.getInsetsToDrawInFullscreen(isMultiWindowMode);
float currentInsetsLeft = insets.left * mFullscreenProgress;
float currentInsetsRight = insets.right * mFullscreenProgress;
mCurrentFullscreenParams.setInsets(currentInsetsLeft,
insets.top * mFullscreenProgress,
currentInsetsRight,
insets.bottom * mFullscreenProgress);
float fullscreenCornerRadius = isMultiWindowMode ? 0 : mWindowCornerRadius;
mCurrentFullscreenParams.setCornerRadius(Utilities.mapRange(mFullscreenProgress,
mCornerRadius, fullscreenCornerRadius) / getRecentsView().getScaleX());
// We scaled the thumbnail to fit the content (excluding insets) within task view width.
// Now that we are drawing left/right insets again, we need to scale down to fit them.
if (getWidth() > 0) {
mCurrentFullscreenParams.setScale(getWidth()
/ (getWidth() + currentInsetsLeft + currentInsetsRight));
}
mCurrentFullscreenParams.setProgress(
mFullscreenProgress,
getRecentsView().getScaleX(),
getWidth(), mActivity.getDeviceProfile(),
thumbnail.getPreviewPositionHelper());
if (!getRecentsView().isTaskIconScaledDown(this)) {
// Some of the items in here are dependent on the current fullscreen params, but don't
@@ -971,26 +942,51 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
/**
* We update and subsequently draw these in {@link #setFullscreenProgress(float)}.
*/
static class FullscreenDrawParams {
RectF mCurrentDrawnInsets = new RectF();
float mCurrentDrawnCornerRadius;
public static class FullscreenDrawParams {
private final float mCornerRadius;
private final float mWindowCornerRadius;
public RectF mCurrentDrawnInsets = new RectF();
public float mCurrentDrawnCornerRadius;
/** The current scale we apply to the thumbnail to adjust for new left/right insets. */
float mScale = 1;
public float mScale = 1;
public FullscreenDrawParams(float cornerRadius) {
setCornerRadius(cornerRadius);
public FullscreenDrawParams(Context context) {
mCornerRadius = TaskCornerRadius.get(context);
mWindowCornerRadius = QuickStepContract.getWindowCornerRadius(context.getResources());
mCurrentDrawnCornerRadius = mCornerRadius;
}
public void setInsets(float left, float top, float right, float bottom) {
mCurrentDrawnInsets.set(left, top, right, bottom);
public FullscreenDrawParams() {
mCurrentDrawnCornerRadius = mWindowCornerRadius = mCornerRadius = 0;
}
public void setCornerRadius(float cornerRadius) {
mCurrentDrawnCornerRadius = cornerRadius;
/**
* Sets the progress in range [0, 1]
*/
public void setProgress(float fullscreenProgress, float parentScale, int previewWidth,
DeviceProfile dp, PreviewPositionHelper pph) {
boolean isMultiWindowMode = dp.isMultiWindowMode;
RectF insets = pph.getInsetsToDrawInFullscreen(isMultiWindowMode);
float currentInsetsLeft = insets.left * fullscreenProgress;
float currentInsetsRight = insets.right * fullscreenProgress;
mCurrentDrawnInsets.set(currentInsetsLeft, insets.top * fullscreenProgress,
currentInsetsRight, insets.bottom * fullscreenProgress);
float fullscreenCornerRadius = isMultiWindowMode ? 0 : mWindowCornerRadius;
mCurrentDrawnCornerRadius =
Utilities.mapRange(fullscreenProgress, mCornerRadius, fullscreenCornerRadius)
/ parentScale;
// We scaled the thumbnail to fit the content (excluding insets) within task view width.
// Now that we are drawing left/right insets again, we need to scale down to fit them.
if (previewWidth > 0) {
mScale = previewWidth / (previewWidth + currentInsetsLeft + currentInsetsRight);
}
}
public void setScale(float scale) {
mScale = scale;
}
}
}
@@ -29,7 +29,6 @@ import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.CancellationSignal;
import com.android.launcher3.LauncherState.ScaleAndTranslation;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.WellbeingModel;
@@ -38,7 +37,6 @@ import com.android.launcher3.proxy.ProxyActivityStarter;
import com.android.launcher3.proxy.StartActivityParams;
import com.android.launcher3.statehandlers.BackButtonAlphaHandler;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.uioverrides.RecentsViewStateController;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.UiThreadHelper;
@@ -204,17 +202,6 @@ public abstract class BaseQuickstepLauncher extends Launcher
return new QuickstepOnboardingPrefs(this, sharedPrefs, stateManager);
}
@Override
protected ScaleAndTranslation getOverviewScaleAndTranslationForNormalState() {
if (SysUINavigationMode.getMode(this) == Mode.NO_BUTTON) {
PagedOrientationHandler layoutVertical =
((RecentsView)getOverviewPanel()).getPagedViewOrientedState().getOrientationHandler();
return layoutVertical.getScaleAndTranslation(getDeviceProfile(),
getOverviewPanel());
}
return super.getOverviewScaleAndTranslationForNormalState();
}
@Override
public void useFadeOutAnimationForLauncherStart(CancellationSignal signal) {
QuickstepAppTransitionManagerImpl appTransitionManager =
@@ -237,6 +224,12 @@ public abstract class BaseQuickstepLauncher extends Launcher
}, signal);
}
@Override
public float[] getNormalOverviewScaleAndOffset() {
return SysUINavigationMode.getMode(this) == Mode.NO_BUTTON
? new float[] {1, 1} : new float[] {1.1f, 0};
}
@Override
public void onDragLayerHierarchyChanged() {
onLauncherStateOrFocusChanged();
@@ -17,8 +17,6 @@
package com.android.launcher3.uioverrides;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.graphics.Scrim.SCRIM_PROGRESS;
@@ -26,23 +24,22 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FA
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCRIM_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import android.util.FloatProperty;
import android.view.View;
import androidx.annotation.NonNull;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherState.ScaleAndTranslation;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.graphics.OverviewScrim;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.quickstep.views.RecentsView;
/**
* State handler for recents view. Manages UI changes and animations for recents view based off the
@@ -50,7 +47,7 @@ import com.android.launcher3.states.StateAnimationConfig;
*
* @param <T> the recents view
*/
public abstract class BaseRecentsViewStateController<T extends View>
public abstract class BaseRecentsViewStateController<T extends RecentsView>
implements StateHandler {
protected final T mRecentsView;
protected final BaseQuickstepLauncher mLauncher;
@@ -62,14 +59,9 @@ public abstract class BaseRecentsViewStateController<T extends View>
@Override
public void setState(@NonNull LauncherState state) {
ScaleAndTranslation scaleAndTranslation = state.getOverviewScaleAndTranslation(mLauncher);
float translationX = scaleAndTranslation.translationX;
if (mRecentsView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
translationX = -translationX;
}
SCALE_PROPERTY.set(mRecentsView, scaleAndTranslation.scale);
mRecentsView.setTranslationX(translationX);
mRecentsView.setTranslationY(scaleAndTranslation.translationY);
float[] scaleAndOffset = state.getOverviewScaleAndOffset(mLauncher);
SCALE_PROPERTY.set(mRecentsView, scaleAndOffset[0]);
ADJACENT_PAGE_OFFSET.set(mRecentsView, scaleAndOffset[1]);
getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0);
OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim();
@@ -98,17 +90,11 @@ public abstract class BaseRecentsViewStateController<T extends View>
*/
void setStateWithAnimationInternal(@NonNull final LauncherState toState,
@NonNull StateAnimationConfig config, @NonNull PendingAnimation setter) {
ScaleAndTranslation scaleAndTranslation = toState.getOverviewScaleAndTranslation(mLauncher);
float translationX = scaleAndTranslation.translationX;
if (mRecentsView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
translationX = -translationX;
}
setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleAndTranslation.scale,
float[] scaleAndOffset = toState.getOverviewScaleAndOffset(mLauncher);
setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleAndOffset[0],
config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR));
setter.setFloat(mRecentsView, VIEW_TRANSLATE_X, translationX,
setter.setFloat(mRecentsView, ADJACENT_PAGE_OFFSET, scaleAndOffset[1],
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR));
setter.setFloat(mRecentsView, VIEW_TRANSLATE_Y, scaleAndTranslation.translationY,
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0,
config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
@@ -102,9 +102,8 @@ public class AllAppsState extends LauncherState {
}
@Override
public ScaleAndTranslation getOverviewScaleAndTranslation(Launcher launcher) {
float slightParallax = -launcher.getDeviceProfile().allAppsCellHeightPx * 0.3f;
return new ScaleAndTranslation(0.9f, 0f, slightParallax);
public float[] getOverviewScaleAndOffset(Launcher launcher) {
return new float[] {0.9f, 0};
}
@Override
@@ -135,8 +135,6 @@ public interface BaseActivityInterface<T extends BaseDraggingActivity> {
void createActivityInterface(long transitionLength);
default void adjustActivityControllerInterpolators() { }
default void onTransitionCancelled() { }
default void setShelfState(ShelfPeekAnim.ShelfAnimState animState,
@@ -63,7 +63,7 @@ public class LayoutUtils {
if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context)) {
//TODO: this needs to account for the swipe gesture height and accessibility
// UI when shown.
extraSpace = 0;
extraSpace = res.getDimensionPixelSize(R.dimen.overview_actions_height);
} else {
extraSpace = getDefaultSwipeHeight(context, dp) + dp.workspacePageIndicatorHeight
+ res.getDimensionPixelSize(
@@ -75,7 +75,14 @@ public class LayoutUtils {
}
public static void calculateFallbackTaskSize(Context context, DeviceProfile dp, Rect outRect) {
calculateTaskSize(context, dp, 0, MULTI_WINDOW_STRATEGY_DEVICE_PROFILE, outRect);
float extraSpace;
if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context)) {
extraSpace = context.getResources()
.getDimensionPixelSize(R.dimen.overview_actions_height);
} else {
extraSpace = 0;
}
calculateTaskSize(context, dp, extraSpace, MULTI_WINDOW_STRATEGY_DEVICE_PROFILE, outRect);
}
@AnyThread
@@ -123,8 +130,6 @@ public class LayoutUtils {
}
float topIconMargin = res.getDimension(R.dimen.task_thumbnail_top_margin);
float bottomMargin = thumbnailBottomMargin(context);
float paddingVert = overviewActionsEnabled && removeShelfFromOverview(context)
? 0 : res.getDimension(R.dimen.task_card_vert_space);
@@ -134,7 +139,7 @@ public class LayoutUtils {
int launcherVisibleHeight = dp.heightPx - insets.top - insets.bottom;
float availableHeight = launcherVisibleHeight
- topIconMargin - extraVerticalSpace - paddingVert - bottomMargin;
- topIconMargin - extraVerticalSpace - paddingVert;
float availableWidth = launcherVisibleWidth - paddingHorz;
float scale = Math.min(availableWidth / taskWidth, availableHeight / taskHeight);
@@ -144,7 +149,7 @@ public class LayoutUtils {
// Center in the visible space
float x = insets.left + (launcherVisibleWidth - outWidth) / 2;
float y = insets.top + Math.max(topIconMargin,
(launcherVisibleHeight - extraVerticalSpace - outHeight - bottomMargin) / 2);
(launcherVisibleHeight - extraVerticalSpace - outHeight) / 2);
outRect.set(Math.round(x), Math.round(y),
Math.round(x) + Math.round(outWidth), Math.round(y) + Math.round(outHeight));
}
@@ -163,14 +168,16 @@ public class LayoutUtils {
}
/**
* Get the margin that the task thumbnail view should use.
* @return the margin in pixels.
* Gets the scale that should be applied to the TaskView so that it matches the target
*/
public static int thumbnailBottomMargin(Context context) {
if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context)) {
return context.getResources().getDimensionPixelSize(R.dimen.overview_actions_height);
public static float getTaskScale(RecentsOrientedState orientedState,
float srcWidth, float srcHeight, float targetWidth, float targetHeight) {
if (orientedState == null
|| orientedState.isHomeRotationAllowed()
|| orientedState.isDisplayPhoneNatural()) {
return srcWidth / targetWidth;
} else {
return 0;
return srcHeight / targetHeight;
}
}
}
@@ -18,9 +18,9 @@ package com.android.quickstep.util;
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.hardware.camera2.params.OutputConfiguration.ROTATION_180;
import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
@@ -28,6 +28,7 @@ import static com.android.launcher3.config.FeatureFlags.FLAG_ENABLE_FIXED_ROTATI
import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY;
import static com.android.launcher3.states.RotationHelper.FIXED_ROTATION_TRANSFORM_SETTING_NAME;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.content.ContentResolver;
@@ -36,6 +37,8 @@ import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler;
import android.provider.Settings;
@@ -45,6 +48,7 @@ import android.view.Surface;
import androidx.annotation.IntDef;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.touch.PagedOrientationHandler;
@@ -135,7 +139,7 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
*/
public boolean update(
@SurfaceRotation int touchRotation, @SurfaceRotation int displayRotation,
int launcherRotation) {
@SurfaceRotation int launcherRotation) {
if (!FeatureFlags.ENABLE_FIXED_ROTATION_TRANSFORM.get()) {
return false;
}
@@ -277,6 +281,25 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
}
}
/**
* Returns the scale and pivot so that the provided taskRect can fit the provided full size
*/
public float getFullScreenScaleAndPivot(Rect taskView, DeviceProfile dp, PointF outPivot) {
Rect insets = dp.getInsets();
float fullWidth = dp.widthPx - insets.left - insets.right;
float fullHeight = dp.heightPx - insets.top - insets.bottom;
final float scale = LayoutUtils.getTaskScale(this,
fullWidth, fullHeight, taskView.width(), taskView.height());
if (scale == 1) {
outPivot.set(fullWidth / 2, fullHeight / 2);
} else {
float factor = scale / (scale - 1);
outPivot.set(taskView.left * factor, taskView.top * factor);
}
return scale;
}
public PagedOrientationHandler getOrientationHandler() {
return mOrientationHandler;
}
+11 -5
View File
@@ -25,6 +25,8 @@ import static com.android.launcher3.AbstractFloatingView.TYPE_SNACKBAR;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.NO_OFFSET;
import static com.android.launcher3.LauncherState.NO_SCALE;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.OVERVIEW_PEEK;
import static com.android.launcher3.Utilities.postAsyncCallback;
@@ -85,7 +87,6 @@ import androidx.annotation.StringRes;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.LauncherState.ScaleAndTranslation;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.allapps.AllAppsContainerView;
@@ -2698,10 +2699,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
return new TouchController[] {getDragController(), new AllAppsSwipeController(this)};
}
protected ScaleAndTranslation getOverviewScaleAndTranslationForNormalState() {
return new ScaleAndTranslation(1.1f, 0f, 0f);
}
public void useFadeOutAnimationForLauncherStart(CancellationSignal signal) { }
public void onDragLayerHierarchyChanged() { }
@@ -2724,6 +2721,14 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
return Stream.of(APP_INFO, WIDGETS, INSTALL);
}
/**
* @see LauncherState#getOverviewScaleAndOffset(Launcher)
*/
public float[] getNormalOverviewScaleAndOffset() {
return new float[] {NO_SCALE, NO_OFFSET};
}
public static Launcher getLauncher(Context context) {
return fromContext(context);
}
@@ -2735,6 +2740,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
return (T) activityContext;
}
/**
* Callback for listening for onResume
*/
+13 -4
View File
@@ -90,6 +90,9 @@ public abstract class LauncherState {
protected static final int FLAG_HIDE_BACK_BUTTON = 1 << 8;
protected static final int FLAG_HAS_SYS_UI_SCRIM = 1 << 9;
public static final float NO_OFFSET = 0;
public static final float NO_SCALE = 1;
protected static final PageAlphaProvider DEFAULT_ALPHA_PROVIDER =
new PageAlphaProvider(ACCEL_2) {
@Override
@@ -220,7 +223,7 @@ public abstract class LauncherState {
public abstract int getTransitionDuration(Launcher launcher);
public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
return new ScaleAndTranslation(1, 0, 0);
return new ScaleAndTranslation(NO_SCALE, NO_OFFSET, NO_OFFSET);
}
public ScaleAndTranslation getHotseatScaleAndTranslation(Launcher launcher) {
@@ -228,12 +231,18 @@ public abstract class LauncherState {
return getWorkspaceScaleAndTranslation(launcher);
}
public ScaleAndTranslation getOverviewScaleAndTranslation(Launcher launcher) {
return launcher.getOverviewScaleAndTranslationForNormalState();
/**
* Returns an array of two elements.
* The first specifies the scale for the overview
* The second is the factor ([0, 1], 0 => center-screen; 1 => offscreen) by which overview
* should be shifted horizontally.
*/
public float[] getOverviewScaleAndOffset(Launcher launcher) {
return launcher.getNormalOverviewScaleAndOffset();
}
public ScaleAndTranslation getQsbScaleAndTranslation(Launcher launcher) {
return new ScaleAndTranslation(1, 0, 0);
return new ScaleAndTranslation(NO_SCALE, NO_OFFSET, NO_OFFSET);
}
public float getOverviewFullscreenProgress() {
@@ -32,7 +32,6 @@ import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherState.ScaleAndTranslation;
import com.android.launcher3.PagedView;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.OverScroller;
@@ -119,11 +118,6 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
return view.getMeasuredHeight();
}
@Override
public int getPrimarySize(Rect rect) {
return rect.height();
}
@Override
public float getPrimarySize(RectF rect) {
return rect.height();
@@ -134,17 +128,6 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler {
return view.getWidth();
}
@Override
public ScaleAndTranslation getScaleAndTranslation(DeviceProfile dp, View view) {
float offscreenTranslationY = dp.heightPx - view.getPaddingTop();
return new ScaleAndTranslation(1f, 0f, offscreenTranslationY);
}
@Override
public float getTranslationValue(ScaleAndTranslation scaleAndTranslation) {
return scaleAndTranslation.translationY;
}
@Override
public FloatProperty<View> getPrimaryViewTranslate() {
return VIEW_TRANSLATE_Y;
@@ -18,6 +18,7 @@ package com.android.launcher3.touch;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -28,7 +29,6 @@ import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherState;
import com.android.launcher3.PagedView;
import com.android.launcher3.util.OverScroller;
@@ -53,16 +53,15 @@ public interface PagedOrientationHandler {
Int2DAction<View> VIEW_SCROLL_BY = View::scrollBy;
Int2DAction<View> VIEW_SCROLL_TO = View::scrollTo;
Float2DAction<Canvas> CANVAS_TRANSLATE = Canvas::translate;
Float2DAction<Matrix> MATRIX_POST_TRANSLATE = Matrix::postTranslate;
<T> void set(T target, Int2DAction<T> action, int param);
<T> void set(T target, Float2DAction<T> action, float param);
float getPrimaryDirection(MotionEvent event, int pointerIndex);
float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId);
int getMeasuredSize(View view);
int getPrimarySize(Rect rect);
float getPrimarySize(RectF rect);
int getSecondaryDimension(View view);
LauncherState.ScaleAndTranslation getScaleAndTranslation(DeviceProfile dp, View view);
float getTranslationValue(LauncherState.ScaleAndTranslation scaleAndTranslation);
FloatProperty<View> getPrimaryViewTranslate();
FloatProperty<View> getSecondaryViewTranslate();
void setPrimaryAndResetSecondaryTranslate(View view, float translation);
@@ -98,7 +97,6 @@ public interface PagedOrientationHandler {
*/
void adjustFloatingIconStartVelocity(PointF velocity);
class CurveProperties {
public int scroll;
public int halfPageSize;
@@ -32,7 +32,6 @@ import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherState.ScaleAndTranslation;
import com.android.launcher3.PagedView;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.OverScroller;
@@ -117,11 +116,6 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
return view.getMeasuredWidth();
}
@Override
public int getPrimarySize(Rect rect) {
return rect.width();
}
@Override
public float getPrimarySize(RectF rect) {
return rect.width();
@@ -132,17 +126,6 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler {
return view.getHeight();
}
@Override
public ScaleAndTranslation getScaleAndTranslation(DeviceProfile dp, View view) {
float offscreenTranslationX = dp.widthPx - view.getPaddingStart();
return new ScaleAndTranslation(1f, offscreenTranslationX, 0f);
}
@Override
public float getTranslationValue(ScaleAndTranslation scaleAndTranslation) {
return scaleAndTranslation.translationX;
}
@Override
public FloatProperty<View> getPrimaryViewTranslate() {
return VIEW_TRANSLATE_X;