Merge "Show splash screen in quickswitch if thumbnail wrong aspect/orientation." into tm-qpr-dev

This commit is contained in:
Pat Manning
2022-07-13 13:56:34 +00:00
committed by Android (Google) Code Review
8 changed files with 195 additions and 4 deletions

View File

@@ -36,6 +36,7 @@
<dimen name="task_thumbnail_icon_drawable_size">44dp</dimen>
<dimen name="overview_task_margin">16dp</dimen>
<dimen name="overview_page_spacing">16dp</dimen>
<dimen name="task_icon_cache_default_icon_size">72dp</dimen>
<item name="overview_max_scale" format="float" type="dimen">0.7</item>
<item name="overview_modal_max_scale" format="float" type="dimen">1.1</item>

View File

@@ -28,6 +28,7 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TR
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.launcher3.testing.TestProtocol.BAD_STATE;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
import static com.android.quickstep.views.RecentsView.OVERVIEW_PROGRESS;
import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
@@ -74,6 +75,7 @@ public abstract class BaseRecentsViewStateController<T extends RecentsView>
getTaskModalnessProperty().set(mRecentsView, state.getOverviewModalness());
RECENTS_GRID_PROGRESS.set(mRecentsView,
state.displayOverviewTasksAsGrid(mLauncher.getDeviceProfile()) ? 1f : 0f);
OVERVIEW_PROGRESS.set(mRecentsView, state == LauncherState.OVERVIEW ? 1f : 0f);
}
@Override
@@ -117,6 +119,9 @@ public abstract class BaseRecentsViewStateController<T extends RecentsView>
boolean showAsGrid = toState.displayOverviewTasksAsGrid(mLauncher.getDeviceProfile());
setter.setFloat(mRecentsView, RECENTS_GRID_PROGRESS, showAsGrid ? 1f : 0f,
showAsGrid ? INSTANT : FINAL_FRAME);
setter.setFloat(mRecentsView, OVERVIEW_PROGRESS,
toState == LauncherState.OVERVIEW ? 1f : 0f, INSTANT);
}
abstract FloatProperty getTaskModalnessProperty();

View File

@@ -263,7 +263,8 @@ public class TaskIconCache implements DisplayInfoChangeListener {
if (mIconFactory == null) {
mIconFactory = new BaseIconFactory(mContext,
DisplayController.INSTANCE.get(mContext).getInfo().getDensityDpi(),
mContext.getResources().getDimensionPixelSize(R.dimen.taskbar_icon_size));
mContext.getResources().getDimensionPixelSize(
R.dimen.task_icon_cache_default_icon_size));
}
return mIconFactory;
}

View File

@@ -27,6 +27,7 @@ import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.quickstep.fallback.RecentsState.OVERVIEW_SPLIT_SELECT;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import static com.android.quickstep.views.RecentsView.OVERVIEW_PROGRESS;
import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.quickstep.views.RecentsView.TASK_MODALNESS;
@@ -105,6 +106,8 @@ public class FallbackRecentsStateController implements StateHandler<RecentsState
boolean showAsGrid = state.displayOverviewTasksAsGrid(mActivity.getDeviceProfile());
setter.setFloat(mRecentsView, RECENTS_GRID_PROGRESS, showAsGrid ? 1f : 0f,
showAsGrid ? INSTANT : FINAL_FRAME);
setter.setFloat(mRecentsView, OVERVIEW_PROGRESS, state == RecentsState.DEFAULT ? 1f : 0f,
INSTANT);
setter.setViewBackgroundColor(mActivity.getScrimView(), state.getScrimColor(mActivity),
config.getInterpolator(ANIM_SCRIM_FADE, LINEAR));

View File

@@ -1,5 +1,6 @@
package com.android.quickstep.views;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
@@ -313,4 +314,11 @@ public class GroupedTaskView extends TaskView {
mSnapshotView2.setDimAlpha(amount);
mDigitalWellBeingToast2.setBannerColorTint(tintColor, amount);
}
@Override
protected void applyThumbnailSplashAlpha() {
super.applyThumbnailSplashAlpha();
mSnapshotView2.setSplashAlpha(
Utilities.mapToRange(mOverviewProgress, 0f, 1f, 1f, 0f, LINEAR));
}
}

View File

