diff --git a/quickstep/recents_ui_overrides/res/layout/overview_panel.xml b/quickstep/recents_ui_overrides/res/layout/overview_panel.xml index eac0bfa8eb..fe57e9b3d5 100644 --- a/quickstep/recents_ui_overrides/res/layout/overview_panel.xml +++ b/quickstep/recents_ui_overrides/res/layout/overview_panel.xml @@ -13,12 +13,20 @@ See the License for the specific language governing permissions and limitations under the License. --> - + + + + + + + diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index 0019ecb427..6c64bf7c75 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -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 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) diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java index 8af26c6e8b..752068843c 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java @@ -19,11 +19,13 @@ import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate. import static com.android.launcher3.graphics.IconShape.getShape; import android.content.Context; +import android.graphics.BlurMaskFilter; import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.DashPathEffect; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.Rect; +import android.os.Process; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.ViewGroup; @@ -39,6 +41,7 @@ import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.graphics.IconPalette; import com.android.launcher3.hybridhotseat.HotseatPredictionController; import com.android.launcher3.icons.IconNormalizer; +import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.touch.ItemClickHandler; @@ -51,13 +54,18 @@ import com.android.launcher3.views.DoubleShadowBubbleTextView; public class PredictedAppIcon extends DoubleShadowBubbleTextView implements LauncherAccessibilityDelegate.AccessibilityActionHandler { + private static final int RING_SHADOW_COLOR = 0x99000000; private static final float RING_EFFECT_RATIO = 0.11f; boolean mIsDrawingDot = false; private final DeviceProfile mDeviceProfile; private final Paint mIconRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Path mRingPath = new Path(); private boolean mIsPinned = false; - private int mNormalizedIconRadius; + private final int mNormalizedIconRadius; + private final BlurMaskFilter mShadowFilter; + private int mPlateColor; + public PredictedAppIcon(Context context) { this(context, null, 0); @@ -73,13 +81,18 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView implements mNormalizedIconRadius = IconNormalizer.getNormalizedCircleSize(getIconSize()) / 2; setOnClickListener(ItemClickHandler.INSTANCE); setOnFocusChangeListener(Launcher.getLauncher(context).getFocusHandler()); + int shadowSize = context.getResources().getDimensionPixelSize( + R.dimen.blur_size_thin_outline); + mShadowFilter = new BlurMaskFilter(shadowSize, BlurMaskFilter.Blur.OUTER); } @Override public void onDraw(Canvas canvas) { int count = canvas.save(); if (!mIsPinned) { - drawEffect(canvas); + boolean isBadged = getTag() instanceof WorkspaceItemInfo + && !Process.myUserHandle().equals(((ItemInfo) getTag()).user); + drawEffect(canvas, isBadged); canvas.translate(getWidth() * RING_EFFECT_RATIO, getHeight() * RING_EFFECT_RATIO); canvas.scale(1 - 2 * RING_EFFECT_RATIO, 1 - 2 * RING_EFFECT_RATIO); } @@ -102,7 +115,7 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView implements public void applyFromWorkspaceItem(WorkspaceItemInfo info) { super.applyFromWorkspaceItem(info); int color = IconPalette.getMutedColor(info.bitmap.color, 0.54f); - mIconRingPaint.setColor(ColorUtils.setAlphaComponent(color, 200)); + mPlateColor = ColorUtils.setAlphaComponent(color, 200); if (mIsPinned) { setContentDescription(info.contentDescription); } else { @@ -174,9 +187,25 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView implements return getPaddingTop() + mDeviceProfile.folderIconOffsetYPx; } - private void drawEffect(Canvas canvas) { - getShape().drawShape(canvas, getOutlineOffsetX(), getOutlineOffsetY(), - mNormalizedIconRadius, mIconRingPaint); + private void drawEffect(Canvas canvas, boolean isBadged) { + mRingPath.reset(); + getShape().addToPath(mRingPath, getOutlineOffsetX(), getOutlineOffsetY(), + mNormalizedIconRadius); + if (isBadged) { + float outlineSize = mNormalizedIconRadius * RING_EFFECT_RATIO * 2; + float iconSize = getIconSize() * (1 - 2 * RING_EFFECT_RATIO); + float badgeSize = LauncherIcons.getBadgeSizeForIconSize((int) iconSize) + outlineSize; + float badgeInset = mNormalizedIconRadius * 2 - badgeSize; + getShape().addToPath(mRingPath, getOutlineOffsetX() + badgeInset, + getOutlineOffsetY() + badgeInset, badgeSize / 2); + + } + mIconRingPaint.setColor(RING_SHADOW_COLOR); + mIconRingPaint.setMaskFilter(mShadowFilter); + canvas.drawPath(mRingPath, mIconRingPaint); + mIconRingPaint.setColor(mPlateColor); + mIconRingPaint.setMaskFilter(null); + canvas.drawPath(mRingPath, mIconRingPaint); } /** @@ -205,10 +234,8 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView implements mOffsetX = icon.getOutlineOffsetX(); mOffsetY = icon.getOutlineOffsetY(); mIconRadius = icon.mNormalizedIconRadius; - mOutlinePaint.setStyle(Paint.Style.STROKE); - mOutlinePaint.setStrokeWidth(5); - mOutlinePaint.setPathEffect(new DashPathEffect(new float[]{15, 15}, 0)); - mOutlinePaint.setColor(Color.argb(100, 245, 245, 245)); + mOutlinePaint.setStyle(Paint.Style.FILL); + mOutlinePaint.setColor(Color.argb(24, 245, 245, 245)); } /** diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java index 3d6e519d3f..2f55fda8f0 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java @@ -15,19 +15,14 @@ */ package com.android.launcher3.uioverrides; -import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA; import static com.android.launcher3.LauncherState.OVERVIEW_BUTTONS; -import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT; import static com.android.launcher3.anim.Interpolators.LINEAR; -import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE; import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA; import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS; import android.annotation.TargetApi; import android.os.Build; import android.util.FloatProperty; -import android.view.View; -import android.view.animation.Interpolator; import androidx.annotation.NonNull; @@ -37,6 +32,7 @@ import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.anim.PropertySetter; import com.android.launcher3.states.StateAnimationConfig; +import com.android.launcher3.util.MultiValueAlpha; import com.android.quickstep.views.ClearAllButton; import com.android.quickstep.views.LauncherRecentsView; import com.android.quickstep.views.RecentsView; @@ -60,7 +56,7 @@ public final class RecentsViewStateController extends mRecentsView.updateEmptyMessage(); mRecentsView.resetTaskVisuals(); } - setAlphas(PropertySetter.NO_ANIM_PROPERTY_SETTER, state, LINEAR); + setAlphas(PropertySetter.NO_ANIM_PROPERTY_SETTER, state); mRecentsView.setFullscreenProgress(state.getOverviewFullscreenProgress()); } @@ -78,22 +74,17 @@ public final class RecentsViewStateController extends AnimationSuccessListener.forRunnable(mRecentsView::resetTaskVisuals)); } - setAlphas(builder, toState, - config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT)); + setAlphas(builder, toState); builder.setFloat(mRecentsView, FULLSCREEN_PROGRESS, toState.getOverviewFullscreenProgress(), LINEAR); } - private void setAlphas(PropertySetter propertySetter, LauncherState state, - Interpolator actionInterpolator) { + private void setAlphas(PropertySetter propertySetter, LauncherState state) { float buttonAlpha = (state.getVisibleElements(mLauncher) & OVERVIEW_BUTTONS) != 0 ? 1 : 0; propertySetter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA, buttonAlpha, LINEAR); - - View actionsView = mLauncher.getActionsView(); - if (actionsView != null) { - propertySetter.setFloat(actionsView, VIEW_ALPHA, buttonAlpha, actionInterpolator); - } + propertySetter.setFloat(mLauncher.getActionsView().getVisibilityAlpha(), + MultiValueAlpha.VALUE, buttonAlpha, LINEAR); } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java index a87d6d14d6..e57e84184e 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java @@ -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 @@ -106,7 +109,7 @@ public class BackgroundAppState extends OverviewState { } @Override - public float getDepth(Context context) { + protected float getDepthUnchecked(Context context) { return 1f; } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java index 1288e7bf9b..b27f16ac08 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java @@ -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 diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java index bcfb11c090..e44f59fd71 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java @@ -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 @@ -144,7 +143,6 @@ public class OverviewState extends LauncherState { @Override public void onStateTransitionEnd(Launcher launcher) { - launcher.getRotationHelper().setCurrentStateRequest(REQUEST_ROTATE); DiscoveryBounce.showForOverviewIfNeeded(launcher); RecentsView recentsView = launcher.getOverviewPanel(); AccessibilityManagerCompat.sendCustomAccessibilityEvent( @@ -205,7 +203,7 @@ public class OverviewState extends LauncherState { } @Override - public float getDepth(Context context) { + protected float getDepthUnchecked(Context context) { return 1f; } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java index c92a872ba9..f4f8bc9ecb 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java @@ -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(); } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java index 1b3610a92d..f6f892b44b 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java @@ -24,6 +24,7 @@ import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_POSI import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.view.MotionEvent; +import android.view.View; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseDraggingActivity; @@ -209,9 +210,11 @@ public abstract class TaskViewTouchController mPendingAnimation = mRecentsView.createTaskLaunchAnimation( mTaskBeingDragged, maxDuration, Interpolators.ZOOM_IN); - mTempCords[1] = mTaskBeingDragged.getHeight(); - dl.getDescendantCoordRelativeToSelf(mTaskBeingDragged, mTempCords); - mEndDisplacement = dl.getHeight() - mTempCords[1]; + // Since the thumbnail is what is filling the screen, based the end displacement on it. + View thumbnailView = mTaskBeingDragged.getThumbnail(); + mTempCords[1] = orientationHandler.getSecondaryDimension(thumbnailView); + dl.getDescendantCoordRelativeToSelf(thumbnailView, mTempCords); + mEndDisplacement = secondaryLayerDimension - mTempCords[1]; } mEndDisplacement *= verticalFactor; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java index 9dce9847c2..e182c59570 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java @@ -117,6 +117,7 @@ final class AppToOverviewAnimationProvider exten }); if (mActivity == null) { Log.e(TAG, "Animation created, before activity"); + anim.play(ValueAnimator.ofInt(0, 1).setDuration(RECENTS_LAUNCH_DURATION)); return anim; } @@ -135,6 +136,7 @@ final class AppToOverviewAnimationProvider exten RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(mTargetTaskId); if (runningTaskTarget == null) { Log.e(TAG, "No closing app"); + anim.play(ValueAnimator.ofInt(0, 1).setDuration(RECENTS_LAUNCH_DURATION)); return anim; } @@ -181,6 +183,7 @@ final class AppToOverviewAnimationProvider exten transaction.apply(); }); } + anim.play(valueAnimator); return anim; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java index fadde374ba..32ab98bd4d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -31,7 +31,6 @@ import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.os.Build; -import android.util.Log; import android.util.Pair; import android.view.MotionEvent; import android.view.View; @@ -46,7 +45,6 @@ import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; -import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.util.VibratorWrapper; import com.android.launcher3.views.FloatingIconView; @@ -133,13 +131,19 @@ public abstract class BaseSwipeUpHandler mBitmapSupplier; - private final SystemUiProxy mSystemUiProxy; + + protected final Context mContext; + protected final Supplier mBitmapSupplier; + protected final SystemUiProxy mSystemUiProxy; public ImageActionsApi(Context context, Supplier bitmapSupplier) { mContext = context; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java index 455ae764a9..b4764dc506 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java @@ -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 { - private Runnable mAdjustInterpolatorsRunnable; private Pair mSwipeUpPullbackStartAndMaxProgress = BaseActivityInterface.super.getSwipeUpPullbackStartAndMaxProgress(); @@ -242,14 +237,6 @@ public final class LauncherActivityInterface implements BaseActivityInterface { - // 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); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java index 31a2814ed0..5a64382478 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java @@ -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 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 mTaskAnimationManager = taskAnimationManager; mTouchTimeMs = touchTimeMs; mContinuingLastGesture = continuingLastGesture; + mTaskViewSimulator = new TaskViewSimulator(context, LayoutUtils::calculateLauncherTaskSize); + + initAfterSubclassConstructor(); initStateCallbacks(); } @@ -473,23 +483,11 @@ public class LauncherSwipeHandler } 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 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 private void onAnimatorPlaybackControllerCreated(AnimatorPlaybackController anim) { mLauncherTransitionController = anim; mLauncherTransitionController.dispatchSetInterpolator(t -> t * mDragLengthFactor); - mAnimationFactory.adjustActivityControllerInterpolators(); mLauncherTransitionController.dispatchOnStart(); updateLauncherTransitionProgress(); } @@ -555,7 +580,9 @@ public class LauncherSwipeHandler @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 } } + 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 mLauncherTransitionController.dispatchSetInterpolator(t -> end); } else { mLauncherTransitionController.dispatchSetInterpolator(adjustedInterpolator); - mAnimationFactory.adjustActivityControllerInterpolators(); } mLauncherTransitionController.getAnimationPlayer().setDuration(Math.max(0, duration)); @@ -1296,6 +1332,7 @@ public class LauncherSwipeHandler private void setTargetAlphaProvider(TargetAlphaProvider provider) { mAppWindowAnimationHelper.setTaskAlphaCallback(provider); + mTaskViewSimulator.setTaskAlphaCallback(provider); updateFinalShift(); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java index 42d944fb78..52a25589a6 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java @@ -71,6 +71,7 @@ public final class RecentsActivity extends BaseRecentsActivity { mRecentsRootView = findViewById(R.id.drag_layer); mFallbackRecentsView = findViewById(R.id.overview_panel); mRecentsRootView.recreateControllers(); + mFallbackRecentsView.init(findViewById(R.id.overview_actions_view)); } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java index fbf29af9fb..147f9330c7 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java @@ -16,7 +16,6 @@ package com.android.quickstep; -import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS; import static com.android.launcher3.util.MainThreadInitializedObject.forOverride; import android.content.Context; @@ -84,47 +83,47 @@ public class TaskOverlayFactory implements ResourceBasedOverride { /** * Overlay on each task handling Overview Action Buttons. */ - public static class TaskOverlay { + public static class TaskOverlay { private final Context mApplicationContext; - private OverviewActionsView mActionsView; - private final TaskThumbnailView mThumbnailView; + protected final TaskThumbnailView mThumbnailView; + private T mActionsView; protected TaskOverlay(TaskThumbnailView taskThumbnailView) { mApplicationContext = taskThumbnailView.getContext().getApplicationContext(); mThumbnailView = taskThumbnailView; } + protected T getActionsView() { + if (mActionsView == null) { + mActionsView = BaseActivity.fromContext(mThumbnailView.getContext()).findViewById( + R.id.overview_actions_view); + } + return mActionsView; + } + /** * Called when the current task is interactive for the user */ public void initOverlay(Task task, ThumbnailData thumbnail, Matrix matrix) { ImageActionsApi imageApi = new ImageActionsApi( mApplicationContext, mThumbnailView::getThumbnail); + getActionsView().setCallbacks(new OverlayUICallbacks() { + @Override + public void onShare() { + imageApi.startShareActivity(); + } - if (mActionsView == null && ENABLE_OVERVIEW_ACTIONS.get() - && SysUINavigationMode.removeShelfFromOverview(mApplicationContext)) { - mActionsView = BaseActivity.fromContext(mThumbnailView.getContext()).findViewById( - R.id.overview_actions_view); - } - if (mActionsView != null) { - mActionsView.setListener(new OverviewActionsView.Listener() { - @Override - public void onShare() { - imageApi.startShareActivity(); - } - - @Override - public void onScreenshot() { - imageApi.saveScreenshot(mThumbnailView.getThumbnail(), - getTaskSnapshotBounds(), getTaskSnapshotInsets(), task.key.id); - } - }); - } - + @Override + public void onScreenshot() { + imageApi.saveScreenshot(mThumbnailView.getThumbnail(), + getTaskSnapshotBounds(), getTaskSnapshotInsets(), task.key.id); + } + }); } + /** * Called when the overlay is no longer used. */ @@ -161,4 +160,16 @@ public class TaskOverlayFactory implements ResourceBasedOverride { return Insets.of(0, 0, 0, 0); } } + + /** + * Callbacks the Ui can generate. This is the only way for a Ui to call methods on the + * controller. + */ + public interface OverlayUICallbacks { + /** User has indicated they want to share the current task. */ + void onShare(); + + /** User has indicated they want to screenshot the current task. */ + void onScreenshot(); + } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index 2c2feb21c4..9b5a935e6b 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -90,7 +90,6 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.InputMonitorCompat; -import com.android.systemui.shared.system.RecentsAnimationListener; import com.android.systemui.shared.tracing.ProtoTraceable; import java.io.FileDescriptor; @@ -299,9 +298,6 @@ public class TouchInteractionService extends Service implements PluginListener activityInterface = mOverviewComponentObserver.getActivityInterface(); + final Intent overviewIntent = new Intent( + mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState()); if (activityInterface.getCreatedActivity() == null) { // Make sure that UI states will be initialized. activityInterface.createActivityInitListener((wasVisible) -> { AppLaunchTracker.INSTANCE.get(TouchInteractionService.this); return false; - }).register(); + }).register(overviewIntent); } else if (fromInit) { // The activity has been created before the initialization of overview service. It is // usually happens when booting or launcher is the top activity, so we should already @@ -767,8 +756,7 @@ public class TouchInteractionService extends Service implements PluginListener ActivityManagerWrapper.getInstance() - .startRecentsActivity(intent, null, listener, null, null)); - } - @Override public void onPluginConnected(OverscrollPlugin overscrollPlugin, Context context) { mOverscrollPlugin = overscrollPlugin; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java index dc0c194812..235ac16413 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java @@ -26,10 +26,10 @@ 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; +import com.android.quickstep.views.OverviewActionsView; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.Task; @@ -57,7 +57,6 @@ public class FallbackRecentsView extends RecentsView { private boolean mInOverviewState = true; private float mZoomScale = 1f; - private float mZoomTranslationY = 0f; private RunningTaskInfo mRunningTaskInfo; @@ -67,6 +66,11 @@ public class FallbackRecentsView extends RecentsView { public FallbackRecentsView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); + } + + @Override + public void init(OverviewActionsView actionsView) { + super.init(actionsView); setOverviewStateEnabled(true); setOverlayEnabled(true); } @@ -139,14 +143,11 @@ public class FallbackRecentsView extends RecentsView { 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); @@ -155,7 +156,6 @@ public class FallbackRecentsView extends RecentsView { 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); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index fe9ef2befe..1f6c506d3a 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -333,7 +333,8 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mTaskAnimationManager.isRecentsAnimationRunning(), isLikelyToStartNewTask); mInteractionHandler.setGestureEndCallback(this::onInteractionGestureFinished); mMotionPauseDetector.setOnMotionPauseListener(mInteractionHandler::onMotionPauseChanged); - mInteractionHandler.initWhenReady(); + Intent intent = new Intent(mInteractionHandler.getLaunchIntent()); + mInteractionHandler.initWhenReady(intent); if (mTaskAnimationManager.isRecentsAnimationRunning()) { mActiveCallbacks = mTaskAnimationManager.continueRecentsAnimation(mGestureState); @@ -341,7 +342,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mTaskAnimationManager.notifyRecentsAnimationState(mInteractionHandler); notifyGestureStarted(); } else { - Intent intent = mInteractionHandler.getLaunchIntent(); intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mGestureState.getGestureId()); mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation(mGestureState, intent, mInteractionHandler); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java index 0a21413fb4..c49b8f2d14 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java @@ -36,17 +36,14 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; -import com.android.quickstep.views.LauncherRecentsView; import com.android.quickstep.views.RecentsView; import com.android.systemui.plugins.OverscrollPlugin; import com.android.systemui.shared.system.InputMonitorCompat; /** * Input consumer for handling events to pass to an {@code OverscrollPlugin}. - * - * @param Draggable activity subclass used by RecentsView */ -public class OverscrollInputConsumer extends DelegateInputConsumer { +public class OverscrollInputConsumer extends DelegateInputConsumer { private static final String TAG = "OverscrollInputConsumer"; @@ -61,12 +58,12 @@ public class OverscrollInputConsumer extends Del private final float mSquaredSlop; - private final Context mContext; private final GestureState mGestureState; @Nullable private final OverscrollPlugin mPlugin; private final GestureDetector mGestureDetector; + @Nullable private RecentsView mRecentsView; public OverscrollInputConsumer(Context context, GestureState gestureState, @@ -77,7 +74,6 @@ public class OverscrollInputConsumer extends Del .getInteger(R.integer.assistant_gesture_corner_deg_threshold); mFlingThresholdPx = context.getResources() .getDimension(R.dimen.gestures_overscroll_fling_threshold); - mContext = context; mGestureState = gestureState; mPlugin = plugin; @@ -85,9 +81,6 @@ public class OverscrollInputConsumer extends Del mSquaredSlop = slop * slop; mGestureDetector = new GestureDetector(context, new FlingGestureListener()); - - gestureState.getActivityInterface().createActivityInitListener(this::onActivityInit) - .register(); } @Override @@ -95,12 +88,6 @@ public class OverscrollInputConsumer extends Del return TYPE_OVERSCROLL | mDelegate.getType(); } - private boolean onActivityInit(Boolean alreadyOnHome) { - mRecentsView = mGestureState.getActivityInterface().getCreatedActivity().getOverviewPanel(); - - return true; - } - @Override public void onMotionEvent(MotionEvent ev) { switch (ev.getActionMasked()) { @@ -191,10 +178,17 @@ public class OverscrollInputConsumer extends Del } private boolean isOverscrolled() { + if (mRecentsView == null) { + BaseDraggingActivity activity = mGestureState.getActivityInterface() + .getCreatedActivity(); + if (activity != null) { + mRecentsView = activity.getOverviewPanel(); + } + } + // Make sure there isn't an app to quick switch to on our right int maxIndex = 0; - if ((mRecentsView instanceof LauncherRecentsView) - && ((LauncherRecentsView) mRecentsView).hasRecentsExtraCard()) { + if (mRecentsView != null && mRecentsView.hasRecentsExtraCard()) { maxIndex = 1; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java index 75a59762b6..00329b87e0 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java @@ -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.getDisplayRotation() == Surface.ROTATION_0 - || mOrientedState.getDisplayRotation() == Surface.ROTATION_180)) { - 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) { @@ -277,8 +271,9 @@ public class AppWindowAnimationHelper { mCurrentRect.offset(params.mOffset, 0); } else { int displayRotation = mOrientedState.getDisplayRotation(); + int launcherRotation = mOrientedState.getLauncherRotation(); mOrientedState.getOrientationHandler().offsetTaskRect(mCurrentRect, - params.mOffset, displayRotation); + params.mOffset, displayRotation, launcherRotation); } } @@ -377,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()) { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java index dde76059fe..8a6c4a17ae 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java @@ -207,9 +207,23 @@ public class RectFSpringAnim { mRectScaleAnim.skipToEnd(); } } + mRectXAnimEnded = true; + mRectYAnimEnded = true; + mRectScaleAnimEnded = true; + maybeOnEnd(); + } + + private boolean isEnded() { + return mRectXAnimEnded && mRectYAnimEnded && mRectScaleAnimEnded; } private void onUpdate() { + if (isEnded()) { + // Prevent further updates from being called. This can happen between callbacks for + // ending the x/y/scale animations. + return; + } + if (!mOnUpdateListeners.isEmpty()) { float currentWidth = Utilities.mapRange(mCurrentScaleProgress, mStartRect.width(), mTargetRect.width()); @@ -229,7 +243,7 @@ public class RectFSpringAnim { } private void maybeOnEnd() { - if (mAnimsStarted && mRectXAnimEnded && mRectYAnimEnded && mRectScaleAnimEnded) { + if (mAnimsStarted && isEnded()) { mAnimsStarted = false; for (Animator.AnimatorListener animatorListener : mAnimatorListeners) { animatorListener.onAnimationEnd(null); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java index 9cf45b3151..bde6f9af19 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java @@ -21,6 +21,7 @@ import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS; +import static com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTROLLER; import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW; import android.animation.Animator; @@ -146,7 +147,7 @@ public class StaggeredWorkspaceAnim { */ private void prepareToAnimate(Launcher launcher) { StateAnimationConfig config = new StateAnimationConfig(); - config.animFlags = ANIM_ALL_COMPONENTS | SKIP_OVERVIEW; + config.animFlags = ANIM_ALL_COMPONENTS | SKIP_OVERVIEW | SKIP_DEPTH_CONTROLLER; config.duration = 0; // setRecentsAttachedToAppWindow() will animate recents out. launcher.getStateManager().createAtomicAnimation(BACKGROUND_APP, NORMAL, config).start(); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java new file mode 100644 index 0000000000..0131fdf5c4 --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java @@ -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); + } + +} diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java index 98eb29aa67..454223e06f 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java @@ -47,7 +47,6 @@ import com.android.launcher3.appprediction.PredictionUiStateManager; import com.android.launcher3.appprediction.PredictionUiStateManager.Client; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.statehandlers.DepthController; -import com.android.launcher3.states.RotationHelper; import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; import com.android.launcher3.util.TraceHelper; import com.android.launcher3.views.ScrimView; @@ -88,10 +87,6 @@ public class LauncherRecentsView extends RecentsView } }; - private RotationHelper.ForcedRotationChangedListener mForcedRotationChangedListener = - isForcedRotation -> LauncherRecentsView.this - .disableMultipleLayoutRotations(!isForcedRotation); - public LauncherRecentsView(Context context) { this(context, null); } @@ -102,10 +97,15 @@ public class LauncherRecentsView extends RecentsView public LauncherRecentsView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - setContentAlpha(0); mActivity.getStateManager().addStateListener(this); } + @Override + public void init(OverviewActionsView actionsView) { + super.init(actionsView); + setContentAlpha(0); + } + @Override public void startHome() { if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { @@ -183,27 +183,6 @@ public class LauncherRecentsView extends RecentsView 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()) { @@ -344,7 +323,6 @@ public class LauncherRecentsView extends RecentsView super.onAttachedToWindow(); PluginManagerWrapper.INSTANCE.get(getContext()).addPluginListener( mRecentsExtraCardPluginListener, RecentsExtraCard.class); - mActivity.getRotationHelper().addForcedRotationCallback(mForcedRotationChangedListener); } @Override @@ -352,7 +330,6 @@ public class LauncherRecentsView extends RecentsView super.onDetachedFromWindow(); PluginManagerWrapper.INSTANCE.get(getContext()).removePluginListener( mRecentsExtraCardPluginListener); - mActivity.getRotationHelper().removeForcedRotationCallback(mForcedRotationChangedListener); } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java index 6a37e2b7de..93e68c0f5d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java @@ -16,34 +16,59 @@ package com.android.quickstep.views; +import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS; +import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview; + import android.content.Context; import android.util.AttributeSet; -import android.view.LayoutInflater; import android.view.View; +import android.view.View.OnClickListener; import android.widget.FrameLayout; +import androidx.annotation.IntDef; import androidx.annotation.Nullable; import com.android.launcher3.R; +import com.android.launcher3.util.MultiValueAlpha; +import com.android.launcher3.util.MultiValueAlpha.AlphaProperty; +import com.android.quickstep.TaskOverlayFactory.OverlayUICallbacks; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; /** * View for showing action buttons in Overview */ -public class OverviewActionsView extends FrameLayout { +public class OverviewActionsView extends FrameLayout + implements OnClickListener { - private final View mScreenshotButton; - private final View mShareButton; + @IntDef(flag = true, value = { + HIDDEN_UNSUPPORTED_NAVIGATION, + HIDDEN_DISABLED_FEATURE, + HIDDEN_NON_ZERO_ROTATION, + HIDDEN_NO_TASKS, + HIDDEN_GESTURE_RUNNING, + HIDDEN_NO_RECENTS}) + @Retention(RetentionPolicy.SOURCE) + public @interface ActionsHiddenFlags { } - /** - * Listener for taps on the various actions. - */ - public interface Listener { - /** User has initiated the share actions. */ - void onShare(); + public static final int HIDDEN_UNSUPPORTED_NAVIGATION = 1 << 0; + public static final int HIDDEN_DISABLED_FEATURE = 1 << 1; + public static final int HIDDEN_NON_ZERO_ROTATION = 1 << 2; + public static final int HIDDEN_NO_TASKS = 1 << 3; + public static final int HIDDEN_GESTURE_RUNNING = 1 << 4; + public static final int HIDDEN_NO_RECENTS = 1 << 5; - /** User has initiated the screenshot action. */ - void onScreenshot(); - } + private static final int INDEX_CONTENT_ALPHA = 0; + private static final int INDEX_VISIBILITY_ALPHA = 1; + private static final int INDEX_HIDDEN_FLAGS_ALPHA = 2; + + private final MultiValueAlpha mMultiValueAlpha; + + @ActionsHiddenFlags + private int mHiddenFlags; + + protected T mCallbacks; public OverviewActionsView(Context context) { this(context, null); @@ -54,26 +79,62 @@ public class OverviewActionsView extends FrameLayout { } public OverviewActionsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - this(context, attrs, defStyleAttr, 0); + super(context, attrs, defStyleAttr, 0); + mMultiValueAlpha = new MultiValueAlpha(this, 3); } - public OverviewActionsView(Context context, AttributeSet attrs, int defStyleAttr, - int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - LayoutInflater.from(context).inflate(R.layout.overview_actions, this, true); - mShareButton = findViewById(R.id.action_share); - mScreenshotButton = findViewById(R.id.action_screenshot); + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + findViewById(R.id.action_share).setOnClickListener(this); + findViewById(R.id.action_screenshot).setOnClickListener(this); } /** * Set listener for callbacks on action button taps. * - * @param listener for callbacks, or {@code null} to clear the listener. + * @param callbacks for callbacks, or {@code null} to clear the listener. */ - public void setListener(@Nullable OverviewActionsView.Listener listener) { - mShareButton.setOnClickListener( - listener == null ? null : view -> listener.onShare()); - mScreenshotButton.setOnClickListener( - listener == null ? null : view -> listener.onScreenshot()); + public void setCallbacks(T callbacks) { + mCallbacks = callbacks; + } + + @Override + public void onClick(View view) { + if (mCallbacks == null) { + return; + } + int id = view.getId(); + if (id == R.id.action_share) { + mCallbacks.onShare(); + } else if (id == R.id.action_screenshot) { + mCallbacks.onScreenshot(); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + updateHiddenFlags(HIDDEN_DISABLED_FEATURE, !ENABLE_OVERVIEW_ACTIONS.get()); + updateHiddenFlags(HIDDEN_UNSUPPORTED_NAVIGATION, !removeShelfFromOverview(getContext())); + } + + public void updateHiddenFlags(@ActionsHiddenFlags int visibilityFlags, boolean enable) { + if (enable) { + mHiddenFlags |= visibilityFlags; + } else { + mHiddenFlags &= ~visibilityFlags; + } + boolean isHidden = mHiddenFlags != 0; + mMultiValueAlpha.getProperty(INDEX_HIDDEN_FLAGS_ALPHA).setValue(isHidden ? 0 : 1); + setVisibility(isHidden ? INVISIBLE : VISIBLE); + } + + public AlphaProperty getContentAlpha() { + return mMultiValueAlpha.getProperty(INDEX_CONTENT_ALPHA); + } + + public AlphaProperty getVisibilityAlpha() { + return mMultiValueAlpha.getProperty(INDEX_VISIBILITY_ALPHA); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java index a18f7bae05..b687920f49 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java @@ -28,7 +28,6 @@ import static com.android.launcher3.anim.Interpolators.ACCEL; import static com.android.launcher3.anim.Interpolators.ACCEL_2; import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.LINEAR; -import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_DISMISS_SWIPE_UP; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_LAUNCH_SWIPE_DOWN; @@ -39,6 +38,10 @@ import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType. import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW; import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId; +import static com.android.quickstep.views.OverviewActionsView.HIDDEN_GESTURE_RUNNING; +import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NON_ZERO_ROTATION; +import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_RECENTS; +import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_TASKS; import android.animation.AnimatorSet; import android.animation.LayoutTransition; @@ -50,8 +53,10 @@ import android.app.ActivityManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Point; +import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Typeface; @@ -66,12 +71,12 @@ import android.util.AttributeSet; import android.util.FloatProperty; import android.util.Property; import android.util.SparseBooleanArray; -import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.OrientationEventListener; +import android.view.Surface; import android.view.View; import android.view.ViewDebug; import android.view.ViewGroup; @@ -85,9 +90,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.BaseActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Insettable; -import com.android.launcher3.InsettableFrameLayout; 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; @@ -115,19 +118,18 @@ import com.android.quickstep.RecentsAnimationController; import com.android.quickstep.RecentsAnimationTargets; import com.android.quickstep.RecentsModel; import com.android.quickstep.RecentsModel.TaskVisualsChangeListener; -import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SystemUiProxy; 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; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.ConfigurationCompat; import com.android.systemui.shared.system.LauncherEventUtil; import com.android.systemui.shared.system.PackageManagerWrapper; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat; @@ -172,8 +174,23 @@ public abstract class RecentsView extends PagedView impl } }; - protected final RecentsOrientedState mOrientationState = new RecentsOrientedState(); + public static final FloatProperty ADJACENT_PAGE_OFFSET = + new FloatProperty("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; @@ -185,6 +202,7 @@ public abstract class RecentsView 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; @@ -195,7 +213,6 @@ public abstract class RecentsView 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(); @@ -214,6 +231,8 @@ public abstract class RecentsView extends PagedView impl private boolean mOverlayEnabled; protected boolean mFreezeViewVisibility; + private float mAdjacentPageOffset = 0; + /** * TODO: Call reloadIdNeeded in onTaskStackChanged. */ @@ -282,6 +301,9 @@ public abstract class RecentsView extends PagedView impl } }; + private final RecentsOrientedState.SystemRotationChangeListener mSystemRotationChangeListener = + enabled -> toggleOrientationEventListener(); + private final PinnedStackAnimationListener mIPinnedStackAnimationListener = new PinnedStackAnimationListener(); @@ -328,8 +350,7 @@ public abstract class RecentsView extends PagedView impl // Keeps track of the index where the first TaskView should be private int mTaskViewStartIndex = 0; - private View mActionsView; - private boolean mGestureRunning = false; + private OverviewActionsView mActionsView; private BaseActivity.MultiWindowModeChangedListener mMultiWindowModeChangedListener = (inMultiWindowMode) -> { @@ -343,10 +364,11 @@ public abstract class RecentsView extends PagedView impl super(context, attrs, defStyleAttr); setPageSpacing(getResources().getDimensionPixelSize(R.dimen.recents_page_spacing)); setEnableFreeScroll(true); + mOrientationState = new RecentsOrientedState(context); 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 = @@ -362,7 +384,6 @@ public abstract class RecentsView 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); @@ -389,11 +410,6 @@ public abstract class RecentsView extends PagedView impl int rotation = RecentsOrientedState.getRotationForUserDegreesRotated(i); if (mPreviousRotation != rotation) { animateRecentsRotationInPlace(rotation); - if (rotation == 0) { - showActionsView(); - } else { - hideActionsView(); - } mPreviousRotation = rotation; } } @@ -468,6 +484,10 @@ public abstract class RecentsView extends PagedView impl reset(); } + public void init(OverviewActionsView actionsView) { + mActionsView = actionsView; + } + @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); @@ -481,7 +501,8 @@ public abstract class RecentsView extends PagedView impl mIPinnedStackAnimationListener.setActivity(mActivity); SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener( mIPinnedStackAnimationListener); - setActionsView(); + mOrientationState.init(); + mOrientationState.addSystemRotationChangeListener(mSystemRotationChangeListener); } @Override @@ -496,6 +517,8 @@ public abstract class RecentsView extends PagedView impl mIdp.removeOnChangeListener(this); SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(null); mIPinnedStackAnimationListener.setActivity(null); + mOrientationState.removeSystemRotationChangeListener(mSystemRotationChangeListener); + mOrientationState.destroy(); } @Override @@ -507,6 +530,7 @@ public abstract class RecentsView extends PagedView impl TaskView taskView = (TaskView) child; mHasVisibleTaskData.delete(taskView.getTask().key.id); mTaskViewPool.recycle(taskView); + mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, getTaskViewCount() == 0); } updateTaskStartIndex(child); } @@ -519,6 +543,7 @@ public abstract class RecentsView extends PagedView impl // child direction back to match system settings. child.setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_LTR : View.LAYOUT_DIRECTION_RTL); updateTaskStartIndex(child); + mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, false); } private void updateTaskStartIndex(View affectingView) { @@ -549,15 +574,6 @@ public abstract class RecentsView extends PagedView impl } public void setOverviewStateEnabled(boolean enabled) { - if (supportsVerticalLandscape() - && !TestProtocol.sDisableSensorRotation // Ignore hardware dependency for tests - && mOrientationListener.canDetectOrientation()) { - if (enabled) { - mOrientationListener.enable(); - } else { - mOrientationListener.disable(); - } - } mOverviewStateEnabled = enabled; updateTaskStackListenerState(); if (!enabled) { @@ -565,6 +581,26 @@ public abstract class RecentsView extends PagedView impl // its thumbnail mTmpRunningTask = null; } + toggleOrientationEventListener(); + } + + private void toggleOrientationEventListener() { + boolean canEnable = canEnableOverviewRotationAnimation() && mOverviewStateEnabled; + UI_HELPER_EXECUTOR.execute(() -> { + if (canEnable) { + mOrientationListener.enable(); + } else { + mOrientationListener.disable(); + } + }); + } + + private boolean canEnableOverviewRotationAnimation() { + return supportsVerticalLandscape() // not 3P launcher + && !TestProtocol.sDisableSensorRotation // Ignore hardware dependency for tests.. + && mOrientationListener.canDetectOrientation() // ..but does the hardware even work? + && (mOrientationState.isSystemRotationAllowed() && + !mOrientationState.canLauncherRotate()); // launcher is going to rotate itself } public void onDigitalWellbeingToastShown() { @@ -584,6 +620,15 @@ public abstract class RecentsView extends PagedView impl } } + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + int windowConfigurationRotation = ConfigurationCompat + .getWindowConfigurationRotation(getResources().getConfiguration()); + setLayoutInternal(mOrientationState.getTouchRotation(), + mOrientationState.getDisplayRotation(), windowConfigurationRotation); + } + @Override public boolean onTouchEvent(MotionEvent ev) { super.onTouchEvent(ev); @@ -668,7 +713,6 @@ public abstract class RecentsView extends PagedView impl if (getTaskViewCount() != requiredTaskCount) { if (indexOfChild(mClearAllButton) != -1) { removeView(mClearAllButton); - hideActionsView(); } for (int i = getTaskViewCount(); i < requiredTaskCount; i++) { addView(mTaskViewPool.getView()); @@ -678,7 +722,6 @@ public abstract class RecentsView extends PagedView impl } if (requiredTaskCount > 0) { addView(mClearAllButton); - showActionsView(); } } @@ -718,7 +761,6 @@ public abstract class RecentsView extends PagedView impl if (indexOfChild(mClearAllButton) != -1) { removeView(mClearAllButton); } - hideActionsView(); } public int getTaskViewCount() { @@ -778,7 +820,7 @@ public abstract class RecentsView extends PagedView impl for (int i = 0; i < taskCount; i++) { getTaskViewAt(i).setFullscreenProgress(mFullscreenProgress); } - if (mActionsView != null) { + if (mActionsView != null && mOrientationState.getLauncherRotation() == Surface.ROTATION_0) { mActionsView.setVisibility(fullscreenProgress == 0 ? VISIBLE : INVISIBLE); } } @@ -803,7 +845,6 @@ public abstract class RecentsView 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); @@ -980,7 +1021,7 @@ public abstract class RecentsView extends PagedView impl setEnableDrawingLiveTile(false); setRunningTaskHidden(true); setRunningTaskIconScaledDown(true); - mGestureRunning = true; + mActionsView.updateHiddenFlags(HIDDEN_GESTURE_RUNNING, true); } /** @@ -1046,7 +1087,7 @@ public abstract class RecentsView extends PagedView impl } setRunningTaskHidden(false); animateUpRunningTaskIconScale(); - mGestureRunning = false; + mActionsView.updateHiddenFlags(HIDDEN_GESTURE_RUNNING, false); } /** @@ -1057,13 +1098,12 @@ public abstract class RecentsView extends PagedView impl */ public void showCurrentTask(int runningTaskId) { if (getTaskView(runningTaskId) == null) { - boolean wasEmpty = getTaskViewCount() == 0; + boolean wasEmpty = getChildCount() == 0; // Add an empty view for now until the task plan is loaded and applied final TaskView taskView = mTaskViewPool.getView(); addView(taskView, mTaskViewStartIndex); if (wasEmpty) { addView(mClearAllButton); - showActionsView(); } // The temporary running task is only used for the duration between the start of the // gesture and the task list is loaded and applied @@ -1387,7 +1427,6 @@ public abstract class RecentsView extends PagedView impl if (getTaskViewCount() == 0) { removeViewInLayout(mClearAllButton); - hideActionsView(); startHome(); } else { snapToPageImmediately(pageToSnapTo); @@ -1530,14 +1569,12 @@ public abstract class RecentsView extends PagedView impl int alphaInt = Math.round(alpha * 255); mEmptyMessagePaint.setAlpha(alphaInt); mEmptyIcon.setAlpha(alphaInt); + mActionsView.getContentAlpha().setValue(mContentAlpha); + if (alpha > 0) { setVisibility(VISIBLE); - if (!mGestureRunning) { - showActionsView(); - } } else if (!mFreezeViewVisibility) { setVisibility(GONE); - hideActionsView(); } } @@ -1548,24 +1585,33 @@ public abstract class RecentsView extends PagedView impl public void setFreezeViewVisibility(boolean freezeViewVisibility) { if (mFreezeViewVisibility != freezeViewVisibility) { mFreezeViewVisibility = freezeViewVisibility; - if (!mFreezeViewVisibility) { setVisibility(mContentAlpha > 0 ? VISIBLE : GONE); - if (mContentAlpha > 0) { - showActionsView(); - } else { - hideActionsView(); - } } } } + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + if (mActionsView != null) { + mActionsView.updateHiddenFlags(HIDDEN_NO_RECENTS, visibility != VISIBLE); + } + } + public void setLayoutRotation(int touchRotation, int displayRotation) { - if (mOrientationState.update(touchRotation, displayRotation)) { + int launcherRotation = mOrientationState.getLauncherRotation(); + setLayoutInternal(touchRotation, displayRotation, launcherRotation); + } + + private void setLayoutInternal(int touchRotation, int displayRotation, int launcherRotation) { + if (mOrientationState.update(touchRotation, displayRotation, launcherRotation)) { mOrientationHandler = mOrientationState.getOrientationHandler(); mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources()); setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR); mClearAllButton.setRotation(mOrientationHandler.getDegreesRotated()); + mActivity.getDragLayer().recreateControllers(); + mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION, touchRotation != 0); requestLayout(); } } @@ -1589,11 +1635,6 @@ public abstract class RecentsView extends PagedView impl return getTaskViewAtByAbsoluteIndex(getRunningTaskIndex() + 1); } - @Nullable - public TaskView getPreviousTaskView() { - return getTaskViewAtByAbsoluteIndex(getRunningTaskIndex() - 1); - } - @Nullable public TaskView getCurrentPageTaskView() { return getTaskViewAtByAbsoluteIndex(getCurrentPage()); @@ -1653,11 +1694,29 @@ public abstract class RecentsView 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() { @@ -1739,14 +1798,10 @@ public abstract class RecentsView 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. @@ -2006,23 +2061,30 @@ public abstract class RecentsView 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 getEventDispatcher(float navbarRotation) { float degreesRotated; if (navbarRotation == 0) { - degreesRotated = mOrientationState.getTouchRotationDegrees(); + degreesRotated = mOrientationState.areMultipleLayoutOrientationsDisabled() ? 0 : + mOrientationHandler.getDegreesRotated(); } else { degreesRotated = -navbarRotation; } @@ -2035,7 +2097,8 @@ public abstract class RecentsView extends PagedView impl // PagedOrientationHandler return e -> { if (navbarRotation != 0 - && !mOrientationState.areMultipleLayoutOrientationsDisabled()) { + && !mOrientationState.areMultipleLayoutOrientationsDisabled() + && !mOrientationState.getOrientationHandler().isLayoutNaturalToLauncher()) { mOrientationState.flipVertical(e); super.onTouchEvent(e); mOrientationState.flipVertical(e); @@ -2122,36 +2185,4 @@ public abstract class RecentsView extends PagedView impl mActivity.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS); } } - - private void showActionsView() { - if (mActionsView != null && getTaskViewCount() > 0) { - mActionsView.setVisibility(VISIBLE); - } - } - - private void hideActionsView() { - if (mActionsView != null) { - mActionsView.setVisibility(GONE); - } - } - - private void setActionsView() { - if (mActionsView == null && ENABLE_OVERVIEW_ACTIONS.get() - && SysUINavigationMode.removeShelfFromOverview(mActivity)) { - mActionsView = ((ViewGroup) getParent()).findViewById(R.id.overview_actions_view); - if (mActionsView != null) { - InsettableFrameLayout.LayoutParams layoutParams = - new InsettableFrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, - getResources().getDimensionPixelSize( - R.dimen.overview_actions_height)); - layoutParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; - int margin = getResources().getDimensionPixelSize( - R.dimen.overview_actions_horizontal_margin); - layoutParams.setMarginStart(margin); - layoutParams.setMarginEnd(margin); - mActionsView.setLayoutParams(layoutParams); - showActionsView(); - } - } - } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java index 178ff32b4a..a05e0fa4fc 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java @@ -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 DIM_ALPHA = new FloatProperty("dimAlpha") { @Override @@ -87,12 +87,11 @@ public class TaskThumbnailView extends View implements PluginListener 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 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 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; + } + } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java index 470b720f5e..b0758c9e48 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java @@ -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; - } } } diff --git a/quickstep/res/drawable-v28/back_gesture_tutorial_action_button_background.xml b/quickstep/res/drawable-v28/gesture_tutorial_action_button_background.xml similarity index 90% rename from quickstep/res/drawable-v28/back_gesture_tutorial_action_button_background.xml rename to quickstep/res/drawable-v28/gesture_tutorial_action_button_background.xml index cd30ef7075..57423c2ffc 100644 --- a/quickstep/res/drawable-v28/back_gesture_tutorial_action_button_background.xml +++ b/quickstep/res/drawable-v28/gesture_tutorial_action_button_background.xml @@ -16,5 +16,5 @@ - + \ No newline at end of file diff --git a/quickstep/res/drawable/back_gesture_tutorial_action_button_background.xml b/quickstep/res/drawable/gesture_tutorial_action_button_background.xml similarity index 90% rename from quickstep/res/drawable/back_gesture_tutorial_action_button_background.xml rename to quickstep/res/drawable/gesture_tutorial_action_button_background.xml index d7b910273a..3f3b288e2d 100644 --- a/quickstep/res/drawable/back_gesture_tutorial_action_button_background.xml +++ b/quickstep/res/drawable/gesture_tutorial_action_button_background.xml @@ -16,5 +16,5 @@ - + \ No newline at end of file diff --git a/quickstep/res/drawable/back_gesture_tutorial_close_button.xml b/quickstep/res/drawable/gesture_tutorial_close_button.xml similarity index 100% rename from quickstep/res/drawable/back_gesture_tutorial_close_button.xml rename to quickstep/res/drawable/gesture_tutorial_close_button.xml diff --git a/quickstep/res/drawable/home_gesture.xml b/quickstep/res/drawable/home_gesture.xml new file mode 100644 index 0000000000..c253b7e5c3 --- /dev/null +++ b/quickstep/res/drawable/home_gesture.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/quickstep/res/layout/back_gesture_tutorial_fragment.xml b/quickstep/res/layout/back_gesture_tutorial_fragment.xml deleted file mode 100644 index d8c25bd4d0..0000000000 --- a/quickstep/res/layout/back_gesture_tutorial_fragment.xml +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - -