For the widget transition animation fallback background color, use either the splash screen background color if a task is starting or the task description-attached background color. With a background in place, allow the window to fully fade out before fading in the widget, by moving the window alpha math into an animation factory-specific implementation. Bug: 187706750 Test: Manual Change-Id: I2b5a7783b0585d447ad60534bc48d2e2176877ed
192 lines
8.0 KiB
Java
192 lines
8.0 KiB
Java
/*
|
|
* Copyright (C) 2021 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.views;
|
|
|
|
import android.annotation.TargetApi;
|
|
import android.content.Context;
|
|
import android.graphics.Outline;
|
|
import android.graphics.drawable.ColorDrawable;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.graphics.drawable.GradientDrawable;
|
|
import android.os.Build;
|
|
import android.util.AttributeSet;
|
|
import android.view.View;
|
|
import android.view.ViewOutlineProvider;
|
|
import android.widget.RemoteViews.RemoteViewOutlineProvider;
|
|
|
|
import com.android.launcher3.widget.LauncherAppWidgetHostView;
|
|
import com.android.launcher3.widget.RoundedCornerEnforcement;
|
|
|
|
import java.util.stream.IntStream;
|
|
|
|
/**
|
|
* Mimics the appearance of the background view of a {@link LauncherAppWidgetHostView} through a
|
|
* an App Widget activity launch animation.
|
|
*/
|
|
@TargetApi(Build.VERSION_CODES.S)
|
|
final class FloatingWidgetBackgroundView extends View {
|
|
private final ColorDrawable mFallbackDrawable = new ColorDrawable();
|
|
private final DrawableProperties mForegroundProperties = new DrawableProperties();
|
|
private final DrawableProperties mBackgroundProperties = new DrawableProperties();
|
|
|
|
private Drawable mOriginalForeground;
|
|
private Drawable mOriginalBackground;
|
|
private float mFinalRadius;
|
|
private float mInitialOutlineRadius;
|
|
private float mOutlineRadius;
|
|
private boolean mIsUsingFallback;
|
|
private View mSourceView;
|
|
|
|
FloatingWidgetBackgroundView(Context context, AttributeSet attrs, int defStyleAttr) {
|
|
super(context, attrs, defStyleAttr);
|
|
setOutlineProvider(new ViewOutlineProvider() {
|
|
@Override
|
|
public void getOutline(View view, Outline outline) {
|
|
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mOutlineRadius);
|
|
}
|
|
});
|
|
setClipToOutline(true);
|
|
}
|
|
|
|
void init(LauncherAppWidgetHostView hostView, View backgroundView, float finalRadius,
|
|
int fallbackBackgroundColor) {
|
|
mFinalRadius = finalRadius;
|
|
mSourceView = backgroundView;
|
|
mInitialOutlineRadius = getOutlineRadius(hostView, backgroundView);
|
|
mIsUsingFallback = false;
|
|
if (isSupportedDrawable(backgroundView.getForeground())) {
|
|
mOriginalForeground = backgroundView.getForeground();
|
|
mForegroundProperties.init(
|
|
mOriginalForeground.getConstantState().newDrawable().mutate());
|
|
setForeground(mForegroundProperties.mDrawable);
|
|
mSourceView.setForeground(null);
|
|
}
|
|
if (isSupportedDrawable(backgroundView.getBackground())) {
|
|
mOriginalBackground = backgroundView.getBackground();
|
|
mBackgroundProperties.init(
|
|
mOriginalBackground.getConstantState().newDrawable().mutate());
|
|
setBackground(mBackgroundProperties.mDrawable);
|
|
mSourceView.setBackground(null);
|
|
} else if (mOriginalForeground == null) {
|
|
mFallbackDrawable.setColor(fallbackBackgroundColor);
|
|
setBackground(mFallbackDrawable);
|
|
mIsUsingFallback = true;
|
|
}
|
|
}
|
|
|
|
/** Update the animated properties of the drawables. */
|
|
void update(float cornerRadiusProgress, float fallbackAlpha) {
|
|
if (isUninitialized()) return;
|
|
mOutlineRadius = mInitialOutlineRadius + (mFinalRadius - mInitialOutlineRadius)
|
|
* cornerRadiusProgress;
|
|
mForegroundProperties.updateDrawable(mFinalRadius, cornerRadiusProgress);
|
|
mBackgroundProperties.updateDrawable(mFinalRadius, cornerRadiusProgress);
|
|
setAlpha(mIsUsingFallback ? fallbackAlpha : 1f);
|
|
}
|
|
|
|
/** Restores the drawables to the source view. */
|
|
void finish() {
|
|
if (isUninitialized()) return;
|
|
if (mOriginalForeground != null) mSourceView.setForeground(mOriginalForeground);
|
|
if (mOriginalBackground != null) mSourceView.setBackground(mOriginalBackground);
|
|
}
|
|
|
|
void recycle() {
|
|
mSourceView = null;
|
|
mOriginalForeground = null;
|
|
mOriginalBackground = null;
|
|
mOutlineRadius = 0;
|
|
mFinalRadius = 0;
|
|
setForeground(null);
|
|
setBackground(null);
|
|
}
|
|
|
|
/** Get the largest of drawable corner radii or background view outline radius. */
|
|
float getMaximumRadius() {
|
|
if (isUninitialized()) return 0;
|
|
return Math.max(mInitialOutlineRadius, Math.max(getMaxRadius(mOriginalForeground),
|
|
getMaxRadius(mOriginalBackground)));
|
|
}
|
|
|
|
private boolean isUninitialized() {
|
|
return mSourceView == null;
|
|
}
|
|
|
|
/** Returns the maximum corner radius of {@param drawable}. */
|
|
private static float getMaxRadius(Drawable drawable) {
|
|
if (!(drawable instanceof GradientDrawable)) return 0;
|
|
float[] cornerRadii = ((GradientDrawable) drawable).getCornerRadii();
|
|
float cornerRadius = ((GradientDrawable) drawable).getCornerRadius();
|
|
double radiiMax = cornerRadii == null ? 0 : IntStream.range(0, cornerRadii.length)
|
|
.mapToDouble(i -> cornerRadii[i]).max().orElse(0);
|
|
return Math.max(cornerRadius, (float) radiiMax);
|
|
}
|
|
|
|
/** Returns whether the given drawable type is supported. */
|
|
private static boolean isSupportedDrawable(Drawable drawable) {
|
|
return drawable instanceof ColorDrawable || (drawable instanceof GradientDrawable
|
|
&& ((GradientDrawable) drawable).getShape() == GradientDrawable.RECTANGLE);
|
|
}
|
|
|
|
/** Corner radius from source view's outline, or enforced view. */
|
|
private static float getOutlineRadius(LauncherAppWidgetHostView hostView, View v) {
|
|
if (RoundedCornerEnforcement.isRoundedCornerEnabled()
|
|
&& hostView.hasEnforcedCornerRadius()) {
|
|
return hostView.getEnforcedCornerRadius();
|
|
} else if (v.getOutlineProvider() instanceof RemoteViewOutlineProvider
|
|
&& v.getClipToOutline()) {
|
|
return ((RemoteViewOutlineProvider) v.getOutlineProvider()).getRadius();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/** Stores and modifies a drawable's properties through an animation. */
|
|
private static class DrawableProperties {
|
|
private Drawable mDrawable;
|
|
private float mOriginalRadius;
|
|
private float[] mOriginalRadii;
|
|
private final float[] mTmpRadii = new float[8];
|
|
|
|
/** Store a drawable's animated properties. */
|
|
void init(Drawable drawable) {
|
|
mDrawable = drawable;
|
|
if (!(drawable instanceof GradientDrawable)) return;
|
|
mOriginalRadius = ((GradientDrawable) drawable).getCornerRadius();
|
|
mOriginalRadii = ((GradientDrawable) drawable).getCornerRadii();
|
|
}
|
|
|
|
/**
|
|
* Update the drawable for the given animation state.
|
|
*
|
|
* @param finalRadius the radius of each corner when {@param progress} is 1
|
|
* @param progress the linear progress of the corner radius from its original value to
|
|
* {@param finalRadius}
|
|
*/
|
|
void updateDrawable(float finalRadius, float progress) {
|
|
if (!(mDrawable instanceof GradientDrawable)) return;
|
|
GradientDrawable d = (GradientDrawable) mDrawable;
|
|
if (mOriginalRadii != null) {
|
|
for (int i = 0; i < mOriginalRadii.length; i++) {
|
|
mTmpRadii[i] = mOriginalRadii[i] + (finalRadius - mOriginalRadii[i]) * progress;
|
|
}
|
|
d.setCornerRadii(mTmpRadii);
|
|
} else {
|
|
d.setCornerRadius(mOriginalRadius + (finalRadius - mOriginalRadius) * progress);
|
|
}
|
|
}
|
|
}
|
|
}
|