Merge "Add local wallpaper color extraction to folder backgrounds." into sc-dev

This commit is contained in:
TreeHugger Robot
2021-05-09 04:02:12 +00:00
committed by Android (Google) Code Review
5 changed files with 145 additions and 23 deletions
@@ -39,6 +39,7 @@ import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
import com.android.launcher3.widget.LocalColorExtractor;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -108,12 +109,21 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
protected boolean mIsOpen;
// Index used to get background color when using local wallpaper color extraction.
protected int mColorExtractionIndex;
public AbstractFloatingView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public AbstractFloatingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
mColorExtractionIndex = LocalColorExtractor.getColorIndex(context);
}
/**
+101 -8
View File
@@ -31,6 +31,7 @@ import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.appwidget.AppWidgetHostView;
import android.content.Context;
@@ -38,6 +39,8 @@ import android.graphics.Canvas;
import android.graphics.Insets;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.GradientDrawable;
import android.os.Build;
import android.text.InputType;
import android.text.Selection;
@@ -45,6 +48,7 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Pair;
import android.util.SparseIntArray;
import android.util.TypedValue;
import android.view.FocusFinder;
import android.view.KeyEvent;
@@ -96,13 +100,16 @@ import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pageindicators.PageIndicatorDots;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
import com.android.launcher3.views.ClipPathView;
import com.android.launcher3.widget.LocalColorExtractor;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@@ -152,6 +159,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
private static final float ICON_OVERSCROLL_WIDTH_FACTOR = 0.45f;
private static final int FOLDER_NAME_ANIMATION_DURATION = 633;
private static final int FOLDER_COLOR_ANIMATION_DURATION = 150;
private static final int REORDER_DELAY = 250;
private static final int ON_EXIT_CLOSE_DELAY = 400;
@@ -224,6 +232,19 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
@Nullable private FolderWindowInsetsAnimationCallback mFolderWindowInsetsAnimationCallback;
// Wallpaper local color extraction
@Nullable private LocalColorExtractor mColorExtractor;
@Nullable private LocalColorExtractor.Listener mColorListener;
private final Rect mTempRect = new Rect();
private final RectF mTempRectF = new RectF();
// For simplicity, we start the color change only after the open animation has started.
private Runnable mColorChangeRunnable;
private Animator mColorChangeAnimator;
// The background color animator used in the folder open animation. We keep a reference to this,
// so that we can cancel it when starting mColorChangeAnimator.
private ObjectAnimator mOpenAnimationColorChangeAnimator;
/**
* Used to inflate the Workspace from XML.
*
@@ -241,7 +262,6 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
// name is complete, we have something to focus on, thus hiding the cursor and giving
// reliable behavior when clicking the text field (since it will always gain focus on click).
setFocusableInTouchMode(true);
}
@Override
@@ -276,6 +296,45 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
setWindowInsetsAnimationCallback(mFolderWindowInsetsAnimationCallback);
}
if (Utilities.ATLEAST_S) {
mColorExtractor = LocalColorExtractor.newInstance(mLauncher);
mColorListener = (RectF rect, SparseIntArray extractedColors) -> {
mColorChangeRunnable = () -> {
mColorChangeRunnable = null;
int duration = FOLDER_COLOR_ANIMATION_DURATION;
// Cancel the open animation color change animator.
ObjectAnimator existingAnim = mOpenAnimationColorChangeAnimator;
if (existingAnim != null && existingAnim.isRunning()) {
duration = (int) Math.max(FOLDER_COLOR_ANIMATION_DURATION,
existingAnim.getDuration() * (1f - existingAnim.getDuration()));
existingAnim.cancel();
mOpenAnimationColorChangeAnimator = null;
}
// Start a new animator to the extracted color.
int newColor = extractedColors.get(mColorExtractionIndex);
GradientDrawable bg = (GradientDrawable) getBackground();
mColorChangeAnimator = ObjectAnimator.ofArgb(bg, "color",
bg.getColor().getDefaultColor(), newColor).setDuration(duration);
mColorChangeAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mColorChangeAnimator = null;
}
});
mColorChangeAnimator.start();
};
// If the folder open animation has started, we can start the color change now.
// Otherwise we wait for it to start.
if (mOpenAnimationColorChangeAnimator != null
&& mOpenAnimationColorChangeAnimator.isStarted()) {
post(mColorChangeRunnable);
}
};
}
}
public boolean onLongClick(View v) {
@@ -652,15 +711,18 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
// dropping. One resulting issue is that replaceFolderWithFinalItem() can be called twice.
mDeleteFolderOnDropCompleted = false;
if (mCurrentAnimator != null && mCurrentAnimator.isRunning()) {
mCurrentAnimator.cancel();
}
AnimatorSet anim = new FolderAnimationManager(this, true /* isOpening */).getAnimator();
cancelRunningAnimations();
FolderAnimationManager fam = new FolderAnimationManager(this, true /* isOpening */);
AnimatorSet anim = fam.getAnimator();
mOpenAnimationColorChangeAnimator = fam.getBgColorAnimator();
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
mFolderIcon.setIconVisible(false);
mFolderIcon.drawLeaveBehindIfExists();
if (mColorChangeRunnable != null) {
mColorChangeRunnable.run();
}
}
@Override
public void onAnimationEnd(Animator animation) {
@@ -752,6 +814,15 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
}
private void cancelRunningAnimations() {
if (mCurrentAnimator != null && mCurrentAnimator.isRunning()) {
mCurrentAnimator.cancel();
}
if (mColorChangeAnimator != null && mColorChangeAnimator.isRunning()) {
mColorChangeAnimator.cancel();
}
}
private void animateClosed() {
if (mIsAnimatingClosed) {
return;
@@ -760,9 +831,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
mContent.completePendingPageChanges();
mContent.snapToPageImmediately(mContent.getDestinationPage());
if (mCurrentAnimator != null && mCurrentAnimator.isRunning()) {
mCurrentAnimator.cancel();
}
cancelRunningAnimations();
AnimatorSet a = new FolderAnimationManager(this, false /* isOpening */).getAnimator();
a.addListener(new AnimatorListenerAdapter() {
@Override
@@ -837,6 +906,19 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
clearDragInfo();
mState = STATE_SMALL;
mContent.setCurrentPage(0);
mOpenAnimationColorChangeAnimator = null;
mColorChangeRunnable = null;
if (mColorChangeAnimator != null) {
mColorChangeAnimator.cancel();
mColorChangeAnimator = null;
}
if (mColorExtractor != null) {
mColorExtractor.removeLocations();
mColorExtractor.setListener(null);
}
GradientDrawable bg = (GradientDrawable) getBackground();
bg.setColor(Themes.getAttrColor(getContext(), R.attr.folderFillColor));
}
@Override
@@ -1104,6 +1186,17 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
lp.height = height;
lp.x = left;
lp.y = top;
if (mColorExtractor != null) {
mColorExtractor.removeLocations();
mColorExtractor.setListener(mColorListener);
mTempRect.set(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
mColorExtractor.getExtractedRectForViewRect(mLauncher,
mLauncher.getWorkspace().getCurrentPage(), mTempRect, mTempRectF);
if (!mTempRectF.isEmpty()) {
mColorExtractor.addLocation(Arrays.asList(mTempRectF));
}
}
}
protected int getContentAreaHeight() {
@@ -35,8 +35,6 @@ import android.util.Property;
import android.view.View;
import android.view.animation.AnimationUtils;
import androidx.core.graphics.ColorUtils;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.R;
@@ -80,6 +78,8 @@ public class FolderAnimationManager {
private final PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
private final FolderGridOrganizer mPreviewVerifier;
private ObjectAnimator mBgColorAnimator;
public FolderAnimationManager(Folder folder, boolean isOpening) {
mFolder = folder;
mContent = folder.mContent;
@@ -105,6 +105,12 @@ public class FolderAnimationManager {
R.interpolator.large_folder_preview_item_close_interpolator);
}
/**
* Returns the animator that changes the background color.
*/
public ObjectAnimator getBgColorAnimator() {
return mBgColorAnimator;
}
/**
* Prepares the Folder for animating between open / closed states.
@@ -162,10 +168,15 @@ public class FolderAnimationManager {
final float yDistance = initialY - lp.y;
// Set up the Folder background.
final int finalColor = ColorUtils.setAlphaComponent(
Themes.getAttrColor(mContext, R.attr.folderFillColor), 255);
final int initialColor = setColorAlphaBound(
finalColor, mPreviewBackground.getBackgroundAlpha());
int previewBackgroundColor = Themes.getAttrColor(mContext, R.attr.folderFillColor);
final int finalColor;
if (mIsOpening) {
finalColor = Themes.getAttrColor(mContext, R.attr.popupColorPrimary);
} else {
finalColor = mFolderBackground.getColor().getDefaultColor();
}
final int initialColor = setColorAlphaBound(previewBackgroundColor,
mPreviewBackground.getBackgroundAlpha());
mFolderBackground.mutate();
mFolderBackground.setColor(mIsOpening ? initialColor : finalColor);
@@ -193,11 +204,12 @@ public class FolderAnimationManager {
play(a, anim);
}
mBgColorAnimator = getAnimator(mFolderBackground, "color", initialColor, finalColor);
play(a, mBgColorAnimator);
play(a, getAnimator(mFolder, View.TRANSLATION_X, xDistance, 0f));
play(a, getAnimator(mFolder, View.TRANSLATION_Y, yDistance, 0f));
play(a, getAnimator(mFolder.mContent, SCALE_PROPERTY, initialScale, finalScale));
play(a, getAnimator(mFolder.mFooter, SCALE_PROPERTY, initialScale, finalScale));
play(a, getAnimator(mFolderBackground, "color", initialColor, finalColor));
play(a, mFolderIcon.mFolderName.createTextAlphaAnimator(!mIsOpening));
play(a, getShape().createRevealAnimator(
mFolder, startRect, endRect, finalRadius, !mIsOpening));
@@ -409,7 +421,7 @@ public class FolderAnimationManager {
: ObjectAnimator.ofFloat(view, property, v2, v1);
}
private Animator getAnimator(GradientDrawable drawable, String property, int v1, int v2) {
private ObjectAnimator getAnimator(GradientDrawable drawable, String property, int v1, int v2) {
return mIsOpening
? ObjectAnimator.ofArgb(drawable, property, v1, v2)
: ObjectAnimator.ofArgb(drawable, property, v2, v1);
@@ -91,9 +91,6 @@ public abstract class ArrowPopup<T extends StatefulActivity<LauncherState>>
// +1 for system shortcut view
private static final int MAX_NUM_CHILDREN = MAX_SHORTCUTS + 1;
// Index used to get background color when using local wallpaper color extraction,
private static final int LIGHT_COLOR_EXTRACTION_INDEX = android.R.color.system_accent2_50;
private static final int DARK_COLOR_EXTRACTION_INDEX = android.R.color.system_accent2_800;
private final Rect mTempRect = new Rect();
@@ -129,7 +126,6 @@ public abstract class ArrowPopup<T extends StatefulActivity<LauncherState>>
private final int[] mColors;
private final HashMap<String, View> mViewForRect = new HashMap<>();
private final int mColorExtractionIndex;
@Nullable private LocalColorExtractor mColorExtractor;
public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) {
@@ -138,9 +134,6 @@ public abstract class ArrowPopup<T extends StatefulActivity<LauncherState>>
mOutlineRadius = Themes.getDialogCornerRadius(context);
mLauncher = BaseDraggingActivity.fromContext(context);
mIsRtl = Utilities.isRtl(getResources());
mColorExtractionIndex = Utilities.isDarkTheme(context)
? DARK_COLOR_EXTRACTION_INDEX
: LIGHT_COLOR_EXTRACTION_INDEX;
setClipToOutline(true);
setOutlineProvider(new ViewOutlineProvider() {
@Override
@@ -28,6 +28,7 @@ import androidx.annotation.Nullable;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.ResourceBasedOverride;
import java.util.List;
@@ -35,6 +36,10 @@ import java.util.List;
/** Extracts the colors we need from the wallpaper at given locations. */
public class LocalColorExtractor implements ResourceBasedOverride {
// Index used to get background color when using local wallpaper color extraction,
private static final int LIGHT_COLOR_EXTRACTION_INDEX = android.R.color.system_accent2_50;
private static final int DARK_COLOR_EXTRACTION_INDEX = android.R.color.system_accent2_800;
/** Listener for color changes on a screen location. */
public interface Listener {
/**
@@ -103,4 +108,13 @@ public class LocalColorExtractor implements ResourceBasedOverride {
RectF colorExtractionRectOut) {
// no-op
}
/**
* Returns an index used to query the color of interest from the list of extracted colors.
*/
public static int getColorIndex(Context context) {
return Utilities.isDarkTheme(context)
? DARK_COLOR_EXTRACTION_INDEX
: LIGHT_COLOR_EXTRACTION_INDEX;
}
}