diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java index cfb00568d0..98e50f6b93 100644 --- a/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java +++ b/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java @@ -42,8 +42,6 @@ public class FloatingTaskThumbnailView extends View { private @Nullable BitmapShader mBitmapShader; private @Nullable Bitmap mBitmap; - private FloatingTaskView.FullscreenDrawParams mFullscreenParams; - public FloatingTaskThumbnailView(Context context) { this(context, null); } @@ -58,7 +56,7 @@ public class FloatingTaskThumbnailView extends View { @Override protected void onDraw(Canvas canvas) { - if (mFullscreenParams == null || mBitmap == null) { + if (mBitmap == null) { return; } @@ -67,9 +65,8 @@ public class FloatingTaskThumbnailView extends View { mMatrix.postScale(scale, scale); mBitmapShader.setLocalMatrix(mMatrix); - canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), - mFullscreenParams.mCurrentDrawnCornerRadius / mFullscreenParams.mScaleX, - mFullscreenParams.mCurrentDrawnCornerRadius / mFullscreenParams.mScaleY, mPaint); + FloatingTaskView parent = (FloatingTaskView) getParent(); + parent.drawRoundedRect(canvas, mPaint); } public void setThumbnail(Bitmap bitmap) { @@ -79,8 +76,4 @@ public class FloatingTaskThumbnailView extends View { mPaint.setShader(mBitmapShader); } } - - public void setFullscreenParams(FloatingTaskView.FullscreenDrawParams fullscreenParams) { - mFullscreenParams = fullscreenParams; - } } diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java index c59dc1893a..93a3a9f4bb 100644 --- a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java +++ b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java @@ -3,11 +3,12 @@ package com.android.quickstep.views; import static com.android.launcher3.anim.Interpolators.ACCEL; import static com.android.launcher3.anim.Interpolators.DEACCEL_3; import static com.android.launcher3.anim.Interpolators.LINEAR; -import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; @@ -31,15 +32,13 @@ import com.android.quickstep.util.MultiValueUpdateListener; import com.android.quickstep.util.TaskCornerRadius; import com.android.systemui.shared.system.QuickStepContract; -import java.util.function.Consumer; - /** * Create an instance via - * {@link #getFloatingTaskView(StatefulActivity, View, Bitmap, Drawable, RectF, Consumer)} to + * {@link #getFloatingTaskView(StatefulActivity, View, Bitmap, Drawable, RectF)} to * which will have the thumbnail from the provided existing TaskView overlaying the taskview itself. * * Can then animate the taskview using - * {@link #addAnimation(PendingAnimation, RectF, Rect, View, boolean)} + * {@link #addAnimation(PendingAnimation, RectF, Rect, boolean, boolean)} * giving a starting and ending bounds. Currently this is set to use the split placeholder view, * but it could be generified. * @@ -47,13 +46,13 @@ import java.util.function.Consumer; */ public class FloatingTaskView extends FrameLayout { + private FloatingTaskThumbnailView mThumbnailView; private SplitPlaceholderView mSplitPlaceholderView; private RectF mStartingPosition; private final StatefulActivity mActivity; private final boolean mIsRtl; - private final FullscreenDrawParams mCurrentFullscreenParams; + private final FullscreenDrawParams mFullscreenParams; private PagedOrientationHandler mOrientationHandler; - private FloatingTaskThumbnailView mThumbnailView; public FloatingTaskView(Context context) { this(context, null); @@ -67,17 +66,15 @@ public class FloatingTaskView extends FrameLayout { super(context, attrs, defStyleAttr); mActivity = BaseActivity.fromContext(context); mIsRtl = Utilities.isRtl(getResources()); - mCurrentFullscreenParams = new FullscreenDrawParams(context); + mFullscreenParams = new FullscreenDrawParams(context); } @Override protected void onFinishInflate() { super.onFinishInflate(); mThumbnailView = findViewById(R.id.thumbnail); - mThumbnailView.setFullscreenParams(mCurrentFullscreenParams); mSplitPlaceholderView = findViewById(R.id.split_placeholder); mSplitPlaceholderView.setAlpha(0); - mSplitPlaceholderView.setFullscreenParams(mCurrentFullscreenParams); } private void init(StatefulActivity launcher, View originalView, @Nullable Bitmap thumbnail, @@ -97,17 +94,13 @@ public class FloatingTaskView extends FrameLayout { RecentsView recentsView = launcher.getOverviewPanel(); mOrientationHandler = recentsView.getPagedOrientationHandler(); mSplitPlaceholderView.setIcon(icon, - launcher.getDeviceProfile().overviewTaskIconDrawableSizePx); + mContext.getResources().getDimensionPixelSize(R.dimen.split_placeholder_icon_size)); mSplitPlaceholderView.getIconView().setRotation(mOrientationHandler.getDegreesRotated()); } /** * Configures and returns a an instance of {@link FloatingTaskView} initially matching the * appearance of {@code originalView}. - * - * @param additionalOffsetter optional, to set additional offsets to the FloatingTaskView - * to account for translations. If {@code null} then the - * translation values from originalView will be used */ public static FloatingTaskView getFloatingTaskView(StatefulActivity launcher, View originalView, @Nullable Bitmap thumbnail, Drawable icon, RectF positionOut) { @@ -133,21 +126,22 @@ public class FloatingTaskView extends FrameLayout { setLayoutParams(lp); } - public void update(RectF position, float progress) { + public void update(RectF bounds, float progress) { MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams(); - float dX = position.left - mStartingPosition.left; - float dY = position.top - lp.topMargin; - float scaleX = position.width() / lp.width; - float scaleY = position.height() / lp.height; + float dX = bounds.left - mStartingPosition.left; + float dY = bounds.top - lp.topMargin; + float scaleX = bounds.width() / lp.width; + float scaleY = bounds.height() / lp.height; - mCurrentFullscreenParams.updateParams(position, progress, scaleX, scaleY); + mFullscreenParams.updateParams(bounds, progress, scaleX, scaleY); setTranslationX(dX); setTranslationY(dY); setScaleX(scaleX); setScaleY(scaleY); mSplitPlaceholderView.invalidate(); + mThumbnailView.invalidate(); float childScaleX = 1f / scaleX; float childScaleY = 1f / scaleY; @@ -178,8 +172,8 @@ public class FloatingTaskView extends FrameLayout { } public void addAnimation(PendingAnimation animation, RectF startingBounds, Rect endBounds, - boolean fadeWithThumbnail, boolean isInitialSplit) { - mCurrentFullscreenParams.setIsInitialSplit(isInitialSplit); + boolean fadeWithThumbnail, boolean isStagedTask) { + mFullscreenParams.setIsStagedTask(isStagedTask); final BaseDragLayer dragLayer = mActivity.getDragLayer(); int[] dragLayerBounds = new int[2]; dragLayer.getLocationOnScreen(dragLayerBounds); @@ -219,6 +213,25 @@ public class FloatingTaskView extends FrameLayout { transitionAnimator.addUpdateListener(listener); } + public void drawRoundedRect(Canvas canvas, Paint paint) { + if (mFullscreenParams == null) { + return; + } + + canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), + mFullscreenParams.mCurrentDrawnCornerRadius / mFullscreenParams.mScaleX, + mFullscreenParams.mCurrentDrawnCornerRadius / mFullscreenParams.mScaleY, + paint); + } + + public float getFullscreenScaleX() { + return mFullscreenParams.mScaleX; + } + + public float getFullscreenScaleY() { + return mFullscreenParams.mScaleY; + } + private static class SplitOverlayProperties { private final float finalTaskViewScaleX; @@ -247,9 +260,8 @@ public class FloatingTaskView extends FrameLayout { private final float mCornerRadius; private final float mWindowCornerRadius; - - public boolean mIsInitialSplit = true; - public final RectF mFloatingTaskViewBounds = new RectF(); + public boolean mIsStagedTask; + public final RectF mBounds = new RectF(); public float mCurrentDrawnCornerRadius; public float mScaleX = 1; public float mScaleY = 1; @@ -261,17 +273,16 @@ public class FloatingTaskView extends FrameLayout { mCurrentDrawnCornerRadius = mCornerRadius; } - public void updateParams(RectF floatingTaskViewBounds, float progress, float scaleX, - float scaleY) { - mFloatingTaskViewBounds.set(floatingTaskViewBounds); + public void updateParams(RectF bounds, float progress, float scaleX, float scaleY) { + mBounds.set(bounds); mScaleX = scaleX; mScaleY = scaleY; - mCurrentDrawnCornerRadius = mIsInitialSplit ? 0 : + mCurrentDrawnCornerRadius = mIsStagedTask ? mWindowCornerRadius : Utilities.mapRange(progress, mCornerRadius, mWindowCornerRadius); } - public void setIsInitialSplit(boolean isInitialSplit) { - mIsInitialSplit = isInitialSplit; + public void setIsStagedTask(boolean isStagedTask) { + mIsStagedTask = isStagedTask; } } } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 3c10e212fc..395bfb1b24 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -425,6 +425,7 @@ public abstract class RecentsView { if (success) { @@ -4002,14 +4005,14 @@ public abstract class RecentsView mSplitSelectStateController.setSecondTask( task, aBoolean1 -> RecentsView.this.resetFromSplitSelectionState())); @@ -4077,10 +4080,9 @@ public abstract class RecentsView ALPHA_FLOAT = new FloatProperty("SplitViewAlpha") { @@ -54,7 +53,7 @@ public class SplitPlaceholderView extends FrameLayout { public SplitPlaceholderView(Context context, AttributeSet attrs) { super(context, attrs); - mPaint.setColor(getThemePrimaryColor(context)); + mPaint.setColor(getThemeBackgroundColor(context)); setWillNotDraw(false); } @@ -64,6 +63,19 @@ public class SplitPlaceholderView extends FrameLayout { drawBackground(canvas); super.dispatchDraw(canvas); + + if (mIconView != null) { + // Center the icon view in the visible area. + getLocalVisibleRect(mTempRect); + FloatingTaskView parent = (FloatingTaskView) getParent(); + FrameLayout.LayoutParams params = + (FrameLayout.LayoutParams) mIconView.getLayoutParams(); + params.leftMargin = Math.round(mTempRect.centerX() / parent.getFullscreenScaleX() + - 1.0f * mIconView.getDrawableWidth() / 2); + params.topMargin = Math.round(mTempRect.centerY() / parent.getFullscreenScaleY() + - 1.0f * mIconView.getDrawableHeight() / 2); + mIconView.setLayoutParams(params); + } } @Nullable @@ -71,10 +83,6 @@ public class SplitPlaceholderView extends FrameLayout { return mIconView; } - public void setFullscreenParams(FloatingTaskView.FullscreenDrawParams fullscreenParams) { - mFullscreenParams = fullscreenParams; - } - public void setIcon(Drawable drawable, int iconSize) { if (mIconView == null) { mIconView = new IconView(getContext()); @@ -83,23 +91,17 @@ public class SplitPlaceholderView extends FrameLayout { mIconView.setDrawable(drawable); mIconView.setDrawableSize(iconSize, iconSize); FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(iconSize, iconSize); - params.gravity = Gravity.CENTER; mIconView.setLayoutParams(params); } private void drawBackground(Canvas canvas) { - if (mFullscreenParams == null) { - return; - } - - canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), - mFullscreenParams.mCurrentDrawnCornerRadius / mFullscreenParams.mScaleX, - mFullscreenParams.mCurrentDrawnCornerRadius / mFullscreenParams.mScaleY, mPaint); + FloatingTaskView parent = (FloatingTaskView) getParent(); + parent.drawRoundedRect(canvas, mPaint); } - private static int getThemePrimaryColor(Context context) { + private static int getThemeBackgroundColor(Context context) { final TypedValue value = new TypedValue(); - context.getTheme().resolveAttribute(android.R.attr.colorPrimary, value, true); + context.getTheme().resolveAttribute(android.R.attr.colorBackground, value, true); return value.data; } } diff --git a/res/values/dimens.xml b/res/values/dimens.xml index a6abee2341..0615053de8 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -359,7 +359,9 @@ 0dp 0dp 0dp - 110dp + 72dp + 16dp + 44dp 200dp diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java index 217a5583dd..4fcba18844 100644 --- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java @@ -394,12 +394,21 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { } @Override - public void getInitialSplitPlaceholderBounds(int placeholderHeight, DeviceProfile dp, - @StagePosition int stagePosition, Rect out) { + public void getInitialSplitPlaceholderBounds(int placeholderHeight, int placeholderInset, + DeviceProfile dp, @StagePosition int stagePosition, Rect out) { // In fake land/seascape, the placeholder always needs to go to the "top" of the device, // which is the same bounds as 0 rotation. int width = dp.widthPx; out.set(0, 0, width, placeholderHeight); + out.inset(placeholderInset, 0); + + // Adjust the top to account for content off screen. This will help to animate the view in + // with rounded corners. + int screenWidth = dp.widthPx; + int screenHeight = dp.heightPx; + int totalHeight = (int) (1.0f * screenHeight / 2 * (screenWidth - 2 * placeholderInset) + / screenWidth); + out.top -= (totalHeight - placeholderHeight); } @Override diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java index 1b171266fa..850eaaf9b4 100644 --- a/src/com/android/launcher3/touch/PagedOrientationHandler.java +++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java @@ -110,10 +110,10 @@ public interface PagedOrientationHandler { int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect); List getSplitPositionOptions(DeviceProfile dp); /** - * @param splitholderSize height of placeholder view in portrait, width in landscape + * @param placeholderHeight height of placeholder view in portrait, width in landscape */ - void getInitialSplitPlaceholderBounds(int splitholderSize, DeviceProfile dp, - @StagePosition int stagePosition, Rect out); + void getInitialSplitPlaceholderBounds(int placeholderHeight, int placeholderInset, + DeviceProfile dp, @StagePosition int stagePosition, Rect out); /** * @param splitDividerSize height of split screen drag handle in portrait, width in landscape diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java index 7e1cb256dc..d132901238 100644 --- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java +++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java @@ -436,29 +436,48 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { } @Override - public void getInitialSplitPlaceholderBounds(int placeholderHeight, DeviceProfile dp, - @StagePosition int stagePosition, Rect out) { - int width = dp.widthPx; - out.set(0, 0, width, placeholderHeight); + public void getInitialSplitPlaceholderBounds(int placeholderHeight, int placeholderInset, + DeviceProfile dp, @StagePosition int stagePosition, Rect out) { + int screenWidth = dp.widthPx; + int screenHeight = dp.heightPx; + out.set(0, 0, screenWidth, placeholderHeight); if (!dp.isLandscape) { // portrait, phone or tablet - spans width of screen, nothing else to do + out.inset(placeholderInset, 0); + + // Adjust the top to account for content off screen. This will help to animate the view + // in with rounded corners. + int totalHeight = (int) (1.0f * screenHeight / 2 * (screenWidth - 2 * placeholderInset) + / screenWidth); + out.top -= (totalHeight - placeholderHeight); return; } // Now we rotate the portrait rect depending on what side we want pinned boolean pinToRight = stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT; - int screenHeight = dp.heightPx; - float postRotateScale = (float) screenHeight / width; + float postRotateScale = (float) screenHeight / screenWidth; mTmpMatrix.reset(); mTmpMatrix.postRotate(pinToRight ? 90 : 270); - mTmpMatrix.postTranslate(pinToRight ? width : 0, pinToRight ? 0 : width); + mTmpMatrix.postTranslate(pinToRight ? screenWidth : 0, pinToRight ? 0 : screenWidth); // The placeholder height stays constant after rotation, so we don't change width scale mTmpMatrix.postScale(1, postRotateScale); mTmpRectF.set(out); mTmpMatrix.mapRect(mTmpRectF); + mTmpRectF.inset(0, placeholderInset); mTmpRectF.roundOut(out); + + // Adjust the top to account for content off screen. This will help to animate the view in + // with rounded corners. + int totalWidth = (int) (1.0f * screenWidth / 2 * (screenHeight - 2 * placeholderInset) + / screenHeight); + int width = out.width(); + if (pinToRight) { + out.right += totalWidth - width; + } else { + out.left -= totalWidth - width; + } } @Override