Adding TaskViewSimulator for simulating taskView layout on a remote target am: f2393f1d20

Change-Id: I020e4b56de42e455b92c078bf4c8502fa3f0713c
This commit is contained in:
Sunny Goyal
2020-04-21 19:46:57 +00:00
committed by Automerger Merge Worker
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;