Merge "Fix fullscreen and landscape task insets" into ub-launcher3-qt-dev

This commit is contained in:
Tony Wickham
2019-05-13 23:43:48 +00:00
committed by Android (Google) Code Review
6 changed files with 137 additions and 94 deletions
@@ -17,13 +17,10 @@ package com.android.launcher3.uioverrides.states;
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
import android.graphics.Rect;
import com.android.launcher3.Launcher;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskThumbnailView;
import com.android.quickstep.views.TaskView;
/**
@@ -45,18 +42,9 @@ public class QuickSwitchState extends OverviewState {
if (recentsView.getTaskViewCount() == 0) {
return super.getOverviewScaleAndTranslation(launcher);
}
// Compute scale and translation y such that the most recent task view fills the screen.
TaskThumbnailView dummyThumbnail = recentsView.getTaskViewAt(0).getThumbnail();
TaskView dummyTask = recentsView.getTaskViewAt(0);
ClipAnimationHelper clipAnimationHelper = new ClipAnimationHelper(launcher);
clipAnimationHelper.fromTaskThumbnailView(dummyThumbnail, recentsView);
Rect targetRect = new Rect();
recentsView.getTaskSize(targetRect);
clipAnimationHelper.updateTargetRect(targetRect);
float toScale = clipAnimationHelper.getSourceRect().width()
/ clipAnimationHelper.getTargetRect().width();
float toTranslationY = clipAnimationHelper.getSourceRect().centerY()
- clipAnimationHelper.getTargetRect().centerY();
return new ScaleAndTranslation(toScale, 0, toTranslationY);
return clipAnimationHelper.getOverviewFullscreenScaleAndTranslation(dummyTask);
}
@Override
@@ -124,7 +124,7 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll
@Override
protected void updateProgress(float progress) {
super.updateProgress(progress);
updateFullscreenProgress(progress);
updateFullscreenProgress(Utilities.boundToRange(progress, 0, 1));
}
private void updateFullscreenProgress(float progress) {
@@ -301,34 +301,19 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
return;
}
// Setup the clip animation helper source/target rects in the final transformed state
// of the recents view (a scale/translationY may be applied prior to this animation
// starting to line up the side pages during swipe up)
float prevRvScale = recentsView.getScaleX();
float prevRvTransY = recentsView.getTranslationY();
float targetRvScale = endState.getOverviewScaleAndTranslation(launcher).scale;
SCALE_PROPERTY.set(recentsView, targetRvScale);
recentsView.setTranslationY(0);
ClipAnimationHelper clipHelper = new ClipAnimationHelper(launcher);
float tmpCurveScale = v.getCurveScale();
v.setCurveScale(1f);
clipHelper.fromTaskThumbnailView(v.getThumbnail(), (RecentsView) v.getParent(), null);
v.setCurveScale(tmpCurveScale);
SCALE_PROPERTY.set(recentsView, prevRvScale);
recentsView.setTranslationY(prevRvTransY);
LauncherState.ScaleAndTranslation fromScaleAndTranslation
= clipHelper.getOverviewFullscreenScaleAndTranslation(v);
LauncherState.ScaleAndTranslation endScaleAndTranslation
= endState.getOverviewScaleAndTranslation(launcher);
if (!clipHelper.getSourceRect().isEmpty() && !clipHelper.getTargetRect().isEmpty()) {
float fromScale = clipHelper.getSourceRect().width()
/ clipHelper.getTargetRect().width();
float fromTranslationY = clipHelper.getSourceRect().centerY()
- clipHelper.getTargetRect().centerY();
Animator scale = ObjectAnimator.ofFloat(recentsView, SCALE_PROPERTY, fromScale, 1);
Animator translateY = ObjectAnimator.ofFloat(recentsView, TRANSLATION_Y,
fromTranslationY, 0);
scale.setInterpolator(LINEAR);
translateY.setInterpolator(LINEAR);
anim.playTogether(scale, translateY);
}
Animator scale = ObjectAnimator.ofFloat(recentsView, SCALE_PROPERTY,
fromScaleAndTranslation.scale, endScaleAndTranslation.scale);
Animator translateY = ObjectAnimator.ofFloat(recentsView, TRANSLATION_Y,
fromScaleAndTranslation.translationY, endScaleAndTranslation.translationY);
scale.setInterpolator(LINEAR);
translateY.setInterpolator(LINEAR);
anim.playTogether(scale, translateY);
}
@Override
@@ -35,12 +35,14 @@ 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.views.BaseDragLayer;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskThumbnailView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.recents.utilities.RectFEvaluator;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -280,6 +282,21 @@ public class ClipAnimationHelper {
}
}
/**
* Compute scale and translation y such that the specified task view fills the screen.
*/
public LauncherState.ScaleAndTranslation getOverviewFullscreenScaleAndTranslation(TaskView v) {
TaskThumbnailView thumbnailView = v.getThumbnail();
RecentsView recentsView = v.getRecentsView();
fromTaskThumbnailView(thumbnailView, recentsView);
Rect taskSize = new Rect();
recentsView.getTaskSize(taskSize);
updateTargetRect(taskSize);
float scale = mSourceRect.width() / mTargetRect.width();
float translationY = mSourceRect.centerY() - mSourceRect.top - mTargetRect.centerY();
return new LauncherState.ScaleAndTranslation(scale, 0, translationY);
}
private void updateStackBoundsToMultiWindowTaskSize(BaseDraggingActivity activity) {
ISystemUiProxy sysUiProxy = RecentsModel.INSTANCE.get(activity).getSystemUiProxy();
if (sysUiProxy != null) {
@@ -33,6 +33,7 @@ import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.FloatProperty;
@@ -59,7 +60,7 @@ public class TaskThumbnailView extends View {
private final static ColorMatrix COLOR_MATRIX = new ColorMatrix();
private final static ColorMatrix SATURATION_COLOR_MATRIX = new ColorMatrix();
private final static Rect EMPTY_RECT = new Rect();
private final static RectF EMPTY_RECT_F = new RectF();
public static final Property<TaskThumbnailView, Float> DIM_ALPHA =
new FloatProperty<TaskThumbnailView>("dimAlpha") {
@@ -87,10 +88,9 @@ public class TaskThumbnailView extends View {
private final Matrix mMatrix = new Matrix();
private float mClipBottom = -1;
private Rect mScaledInsets = new Rect();
private Rect mCurrentDrawnInsets = new Rect();
private float mCurrentDrawnCornerRadius;
private boolean mIsRotated;
// Contains the portion of the thumbnail that is clipped when fullscreen progress = 0.
private RectF mClippedInsets = new RectF();
private TaskView.FullscreenDrawParams mFullscreenParams;
private Task mTask;
private ThumbnailData mThumbnailData;
@@ -118,7 +118,7 @@ public class TaskThumbnailView extends View {
mDimmingPaintAfterClearing.setColor(Color.BLACK);
mActivity = BaseActivity.fromContext(context);
mIsDarkTextTheme = Themes.getAttrBoolean(mActivity, R.attr.isWorkspaceDarkText);
setCurrentDrawnInsetsAndRadius(EMPTY_RECT, mCornerRadius);
mFullscreenParams = new TaskView.FullscreenDrawParams(mCornerRadius);
}
public void bind(Task task) {
@@ -201,23 +201,27 @@ public class TaskThumbnailView extends View {
@Override
protected void onDraw(Canvas canvas) {
RectF currentDrawnInsets = mFullscreenParams.mCurrentDrawnInsets;
canvas.save();
canvas.translate(currentDrawnInsets.left, currentDrawnInsets.top);
canvas.scale(mFullscreenParams.mScale, mFullscreenParams.mScale);
// Draw the insets if we're being drawn fullscreen (we do this for quick switch).
drawOnCanvas(canvas,
-mCurrentDrawnInsets.left,
-mCurrentDrawnInsets.top,
getMeasuredWidth() + mCurrentDrawnInsets.right,
getMeasuredHeight() + mCurrentDrawnInsets.bottom,
mCurrentDrawnCornerRadius);
-currentDrawnInsets.left,
-currentDrawnInsets.top,
getMeasuredWidth() + currentDrawnInsets.right,
getMeasuredHeight() + currentDrawnInsets.bottom,
mFullscreenParams.mCurrentDrawnCornerRadius);
canvas.restore();
}
public Rect getInsetsToDrawInFullscreen(boolean isMultiWindowMode) {
// Don't show insets in the wrong orientation or in multi window mode.
return mIsRotated || isMultiWindowMode ? EMPTY_RECT : mScaledInsets;
public RectF getInsetsToDrawInFullscreen(boolean isMultiWindowMode) {
// Don't show insets in multi window mode.
return isMultiWindowMode ? EMPTY_RECT_F : mClippedInsets;
}
public void setCurrentDrawnInsetsAndRadius(Rect insets, float radius) {
mCurrentDrawnInsets.set(insets);
mCurrentDrawnCornerRadius = radius;
public void setFullscreenParams(TaskView.FullscreenDrawParams fullscreenParams) {
mFullscreenParams = fullscreenParams;
invalidate();
}
@@ -275,7 +279,7 @@ public class TaskThumbnailView extends View {
}
private void updateThumbnailMatrix() {
mIsRotated = false;
boolean isRotated = false;
mClipBottom = -1;
if (mBitmapShader != null && mThumbnailData != null) {
float scale = mThumbnailData.scale;
@@ -296,30 +300,28 @@ public class TaskThumbnailView extends View {
final Configuration configuration =
getContext().getResources().getConfiguration();
// Rotate the screenshot if not in multi-window mode
mIsRotated = FeatureFlags.OVERVIEW_USE_SCREENSHOT_ORIENTATION &&
isRotated = FeatureFlags.OVERVIEW_USE_SCREENSHOT_ORIENTATION &&
configuration.orientation != mThumbnailData.orientation &&
!mActivity.isInMultiWindowMode() &&
mThumbnailData.windowingMode == WINDOWING_MODE_FULLSCREEN;
// Scale the screenshot to always fit the width of the card.
thumbnailScale = mIsRotated
thumbnailScale = isRotated
? getMeasuredWidth() / thumbnailHeight
: getMeasuredWidth() / thumbnailWidth;
}
mScaledInsets.set(thumbnailInsets);
Utilities.scaleRect(mScaledInsets, thumbnailScale);
if (mIsRotated) {
if (isRotated) {
int rotationDir = profile.isVerticalBarLayout() && !profile.isSeascape() ? -1 : 1;
mMatrix.setRotate(90 * rotationDir);
int newLeftInset = rotationDir == 1 ? thumbnailInsets.bottom : thumbnailInsets.top;
int newTopInset = rotationDir == 1 ? thumbnailInsets.left : thumbnailInsets.right;
mMatrix.postTranslate(-newLeftInset * scale, -newTopInset * scale);
mClippedInsets.offsetTo(newLeftInset * scale, newTopInset * scale);
if (rotationDir == -1) {
// Crop the right/bottom side of the screenshot rather than left/top
float excessHeight = thumbnailWidth * thumbnailScale - getMeasuredHeight();
mMatrix.postTranslate(0, -excessHeight);
mClippedInsets.offset(0, excessHeight);
}
mMatrix.postTranslate(-mClippedInsets.left, -mClippedInsets.top);
// Move the screenshot to the thumbnail window (rotation moved it out).
if (rotationDir == 1) {
mMatrix.postTranslate(mThumbnailData.thumbnail.getHeight(), 0);
@@ -327,13 +329,28 @@ public class TaskThumbnailView extends View {
mMatrix.postTranslate(0, mThumbnailData.thumbnail.getWidth());
}
} else {
mMatrix.setTranslate(-mThumbnailData.insets.left * scale,
-mThumbnailData.insets.top * scale);
mClippedInsets.offsetTo(thumbnailInsets.left * scale, thumbnailInsets.top * scale);
mMatrix.setTranslate(-mClippedInsets.left, -mClippedInsets.top);
}
final float widthWithInsets;
final float heightWithInsets;
if (isRotated) {
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((mIsRotated ? thumbnailWidth : thumbnailHeight)
float bitmapHeight = Math.max((isRotated ? thumbnailWidth : thumbnailHeight)
* thumbnailScale, 0);
if (Math.round(bitmapHeight) < getMeasuredHeight()) {
mClipBottom = bitmapHeight;
@@ -341,7 +358,7 @@ public class TaskThumbnailView extends View {
mPaint.setShader(mBitmapShader);
}
if (mIsRotated) {
if (isRotated) {
// The overlay doesn't really work when the screenshot is rotated, so don't add it.
mOverlay.reset();
} else {
@@ -32,6 +32,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.Outline;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
@@ -166,7 +167,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
private float mCurveScale;
private float mZoomScale;
private float mFullscreenProgress;
private final Rect mCurrentDrawnInsets = new Rect();
private final FullscreenDrawParams mCurrentFullscreenParams;
private final float mCornerRadius;
private final float mWindowCornerRadius;
private final BaseDraggingActivity mActivity;
@@ -214,7 +215,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
});
mCornerRadius = TaskCornerRadius.get(context);
mWindowCornerRadius = QuickStepContract.getWindowCornerRadius(context.getResources());
mOutlineProvider = new TaskOutlineProvider(getResources(), mCornerRadius);
mCurrentFullscreenParams = new FullscreenDrawParams(mCornerRadius);
mOutlineProvider = new TaskOutlineProvider(getResources(), mCurrentFullscreenParams);
setOutlineProvider(mOutlineProvider);
}
@@ -540,26 +542,26 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
private static final class TaskOutlineProvider extends ViewOutlineProvider {
private final int mMarginTop;
private final Rect mInsets = new Rect();
private float mRadius;
private FullscreenDrawParams mFullscreenParams;
TaskOutlineProvider(Resources res, float radius) {
TaskOutlineProvider(Resources res, FullscreenDrawParams fullscreenParams) {
mMarginTop = res.getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
mRadius = radius;
mFullscreenParams = fullscreenParams;
}
public void setCurrentDrawnInsetsAndRadius(Rect insets, float radius) {
mInsets.set(insets);
mRadius = radius;
public void setFullscreenParams(FullscreenDrawParams params) {
mFullscreenParams = params;
}
@Override
public void getOutline(View view, Outline outline) {
outline.setRoundRect(-mInsets.left,
mMarginTop - mInsets.top,
view.getWidth() + mInsets.right,
view.getHeight() + mInsets.bottom,
mRadius);
RectF insets = mFullscreenParams.mCurrentDrawnInsets;
float scale = mFullscreenParams.mScale;
outline.setRoundRect(0,
(int) (mMarginTop * scale),
(int) ((insets.left + view.getWidth() + insets.right) * scale),
(int) ((insets.top + view.getHeight() + insets.bottom) * scale),
mFullscreenParams.mCurrentDrawnCornerRadius);
}
}
@@ -658,17 +660,25 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
TaskThumbnailView thumbnail = getThumbnail();
boolean isMultiWindowMode = mActivity.getDeviceProfile().isMultiWindowMode;
Rect insets = thumbnail.getInsetsToDrawInFullscreen(isMultiWindowMode);
mCurrentDrawnInsets.set((int) (insets.left * mFullscreenProgress),
(int) (insets.top * mFullscreenProgress),
(int) (insets.right * mFullscreenProgress),
(int) (insets.bottom * mFullscreenProgress));
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;
float cornerRadius = Utilities.mapRange(mFullscreenProgress, mCornerRadius,
fullscreenCornerRadius) / getRecentsView().getScaleX();
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));
}
thumbnail.setCurrentDrawnInsetsAndRadius(mCurrentDrawnInsets, cornerRadius);
mOutlineProvider.setCurrentDrawnInsetsAndRadius(mCurrentDrawnInsets, cornerRadius);
thumbnail.setFullscreenParams(mCurrentFullscreenParams);
mOutlineProvider.setFullscreenParams(mCurrentFullscreenParams);
invalidateOutline();
}
@@ -686,4 +696,30 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
}
return mShowScreenshot;
}
/**
* We update and subsequently draw these in {@link #setFullscreenProgress(float)}.
*/
static class FullscreenDrawParams {
RectF mCurrentDrawnInsets = new RectF();
float mCurrentDrawnCornerRadius;
/** The current scale we apply to the thumbnail to adjust for new left/right insets. */
float mScale = 1;
public FullscreenDrawParams(float cornerRadius) {
setCornerRadius(cornerRadius);
}
public void setInsets(float left, float top, float right, float bottom) {
mCurrentDrawnInsets.set(left, top, right, bottom);
}
public void setCornerRadius(float cornerRadius) {
mCurrentDrawnCornerRadius = cornerRadius;
}
public void setScale(float scale) {
mScale = scale;
}
}
}