Merge "Overview - add the ability to color scrim task views." into sc-dev

This commit is contained in:
Zak Cohen
2021-04-05 21:05:25 +00:00
committed by Android (Google) Code Review
7 changed files with 123 additions and 61 deletions
@@ -30,6 +30,7 @@ import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.AppUsageLimit;
import android.graphics.Outline;
import android.graphics.Paint;
import android.icu.text.MeasureFormat;
import android.icu.text.MeasureFormat.FormatWidth;
import android.icu.util.Measure;
@@ -48,6 +49,7 @@ import androidx.annotation.StringRes;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.systemui.shared.recents.model.Task;
import java.time.Duration;
@@ -297,4 +299,17 @@ public final class DigitalWellBeingToast {
mBanner.setAlpha(alpha);
}
}
void setBannerColorTint(int color, float amount) {
if (mBanner == null) {
return;
}
if (mBannerAlpha == 0 || amount == 0) {
mBanner.setLayerType(View.LAYER_TYPE_NONE, null);
}
Paint layerPaint = new Paint();
layerPaint.setColorFilter(Utilities.makeColorTintingColorFilter(color, amount));
mBanner.setLayerType(View.LAYER_TYPE_HARDWARE, layerPaint);
mBanner.setLayerPaint(layerPaint);
}
}
@@ -21,6 +21,8 @@ import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import com.android.launcher3.Utilities;
/**
* A view which draws a drawable stretched to fit its size. Unlike ImageView, it avoids relayout
* when the drawable changes.
@@ -102,4 +104,16 @@ public class IconView extends View {
setVisibility(INVISIBLE);
}
}
/**
* Set the tint color of the icon, useful for scrimming or dimming.
*
* @param color to blend in.
* @param amount [0,1] 0 no tint, 1 full tint
*/
public void setIconColorTint(int color, float amount) {
if (mDrawable != null) {
mDrawable.setColorFilter(Utilities.makeColorTintingColorFilter(color, amount));
}
}
}
@@ -3309,6 +3309,16 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
return mSizeStrategy;
}
/**
* Set all the task views to color tint scrim mode, dimming or tinting them all. Allows the
* tasks to be dimmed while other elements in the recents view are left alone.
*/
public void showForegroundScrim(boolean show) {
for (int i = 0; i < getTaskViewCount(); i++) {
getTaskViewAt(i).showColorTint(show);
}
}
private boolean showAsGrid() {
return mOverviewGridEnabled || (mCurrentGestureEndTarget != null
&& mSizeStrategy.stateFromGestureEndTarget(
@@ -249,9 +249,11 @@ public class TaskMenuView extends AbstractFloatingView {
final Animator revealAnimator = createOpenCloseOutlineProvider()
.createRevealAnimator(this, closing);
revealAnimator.setInterpolator(Interpolators.DEACCEL);
mOpenCloseAnimator.play(revealAnimator);
mOpenCloseAnimator.play(ObjectAnimator.ofFloat(mTaskView.getThumbnail(), DIM_ALPHA,
closing ? 0 : TaskView.MAX_PAGE_SCRIM_ALPHA));
mOpenCloseAnimator.playTogether(revealAnimator,
ObjectAnimator.ofFloat(
mTaskView.getThumbnail(), DIM_ALPHA,
closing ? 0 : TaskView.MAX_PAGE_SCRIM_ALPHA),
ObjectAnimator.ofFloat(this, ALPHA, closing ? 0 : 1));
mOpenCloseAnimator.addListener(new AnimationSuccessListener() {
@Override
public void onAnimationStart(Animator animation) {
@@ -265,7 +267,6 @@ public class TaskMenuView extends AbstractFloatingView {
}
}
});
mOpenCloseAnimator.play(ObjectAnimator.ofFloat(this, ALPHA, closing ? 0 : 1));
mOpenCloseAnimator.setDuration(closing ? REVEAL_CLOSE_DURATION: REVEAL_OPEN_DURATION);
mOpenCloseAnimator.start();
}
@@ -28,8 +28,6 @@ import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Paint;
@@ -46,10 +44,10 @@ import android.view.Surface;
import android.view.View;
import androidx.annotation.RequiresApi;
import androidx.core.graphics.ColorUtils;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
@@ -67,10 +65,6 @@ import com.android.systemui.shared.recents.model.ThumbnailData;
* A task in the Recents view.
*/
public class TaskThumbnailView extends View implements PluginListener<OverviewScreenshotActions> {
private static final ColorMatrix COLOR_MATRIX = new ColorMatrix();
private static final ColorMatrix SATURATION_COLOR_MATRIX = new ColorMatrix();
private static final MainThreadInitializedObject<FullscreenDrawParams> TEMP_PARAMS =
new MainThreadInitializedObject<>(FullscreenDrawParams::new);
@@ -89,11 +83,11 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
private final BaseActivity mActivity;
private TaskOverlay mOverlay;
private final boolean mIsDarkTextTheme;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint mClearPaint = new Paint();
private final Paint mDimmingPaintAfterClearing = new Paint();
private final int mDimColor;
// Contains the portion of the thumbnail that is clipped when fullscreen progress = 0.
private final Rect mPreviewRect = new Rect();
@@ -104,9 +98,8 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
private ThumbnailData mThumbnailData;
protected BitmapShader mBitmapShader;
private float mDimAlpha = 1f;
private float mDimAlphaMultiplier = 1f;
private float mSaturation = 1f;
/** How much this thumbnail is dimmed, 0 not dimmed at all, 1 totally dimmed. */
private float mDimAlpha = 0f;
private boolean mOverlayEnabled;
private OverviewScreenshotActions mOverviewScreenshotActionsPlugin;
@@ -124,11 +117,12 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
mPaint.setFilterBitmap(true);
mBackgroundPaint.setColor(Color.WHITE);
mClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
mDimmingPaintAfterClearing.setColor(Color.BLACK);
mActivity = BaseActivity.fromContext(context);
mIsDarkTextTheme = Themes.getAttrBoolean(mActivity, R.attr.isWorkspaceDarkText);
// Initialize with placeholder value. It is overridden later by TaskView
mFullscreenParams = TEMP_PARAMS.get(context);
mDimColor = Themes.getColorBackgroundFloating(context);
mDimmingPaintAfterClearing.setColor(mDimColor);
}
/**
@@ -186,15 +180,12 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
updateThumbnailPaintFilter();
}
public void setDimAlphaMultipler(float dimAlphaMultipler) {
mDimAlphaMultiplier = dimAlphaMultipler;
setDimAlpha(mDimAlpha);
}
/**
* Sets the alpha of the dim layer on top of this view.
* <p>
* If dimAlpha is 0, no dimming is applied; if dimAlpha is 1, the thumbnail will be black.
* If dimAlpha is 0, no dimming is applied; if dimAlpha is 1, the thumbnail will be the
* extracted background color.
*
*/
public void setDimAlpha(float dimAlpha) {
mDimAlpha = dimAlpha;
@@ -359,15 +350,15 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
}
private void updateThumbnailPaintFilter() {
int mul = (int) ((1 - mDimAlpha * mDimAlphaMultiplier) * 255);
ColorFilter filter = getColorFilter(mul, mIsDarkTextTheme, mSaturation);
ColorFilter filter = getColorFilter(mDimAlpha);
mBackgroundPaint.setColorFilter(filter);
mDimmingPaintAfterClearing.setAlpha(255 - mul);
int alpha = (int) (mDimAlpha * 255);
mDimmingPaintAfterClearing.setAlpha(alpha);
if (mBitmapShader != null) {
mPaint.setColorFilter(filter);
} else {
mPaint.setColorFilter(null);
mPaint.setColor(Color.argb(255, mul, mul, mul));
mPaint.setColor(ColorUtils.blendARGB(Color.BLACK, mDimColor, alpha));
}
invalidate();
}
@@ -401,35 +392,8 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
updateThumbnailMatrix();
}
/**
* @param intensity multiplier for color values. 0 - make black (white if shouldLighten), 255 -
* leave unchanged.
*/
private static ColorFilter getColorFilter(int intensity, boolean shouldLighten,
float saturation) {
intensity = Utilities.boundToRange(intensity, 0, 255);
if (intensity == 255 && saturation == 1) {
return null;
}
final float intensityScale = intensity / 255f;
COLOR_MATRIX.setScale(intensityScale, intensityScale, intensityScale, 1);
if (saturation != 1) {
SATURATION_COLOR_MATRIX.setSaturation(saturation);
COLOR_MATRIX.postConcat(SATURATION_COLOR_MATRIX);
}
if (shouldLighten) {
final float[] colorArray = COLOR_MATRIX.getArray();
final int colorAdd = 255 - intensity;
colorArray[4] = colorAdd;
colorArray[9] = colorAdd;
colorArray[14] = colorAdd;
}
return new ColorMatrixColorFilter(COLOR_MATRIX);
private ColorFilter getColorFilter(float dimAmount) {
return Utilities.makeColorTintingColorFilter(mDimColor, dimAmount);
}
public Bitmap getThumbnail() {
@@ -89,6 +89,7 @@ import com.android.launcher3.util.ActivityOptionsWrapper;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.TransformingTouchDelegate;
import com.android.launcher3.util.ViewPool.Reusable;
import com.android.quickstep.RecentsModel;
@@ -134,10 +135,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
@IntDef({FLAG_UPDATE_ALL, FLAG_UPDATE_ICON, FLAG_UPDATE_THUMBNAIL})
public @interface TaskDataChanges {}
/**
* The alpha of a black scrim on a page in the carousel as it leaves the screen.
* In the resting position of the carousel, the adjacent pages have about half this scrim.
*/
/** The maximum amount that a task view can be scrimmed, dimmed or tinted. */
public static final float MAX_PAGE_SCRIM_ALPHA = 0.4f;
/**
@@ -254,6 +252,19 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
}
};
private static final FloatProperty<TaskView> COLOR_TINT =
new FloatProperty<TaskView>("colorTint") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setColorTint(v);
}
@Override
public Float get(TaskView taskView) {
return taskView.getColorTint();
}
};
private final OnAttachStateChangeListener mTaskMenuStateListener =
new OnAttachStateChangeListener() {
@Override
@@ -314,6 +325,11 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
private final float[] mIconCenterCoords = new float[2];
private final float[] mChipCenterCoords = new float[2];
// Colored tint for the task view and all its supplementary views (like the task icon and well
// being banner.
private final int mTintingColor;
private float mTintAmount;
private boolean mIsClickableAsLiveTile = true;
public TaskView(Context context) {
@@ -375,6 +391,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
mOutlineProvider = new TaskOutlineProvider(getContext(), mCurrentFullscreenParams,
mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx);
setOutlineProvider(mOutlineProvider);
mTintingColor = Themes.getColorBackgroundFloating(context);
}
/**
@@ -722,7 +740,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
progress = 1 - progress;
}
mFocusTransitionProgress = progress;
mSnapshotView.setDimAlphaMultipler(0);
float iconScalePercentage = (float) SCALE_ICON_DURATION / DIM_ANIM_DURATION;
float lowerClamp = invert ? 1f - iconScalePercentage : 0;
float upperClamp = invert ? 1 : iconScalePercentage;
@@ -781,6 +798,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
setTranslationZ(0);
setAlpha(mStableAlpha);
setIconScaleAndDim(1);
setColorTint(0);
}
public void setStableAlpha(float parentAlpha) {
@@ -1324,6 +1342,26 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
rv.initiateSplitSelect(this, splitPositionOption);
}
private void setColorTint(float amount) {
mSnapshotView.setDimAlpha(amount);
mIconView.setIconColorTint(mTintingColor, amount);
mDigitalWellBeingToast.setBannerColorTint(mTintingColor, amount);
}
private float getColorTint() {
return mTintAmount;
}
/**
* Show the task view with a color tint (animates value).
*/
public void showColorTint(boolean enable) {
ObjectAnimator tintAnimator = ObjectAnimator.ofFloat(
this, COLOR_TINT, enable ? MAX_PAGE_SCRIM_ALPHA : 0);
tintAnimator.setAutoCancel(true);
tintAnimator.start();
}
/**
* We update and subsequently draw these in {@link #setFullscreenProgress(float)}.
*/
+20
View File
@@ -37,6 +37,8 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.LightingColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
@@ -64,6 +66,7 @@ import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.Interpolator;
import androidx.core.graphics.ColorUtils;
import androidx.core.os.BuildCompat;
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
@@ -732,6 +735,23 @@ public final class Utilities {
}
}
/**
* Make a color filter that blends a color into the destination based on a scalable amout.
*
* @param color to blend in.
* @param tintAmount [0-1] 0 no tinting, 1 full color.
* @return ColorFilter for tinting, or {@code null} if no filter is needed.
*/
public static ColorFilter makeColorTintingColorFilter(int color, float tintAmount) {
if (tintAmount == 0f) {
return null;
}
return new LightingColorFilter(
// This isn't blending in white, its making a multiplication mask for the base color
ColorUtils.blendARGB(Color.WHITE, 0, tintAmount),
ColorUtils.blendARGB(0, color, tintAmount));
}
private static class FixedSizeEmptyDrawable extends ColorDrawable {
private final int mSize;