@@ -363,6 +363,10 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
}
};
/**
* Progress of Recents view from carousel layout to grid layout. If Recents is not shown as a
* grid, then the value remains 0.
*/
public static final FloatProperty<RecentsView> RECENTS_GRID_PROGRESS =
new FloatProperty<RecentsView>("recentsGrid") {
@Override
@@ -376,6 +380,23 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
}
};
/**
* Progress to and from the OVERVIEW state, where being in OverviewState has a value of 1, and
* being in any other LauncherState has a value of 0.
*/
public static final FloatProperty<RecentsView> OVERVIEW_PROGRESS =
new FloatProperty<RecentsView>("overviewProgress") {
@Override
public void setValue(RecentsView view, float overviewProgress) {
view.setOverviewProgress(overviewProgress);
}
@Override
public Float get(RecentsView view) {
return view.mOverviewProgress;
}
};
// OverScroll constants
private static final int OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION = 270;
@@ -466,6 +487,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
protected float mTaskViewsSecondarySplitTranslation = 0;
// Progress from 0 to 1 where 0 is a carousel and 1 is a 2 row grid.
private float mGridProgress = 0;
private float mOverviewProgress = 0;
private boolean mShowAsGridLastOnLayout = false;
private final IntSet mTopRowIdSet = new IntSet();
@@ -2661,6 +2683,18 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
mClearAllButton.setGridProgress(gridProgress);
}
private void setOverviewProgress(float overviewProgress) {
int taskCount = getTaskViewCount();
if (taskCount == 0) {
return;
}
mOverviewProgress = overviewProgress;
for (int i = 0; i < taskCount; i++) {
requireTaskViewAt(i).setOverviewProgress(overviewProgress);
}
}
private void enableLayoutTransitions() {
if (mLayoutTransition == null) {
mLayoutTransition = new LayoutTransition();
@@ -4301,6 +4335,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
properties));
}
}
anim.play(ObjectAnimator.ofFloat(recentsView, OVERVIEW_PROGRESS, 1, 0));
return anim;
}
@@ -4360,6 +4395,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
BACKGROUND_APP.getDepth(mActivity));
anim.play(depthAnimator);
}
anim.play(ObjectAnimator.ofFloat(this, OVERVIEW_PROGRESS, 1f, 0f));
anim.play(progressAnim);
anim.setInterpolator(interpolator);

View File

@@ -36,12 +36,14 @@ import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.Property;
import android.view.Surface;
import android.view.View;
import android.widget.ImageView;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
@@ -50,6 +52,7 @@ import androidx.core.graphics.ColorUtils;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.SystemUiController.SystemUiControllerFlags;
@@ -64,6 +67,7 @@ import com.android.systemui.shared.recents.model.ThumbnailData;
public class TaskThumbnailView extends View {
private static final MainThreadInitializedObject<FullscreenDrawParams> TEMP_PARAMS =
new MainThreadInitializedObject<>(FullscreenDrawParams::new);
private static final float MAX_PCT_BEFORE_ASPECT_RATIOS_CONSIDERED_DIFFERENT = 0.1f;
public static final Property<TaskThumbnailView, Float> DIM_ALPHA =
new FloatProperty<TaskThumbnailView>("dimAlpha") {
@@ -83,6 +87,7 @@ public class TaskThumbnailView extends View {
private TaskOverlay mOverlay;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint mSplashBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint mClearPaint = new Paint();
private final Paint mDimmingPaintAfterClearing = new Paint();
private final int mDimColor;
@@ -91,6 +96,8 @@ public class TaskThumbnailView extends View {
private final Rect mPreviewRect = new Rect();
private final PreviewPositionHelper mPreviewPositionHelper = new PreviewPositionHelper();
private TaskView.FullscreenDrawParams mFullscreenParams;
private ImageView mSplashView;
private Drawable mSplashViewDrawable;
@Nullable
private Task mTask;
@@ -101,6 +108,8 @@ public class TaskThumbnailView extends View {
/** How much this thumbnail is dimmed, 0 not dimmed at all, 1 totally dimmed. */
private float mDimAlpha = 0f;
/** Controls visibility of the splash view, 0 is transparent, 255 fully opaque. */
private int mSplashAlpha = 0;
private boolean mOverlayEnabled;
@@ -116,6 +125,7 @@ public class TaskThumbnailView extends View {
super(context, attrs, defStyleAttr);
mPaint.setFilterBitmap(true);
mBackgroundPaint.setColor(Color.WHITE);
mSplashBackgroundPaint.setColor(Color.WHITE);
mClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
mActivity = BaseActivity.fromContext(context);
// Initialize with placeholder value. It is overridden later by TaskView
@@ -135,6 +145,8 @@ public class TaskThumbnailView extends View {
int color = task == null ? Color.BLACK : task.colorBackground | 0xFF000000;
mPaint.setColor(color);
mBackgroundPaint.setColor(color);
mSplashBackgroundPaint.setColor(color);
updateSplashView(mTask.icon);
}
/**
@@ -152,6 +164,9 @@ public class TaskThumbnailView extends View {
boolean thumbnailWasNull = mThumbnailData == null;
mThumbnailData =
(thumbnailData != null && thumbnailData.thumbnail != null) ? thumbnailData : null;
if (mTask != null) {
updateSplashView(mTask.icon);
}
if (refreshNow) {
refresh(thumbnailWasNull && mThumbnailData != null);
}
@@ -202,6 +217,18 @@ public class TaskThumbnailView extends View {
updateThumbnailPaintFilter();
}
/**
* Sets the alpha of the splash view.
*/
public void setSplashAlpha(float splashAlpha) {
mSplashAlpha = (int) (splashAlpha * 255);
if (mSplashViewDrawable != null) {
mSplashViewDrawable.setAlpha(mSplashAlpha);
}
mSplashBackgroundPaint.setAlpha(mSplashAlpha);
invalidate();
}
public TaskOverlay getTaskOverlay() {
if (mOverlay == null) {
mOverlay = getTaskView().getRecentsView().getTaskOverlayFactory().createOverlay(this);
@@ -259,6 +286,12 @@ public class TaskThumbnailView extends View {
return 0;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
updateSplashView(mSplashViewDrawable);
}
@Override
protected void onDraw(Canvas canvas) {
RectF currentDrawnInsets = mFullscreenParams.mCurrentDrawnInsets;
@@ -309,6 +342,17 @@ public class TaskThumbnailView extends View {
}
canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mPaint);
// Draw splash above thumbnail to hide inconsistencies in rotation and aspect ratios.
if (shouldShowSplashView()) {
if (mSplashView != null) {
canvas.drawRoundRect(x, y, width + 1, height + 1, cornerRadius,
cornerRadius, mSplashBackgroundPaint);
mSplashView.layout((int) x, (int) (y + 1), (int) width, (int) height - 1);
mSplashView.draw(canvas);
}
}
}
public TaskView getTaskView() {
@@ -323,6 +367,78 @@ public class TaskThumbnailView extends View {
}
}
/**
* Determine if the splash should be shown over top of the thumbnail.
*
* <p>We want to show the splash if the aspect ratio or rotation of the thumbnail would be
* different from the task.
*/
boolean shouldShowSplashView() {
return isThumbnailAspectRatioDifferentFromThumbnailData()
|| isThumbnailRotationDifferentFromTask();
}
private void updateSplashView(Drawable icon) {
if (icon == null || icon.getConstantState() == null) {
return;
}
mSplashViewDrawable = icon.getConstantState().newDrawable().mutate();
mSplashViewDrawable.setAlpha(mSplashAlpha);
ImageView imageView = mSplashView == null ? new ImageView(getContext()) : mSplashView;
imageView.setImageDrawable(mSplashViewDrawable);
imageView.setScaleType(ImageView.ScaleType.MATRIX);
Matrix matrix = new Matrix();
float drawableWidth = mSplashViewDrawable.getIntrinsicWidth();
float drawableHeight = mSplashViewDrawable.getIntrinsicHeight();
float viewWidth = getMeasuredWidth();
float viewCenterX = viewWidth / 2f;
float viewHeight = getMeasuredHeight();
float viewCenterY = viewHeight / 2f;
float centeredDrawableLeft = (viewWidth - drawableWidth) / 2f;
float centeredDrawableTop = (viewHeight - drawableHeight) / 2f;
float nonGridScale = getTaskView() == null ? 1 : 1 / getTaskView().getNonGridScale();
float recentsMaxScale = getTaskView() == null || getTaskView().getRecentsView() == null
? 1 : 1 / getTaskView().getRecentsView().getMaxScaleForFullScreen();
float scale = nonGridScale * recentsMaxScale;
// Center the image in the view.
matrix.setTranslate(centeredDrawableLeft, centeredDrawableTop);
// Apply scale transformation after translation, pivoting around center of view.
matrix.postScale(scale, scale, viewCenterX, viewCenterY);
imageView.setImageMatrix(matrix);
mSplashView = imageView;
}
private boolean isThumbnailAspectRatioDifferentFromThumbnailData() {
if (mThumbnailData == null || mThumbnailData.thumbnail == null) {
return false;
}
float thumbnailViewAspect = getWidth() / (float) getHeight();
float thumbnailDataAspect =
mThumbnailData.thumbnail.getWidth() / (float) mThumbnailData.thumbnail.getHeight();
return Utilities.isRelativePercentDifferenceGreaterThan(thumbnailViewAspect,
thumbnailDataAspect, MAX_PCT_BEFORE_ASPECT_RATIOS_CONSIDERED_DIFFERENT);
}
private boolean isThumbnailRotationDifferentFromTask() {
RecentsView recents = getTaskView().getRecentsView();
if (recents == null || mThumbnailData == null) {
return false;
}
if (recents.getPagedOrientationHandler() == PagedOrientationHandler.PORTRAIT) {
int currentRotation = recents.getPagedViewOrientedState().getRecentsActivityRotation();
return (currentRotation - mThumbnailData.rotation) % 2 != 0;
} else {
return recents.getPagedOrientationHandler().getRotation() != mThumbnailData.rotation;
}
}
/**
* Potentially re-init the task overlay. Be cautious when calling this as the overlay may
* do processing on initialization.
@@ -463,8 +579,9 @@ public class TaskThumbnailView extends View {
float availableAspect = isRotated
? availableHeight / availableWidth
: availableWidth / availableHeight;
boolean isAspectLargelyDifferent = Utilities.isRelativePercentDifferenceGreaterThan(
canvasAspect, availableAspect, 0.1f);
boolean isAspectLargelyDifferent =
Utilities.isRelativePercentDifferenceGreaterThan(canvasAspect,
availableAspect, MAX_PCT_BEFORE_ASPECT_RATIOS_CONSIDERED_DIFFERENT);
if (isRotated && isAspectLargelyDifferent) {
// Do not rotate thumbnail if it would not improve fit
isRotated = false;

View File

@@ -18,6 +18,7 @@ package com.android.quickstep.views;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.widget.Toast.LENGTH_SHORT;
import static android.window.SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR;
import static com.android.launcher3.Utilities.comp;
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
@@ -333,6 +334,7 @@ public class TaskView extends FrameLayout implements Reusable {
protected final DigitalWellBeingToast mDigitalWellBeingToast;
private float mFullscreenProgress;
private float mGridProgress;
protected float mOverviewProgress;
private float mNonGridScale = 1;
private float mDismissScale = 1;
protected final FullscreenDrawParams mCurrentFullscreenParams;
@@ -392,7 +394,6 @@ public class TaskView extends FrameLayout implements Reusable {
private boolean mIsClickableAsLiveTile = true;
public TaskView(Context context) {
this(context, null);
}
@@ -660,6 +661,9 @@ public class TaskView extends FrameLayout implements Reusable {
if (freezeTaskList) {
ActivityOptionsCompat.setFreezeRecentTasksList(opts);
}
// TODO(b/202826469): Replace setSplashScreenStyle with setDisableStartingWindow.
opts.setSplashScreenStyle(mSnapshotView.shouldShowSplashView()
? SPLASH_SCREEN_STYLE_SOLID_COLOR : opts.getSplashScreenStyle());
Task.TaskKey key = mTask.key;
UI_HELPER_EXECUTOR.execute(() -> {
if (!ActivityManagerWrapper.getInstance().startActivityFromRecents(key, opts)) {
@@ -1060,6 +1064,21 @@ public class TaskView extends FrameLayout implements Reusable {
return scale;
}
/**
* Updates progress of task view for entering/exiting overview on swipe up/down.
*
* <p>Updates the alpha of any splash screen over the thumbnail if it exists.
*/
public void setOverviewProgress(float overviewProgress) {
mOverviewProgress = overviewProgress;
applyThumbnailSplashAlpha();
}
protected void applyThumbnailSplashAlpha() {
mSnapshotView.setSplashAlpha(
Utilities.mapToRange(mOverviewProgress, 0f, 1f, 1f, 0f, LINEAR));
}
private void setSplitSelectTranslationX(float x) {
mSplitSelectTranslationX = x;
applyTranslationX();