diff options
Diffstat (limited to 'src/com/android/launcher3/views')
-rw-r--r-- | src/com/android/launcher3/views/AbstractSlideInView.java | 199 | ||||
-rw-r--r-- | src/com/android/launcher3/views/ActivityContext.java | 77 | ||||
-rw-r--r-- | src/com/android/launcher3/views/ArrowTipView.java | 161 | ||||
-rw-r--r-- | src/com/android/launcher3/views/ClipIconView.java | 2 | ||||
-rw-r--r-- | src/com/android/launcher3/views/FloatingIconView.java | 10 | ||||
-rw-r--r-- | src/com/android/launcher3/views/OptionsPopupView.java | 52 | ||||
-rw-r--r-- | src/com/android/launcher3/views/Snackbar.java | 6 | ||||
-rw-r--r-- | src/com/android/launcher3/views/WidgetsEduView.java | 10 |
8 files changed, 317 insertions, 200 deletions
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java index ec7ec0b6c0..30e09718c2 100644 --- a/src/com/android/launcher3/views/AbstractSlideInView.java +++ b/src/com/android/launcher3/views/AbstractSlideInView.java @@ -17,24 +17,22 @@ package com.android.launcher3.views; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static com.android.app.animation.Interpolators.LINEAR; +import static com.android.app.animation.Interpolators.scrollInterpolatorForVelocity; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS; import static com.android.launcher3.LauncherAnimUtils.TABLET_BOTTOM_SHEET_SUCCESS_TRANSITION_PROGRESS; import static com.android.launcher3.allapps.AllAppsTransitionController.REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS; -import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity; import static com.android.launcher3.util.ScrollableLayoutManager.PREDICTIVE_BACK_MIN_SCALE; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; -import android.animation.PropertyValuesHolder; +import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Outline; import android.graphics.drawable.Drawable; import android.os.Build; import android.util.AttributeSet; -import android.util.Property; +import android.util.FloatProperty; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; @@ -47,10 +45,13 @@ import androidx.annotation.Nullable; import androidx.annotation.Px; import androidx.annotation.RequiresApi; +import com.android.app.animation.Interpolators; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatedFloat; -import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.anim.AnimatorListeners; +import com.android.launcher3.anim.AnimatorPlaybackController; +import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.touch.BaseSwipeDetector; import com.android.launcher3.touch.SingleAxisSwipeDetector; @@ -66,8 +67,8 @@ import java.util.Optional; public abstract class AbstractSlideInView<T extends Context & ActivityContext> extends AbstractFloatingView implements SingleAxisSwipeDetector.Listener { - protected static final Property<AbstractSlideInView, Float> TRANSLATION_SHIFT = - new Property<AbstractSlideInView, Float>(Float.class, "translationShift") { + protected static final FloatProperty<AbstractSlideInView<?>> TRANSLATION_SHIFT = + new FloatProperty<>("translationShift") { @Override public Float get(AbstractSlideInView view) { @@ -75,25 +76,54 @@ public abstract class AbstractSlideInView<T extends Context & ActivityContext> } @Override - public void set(AbstractSlideInView view, Float value) { + public void setValue(AbstractSlideInView view, float value) { view.setTranslationShift(value); } }; protected static final float TRANSLATION_SHIFT_CLOSED = 1f; protected static final float TRANSLATION_SHIFT_OPENED = 0f; private static final float VIEW_NO_SCALE = 1f; + private static final int DEFAULT_DURATION = 300; protected final T mActivityContext; protected final SingleAxisSwipeDetector mSwipeDetector; - protected final ObjectAnimator mOpenCloseAnimator; + protected @NonNull AnimatorPlaybackController mOpenCloseAnimation; protected ViewGroup mContent; protected final View mColorScrim; - protected Interpolator mScrollInterpolator; + + /** + * Interpolator for {@link #mOpenCloseAnimation} when we are closing due to dragging downwards. + */ + private Interpolator mScrollInterpolator; + private long mScrollDuration; + /** + * End progress for {@link #mOpenCloseAnimation} when we are closing due to dragging downloads. + * <p> + * There are two cases that determine this value: + * <ol> + * <li> + * If the drag interrupts the opening transition (i.e. {@link #mToTranslationShift} + * is {@link #TRANSLATION_SHIFT_OPENED}), we need to animate back to {@code 0} to + * reverse the animation that was paused at {@link #onDragStart(boolean, float)}. + * </li> + * <li> + * If the drag started after the view is fully opened (i.e. + * {@link #mToTranslationShift} is {@link #TRANSLATION_SHIFT_CLOSED}), the animation + * that was set up at {@link #onDragStart(boolean, float)} for closing the view + * should go forward to {@code 1}. + * </li> + * </ol> + */ + private float mScrollEndProgress; // range [0, 1], 0=> completely open, 1=> completely closed protected float mTranslationShift = TRANSLATION_SHIFT_CLOSED; + protected float mFromTranslationShift; + protected float mToTranslationShift; + /** {@link #mOpenCloseAnimation} progress at {@link #onDragStart(boolean, float)}. */ + private float mDragStartProgress; protected boolean mNoIntercept; protected @Nullable OnCloseListener mOnCloseBeginListener; @@ -102,8 +132,8 @@ public abstract class AbstractSlideInView<T extends Context & ActivityContext> protected final AnimatedFloat mSlideInViewScale = new AnimatedFloat(this::onScaleProgressChanged, VIEW_NO_SCALE); protected boolean mIsBackProgressing; - @Nullable private Drawable mContentBackground; - @Nullable private View mContentBackgroundParentView; + private @Nullable Drawable mContentBackground; + private @Nullable View mContentBackgroundParentView; protected final ViewOutlineProvider mViewOutlineProvider = new ViewOutlineProvider() { @Override @@ -122,21 +152,78 @@ public abstract class AbstractSlideInView<T extends Context & ActivityContext> mActivityContext = ActivityContext.lookupContext(context); mScrollInterpolator = Interpolators.SCROLL_CUBIC; + mScrollDuration = DEFAULT_DURATION; mSwipeDetector = new SingleAxisSwipeDetector(context, this, SingleAxisSwipeDetector.VERTICAL); - mOpenCloseAnimator = ObjectAnimator.ofPropertyValuesHolder(this); - mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mSwipeDetector.finishedScrolling(); - announceAccessibilityChanges(); - } - }); + mOpenCloseAnimation = new PendingAnimation(0).createPlaybackController(); + int scrimColor = getScrimColor(context); mColorScrim = scrimColor != -1 ? createColorScrim(context, scrimColor) : null; } + /** + * Sets up a {@link #mOpenCloseAnimation} for opening with default parameters. + * + * @see #setUpOpenCloseAnimation(float, float, long) + */ + protected final AnimatorPlaybackController setUpDefaultOpenAnimation() { + AnimatorPlaybackController animation = setUpOpenCloseAnimation( + TRANSLATION_SHIFT_CLOSED, TRANSLATION_SHIFT_OPENED, DEFAULT_DURATION); + animation.getAnimationPlayer().setInterpolator(Interpolators.FAST_OUT_SLOW_IN); + return animation; + } + + /** + * Sets up a {@link #mOpenCloseAnimation} for opening with a given duration. + * + * @see #setUpOpenCloseAnimation(float, float, long) + */ + protected final AnimatorPlaybackController setUpOpenAnimation(long duration) { + return setUpOpenCloseAnimation( + TRANSLATION_SHIFT_CLOSED, TRANSLATION_SHIFT_OPENED, duration); + } + + private AnimatorPlaybackController setUpCloseAnimation(long duration) { + return setUpOpenCloseAnimation( + TRANSLATION_SHIFT_OPENED, TRANSLATION_SHIFT_CLOSED, duration); + } + + /** + * Initializes a new {@link #mOpenCloseAnimation}. + * + * @param fromTranslationShift translation shift to animate from. + * @param toTranslationShift translation shift to animate to. + * @param duration animation duration. + * @return {@link #mOpenCloseAnimation} + */ + private AnimatorPlaybackController setUpOpenCloseAnimation( + float fromTranslationShift, float toTranslationShift, long duration) { + mFromTranslationShift = fromTranslationShift; + mToTranslationShift = toTranslationShift; + + PendingAnimation animation = new PendingAnimation(duration); + animation.addEndListener(b -> { + mSwipeDetector.finishedScrolling(); + announceAccessibilityChanges(); + }); + + animation.addFloat( + this, TRANSLATION_SHIFT, fromTranslationShift, toTranslationShift, LINEAR); + onOpenCloseAnimationPending(animation); + + mOpenCloseAnimation = animation.createPlaybackController(); + return mOpenCloseAnimation; + } + + /** + * Invoked when a {@link #mOpenCloseAnimation} is being set up. + * <p> + * Subclasses can override this method to modify the animation before it's used to create a + * {@link AnimatorPlaybackController}. + */ + protected void onOpenCloseAnimationPending(PendingAnimation animation) {} + protected void attachToContainer() { if (mColorScrim != null) { getPopupContainer().addView(mColorScrim); @@ -279,19 +366,28 @@ public abstract class AbstractSlideInView<T extends Context & ActivityContext> } private boolean isOpeningAnimationRunning() { - return mIsOpen && mOpenCloseAnimator.isRunning(); + return mIsOpen && mOpenCloseAnimation.getAnimationPlayer().isRunning(); } /* SingleAxisSwipeDetector.Listener */ @Override - public void onDragStart(boolean start, float startDisplacement) { } + public void onDragStart(boolean start, float startDisplacement) { + if (mOpenCloseAnimation.getAnimationPlayer().isRunning()) { + mOpenCloseAnimation.pause(); + mDragStartProgress = mOpenCloseAnimation.getProgressFraction(); + } else { + setUpCloseAnimation(DEFAULT_DURATION); + mDragStartProgress = 0; + } + } @Override public boolean onDrag(float displacement) { - float range = getShiftRange(); - displacement = Utilities.boundToRange(displacement, 0, range); - setTranslationShift(displacement / range); + float progress = mDragStartProgress + + Math.signum(mToTranslationShift - mFromTranslationShift) + * (displacement / getShiftRange()); + mOpenCloseAnimation.setPlayFraction(Utilities.boundToRange(progress, 0, 1)); return true; } @@ -302,16 +398,18 @@ public abstract class AbstractSlideInView<T extends Context & ActivityContext> if ((mSwipeDetector.isFling(velocity) && velocity > 0) || mTranslationShift > successfulShiftThreshold) { mScrollInterpolator = scrollInterpolatorForVelocity(velocity); - mOpenCloseAnimator.setDuration(BaseSwipeDetector.calculateDuration( - velocity, TRANSLATION_SHIFT_CLOSED - mTranslationShift)); + mScrollDuration = BaseSwipeDetector.calculateDuration( + velocity, TRANSLATION_SHIFT_CLOSED - mTranslationShift); + mScrollEndProgress = mToTranslationShift == TRANSLATION_SHIFT_OPENED ? 0 : 1; close(true); } else { - mOpenCloseAnimator.setValues(PropertyValuesHolder.ofFloat( - TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED)); - mOpenCloseAnimator.setDuration( - BaseSwipeDetector.calculateDuration(velocity, mTranslationShift)) - .setInterpolator(Interpolators.DEACCEL); - mOpenCloseAnimator.start(); + ValueAnimator animator = mOpenCloseAnimation.getAnimationPlayer(); + animator.setInterpolator(Interpolators.DECELERATE); + animator.setFloatValues( + mOpenCloseAnimation.getProgressFraction(), + mToTranslationShift == TRANSLATION_SHIFT_OPENED ? 1 : 0); + animator.setDuration(BaseSwipeDetector.calculateDuration(velocity, mTranslationShift)) + .start(); } } @@ -332,32 +430,31 @@ public abstract class AbstractSlideInView<T extends Context & ActivityContext> Optional.ofNullable(mOnCloseBeginListener).ifPresent(OnCloseListener::onSlideInViewClosed); if (!animate) { - mOpenCloseAnimator.cancel(); + mOpenCloseAnimation.pause(); setTranslationShift(TRANSLATION_SHIFT_CLOSED); onCloseComplete(); return; } - mOpenCloseAnimator.setValues( - PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_CLOSED)); - mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mOpenCloseAnimator.removeListener(this); - onCloseComplete(); - } - }); + + final ValueAnimator animator; if (mSwipeDetector.isIdleState()) { - mOpenCloseAnimator - .setDuration(defaultDuration) - .setInterpolator(getIdleInterpolator()); + setUpCloseAnimation(defaultDuration); + animator = mOpenCloseAnimation.getAnimationPlayer(); + animator.setInterpolator(getIdleInterpolator()); } else { - mOpenCloseAnimator.setInterpolator(mScrollInterpolator); + animator = mOpenCloseAnimation.getAnimationPlayer(); + animator.setInterpolator(mScrollInterpolator); + animator.setDuration(mScrollDuration); + mOpenCloseAnimation.getAnimationPlayer().setFloatValues( + mOpenCloseAnimation.getProgressFraction(), mScrollEndProgress); } - mOpenCloseAnimator.start(); + + animator.addListener(AnimatorListeners.forEndCallback(this::onCloseComplete)); + animator.start(); } protected Interpolator getIdleInterpolator() { - return Interpolators.ACCEL; + return Interpolators.ACCELERATE; } protected void onCloseComplete() { diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java index 4b319e5b61..84ea87118c 100644 --- a/src/com/android/launcher3/views/ActivityContext.java +++ b/src/com/android/launcher3/views/ActivityContext.java @@ -18,6 +18,7 @@ package com.android.launcher3.views; import static android.window.SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR; import static com.android.launcher3.LauncherSettings.Animation.DEFAULT_NO_ICON; +import static com.android.launcher3.Utilities.allowBGLaunch; import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.HIDE; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_KEYBOARD_CLOSED; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_PENDING_INTENT; @@ -38,7 +39,6 @@ import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.IBinder; import android.os.Process; -import android.os.StrictMode; import android.os.UserHandle; import android.util.Log; import android.view.Display; @@ -239,6 +239,11 @@ public interface ActivityContext { }; } + /** Long-click callback used for All Apps items. */ + default View.OnLongClickListener getAllAppsItemLongClickListener() { + return v -> false; + } + @Nullable default PopupDataProvider getPopupDataProvider() { return null; @@ -338,6 +343,12 @@ public interface ActivityContext { return null; } + boolean isShortcut = (item instanceof WorkspaceItemInfo) + && item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT + && !((WorkspaceItemInfo) item).isPromise(); + if (isShortcut && GO_DISABLE_WIDGETS) { + return null; + } ActivityOptionsWrapper options = v != null ? getActivityLaunchOptions(v, item) : makeDefaultActivityOptions(item != null && item.animationType == DEFAULT_NO_ICON ? SPLASH_SCREEN_STYLE_SOLID_COLOR : -1 /* SPLASH_SCREEN_STYLE_UNDEFINED */); @@ -349,13 +360,11 @@ public interface ActivityContext { intent.setSourceBounds(Utilities.getViewBounds(v)); } try { - boolean isShortcut = (item instanceof WorkspaceItemInfo) - && (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT - || item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) - && !((WorkspaceItemInfo) item).isPromise(); if (isShortcut) { - // Shortcuts need some special checks due to legacy reasons. - startShortcutIntentSafely(intent, optsBundle, item); + String id = ((WorkspaceItemInfo) item).getDeepShortcutId(); + String packageName = intent.getPackage(); + ((Context) this).getSystemService(LauncherApps.class).startShortcut( + packageName, id, intent.getSourceBounds(), optsBundle, user); } else if (user == null || user.equals(Process.myUserHandle())) { // Could be launching some bookkeeping activity context.startActivity(intent, optsBundle); @@ -410,8 +419,7 @@ public interface ActivityContext { } } ActivityOptions options = - ActivityOptions.makeClipRevealAnimation(v, left, top, width, height); - + allowBGLaunch(ActivityOptions.makeClipRevealAnimation(v, left, top, width, height)); options.setLaunchDisplayId( (v != null && v.getDisplay() != null) ? v.getDisplay().getDisplayId() : Display.DEFAULT_DISPLAY); @@ -423,62 +431,13 @@ public interface ActivityContext { * Creates a default activity option and we do not want association with any launcher element. */ default ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) { - ActivityOptions options = ActivityOptions.makeBasic(); + ActivityOptions options = allowBGLaunch(ActivityOptions.makeBasic()); if (Utilities.ATLEAST_T) { options.setSplashScreenStyle(splashScreenStyle); } return new ActivityOptionsWrapper(options, new RunnableList()); } - /** - * Safely launches an intent for a shortcut. - * - * @param intent Intent to start. - * @param optsBundle Optional launch arguments. - * @param info Shortcut information. - */ - default void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info) { - try { - StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy(); - try { - // Temporarily disable deathPenalty on all default checks. For eg, shortcuts - // containing file Uri's would cause a crash as penaltyDeathOnFileUriExposure - // is enabled by default on NYC. - StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll() - .penaltyLog().build()); - - if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) { - String id = ((WorkspaceItemInfo) info).getDeepShortcutId(); - String packageName = intent.getPackage(); - startShortcut(packageName, id, intent.getSourceBounds(), optsBundle, info.user); - } else { - // Could be launching some bookkeeping activity - ((Context) this).startActivity(intent, optsBundle); - } - } finally { - StrictMode.setVmPolicy(oldPolicy); - } - } catch (SecurityException e) { - throw e; - } - } - - /** - * A wrapper around the platform method with Launcher specific checks. - */ - default void startShortcut(String packageName, String id, Rect sourceBounds, - Bundle startActivityOptions, UserHandle user) { - if (GO_DISABLE_WIDGETS) { - return; - } - try { - ((Context) this).getSystemService(LauncherApps.class).startShortcut(packageName, id, - sourceBounds, startActivityOptions, user); - } catch (SecurityException | IllegalStateException e) { - Log.e(TAG, "Failed to start shortcut", e); - } - } - default CellPosMapper getCellPosMapper() { return CellPosMapper.DEFAULT; } diff --git a/src/com/android/launcher3/views/ArrowTipView.java b/src/com/android/launcher3/views/ArrowTipView.java index 73c5ad457b..b44dbeb616 100644 --- a/src/com/android/launcher3/views/ArrowTipView.java +++ b/src/com/android/launcher3/views/ArrowTipView.java @@ -16,14 +16,21 @@ package com.android.launcher3.views; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.content.Context; import android.content.res.Configuration; +import android.content.res.TypedArray; import android.graphics.CornerPathEffect; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.ShapeDrawable; import android.os.Handler; +import android.util.IntProperty; import android.util.Log; +import android.view.ContextThemeWrapper; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; @@ -33,18 +40,17 @@ import android.widget.TextView; import androidx.annotation.Nullable; import androidx.annotation.Px; -import androidx.core.content.ContextCompat; +import com.android.app.animation.Interpolators; import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; -import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.graphics.TriangleShape; /** - * A base class for arrow tip view in launcher + * A base class for arrow tip view in launcher. */ public class ArrowTipView extends AbstractFloatingView { @@ -54,33 +60,66 @@ public class ArrowTipView extends AbstractFloatingView { private static final long SHOW_DURATION_MS = 300; private static final long HIDE_DURATION_MS = 100; - protected final BaseDraggingActivity mActivity; + public static final IntProperty<ArrowTipView> TEXT_ALPHA = + new IntProperty<>("textAlpha") { + @Override + public void setValue(ArrowTipView view, int v) { + view.setTextAlpha(v); + } + + @Override + public Integer get(ArrowTipView view) { + return view.getTextAlpha(); + } + }; + + private final ActivityContext mActivityContext; private final Handler mHandler = new Handler(); - private final int mArrowWidth; - private final int mArrowMinOffset; private boolean mIsPointingUp; private Runnable mOnClosed; private View mArrowView; + private final int mArrowWidth; + private final int mArrowMinOffset; + private final int mArrowViewPaintColor; + + private AnimatorSet mOpenAnimator = new AnimatorSet(); + private AnimatorSet mCloseAnimator = new AnimatorSet(); + + private int mTextAlpha; public ArrowTipView(Context context) { this(context, false); } public ArrowTipView(Context context, boolean isPointingUp) { + this(context, isPointingUp, R.layout.arrow_toast); + } + + public ArrowTipView(Context context, boolean isPointingUp, int layoutId) { super(context, null, 0); - mActivity = BaseDraggingActivity.fromContext(context); + mActivityContext = ActivityContext.lookupContext(context); mIsPointingUp = isPointingUp; - mArrowWidth = context.getResources().getDimensionPixelSize(R.dimen.arrow_toast_arrow_width); + mArrowWidth = context.getResources().getDimensionPixelSize( + R.dimen.arrow_toast_arrow_width); mArrowMinOffset = context.getResources().getDimensionPixelSize( R.dimen.dynamic_grid_cell_border_spacing); - init(context); + TypedArray ta = context.obtainStyledAttributes(R.styleable.ArrowTipView); + // Set style to default to avoid inflation issues with missing attributes. + if (!ta.hasValue(R.styleable.ArrowTipView_arrowTipBackground) + || !ta.hasValue(R.styleable.ArrowTipView_arrowTipTextColor)) { + context = new ContextThemeWrapper(context, R.style.ArrowTipStyle); + } + mArrowViewPaintColor = ta.getColor(R.styleable.ArrowTipView_arrowTipBackground, + context.getColor(R.color.arrow_tip_view_bg)); + ta.recycle(); + init(context, layoutId); } @Override public boolean onControllerInterceptTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { close(true); - if (mActivity.getDragLayer().isEventOverView(this, ev)) { + if (mActivityContext.getDragLayer().isEventOverView(this, ev)) { return true; } } @@ -89,18 +128,17 @@ public class ArrowTipView extends AbstractFloatingView { @Override protected void handleClose(boolean animate) { + if (mOpenAnimator.isStarted()) { + mOpenAnimator.cancel(); + } if (mIsOpen) { if (animate) { - animate().alpha(0f) - .withLayer() - .setStartDelay(0) - .setDuration(HIDE_DURATION_MS) - .setInterpolator(Interpolators.ACCEL) - .withEndAction(() -> mActivity.getDragLayer().removeView(this)) - .start(); + mCloseAnimator.addListener(AnimatorListeners.forSuccessCallback( + () -> mActivityContext.getDragLayer().removeView(this))); + mCloseAnimator.start(); } else { - animate().cancel(); - mActivity.getDragLayer().removeView(this); + mCloseAnimator.cancel(); + mActivityContext.getDragLayer().removeView(this); } if (mOnClosed != null) mOnClosed.run(); mIsOpen = false; @@ -112,12 +150,31 @@ public class ArrowTipView extends AbstractFloatingView { return (type & TYPE_ON_BOARD_POPUP) != 0; } - private void init(Context context) { - inflate(context, R.layout.arrow_toast, this); + private void init(Context context, int layoutId) { + inflate(context, layoutId, this); setOrientation(LinearLayout.VERTICAL); mArrowView = findViewById(R.id.arrow); updateArrowTipInView(); + setAlpha(0); + + // Create default open animator. + mOpenAnimator.play(ObjectAnimator.ofFloat(this, ALPHA, 1f)); + mOpenAnimator.setStartDelay(SHOW_DELAY_MS); + mOpenAnimator.setDuration(SHOW_DURATION_MS); + mOpenAnimator.setInterpolator(Interpolators.DECELERATE); + + // Create default close animator. + mCloseAnimator.play(ObjectAnimator.ofFloat(this, ALPHA, 0)); + mCloseAnimator.setStartDelay(0); + mCloseAnimator.setDuration(HIDE_DURATION_MS); + mCloseAnimator.setInterpolator(Interpolators.ACCELERATE); + mCloseAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mActivityContext.getDragLayer().removeView(ArrowTipView.this); + } + }); } /** @@ -153,10 +210,10 @@ public class ArrowTipView extends AbstractFloatingView { public ArrowTipView show( String text, int gravity, int arrowMarginStart, int top, boolean shouldAutoClose) { ((TextView) findViewById(R.id.text)).setText(text); - ViewGroup parent = mActivity.getDragLayer(); + ViewGroup parent = mActivityContext.getDragLayer(); parent.addView(this); - DeviceProfile grid = mActivity.getDeviceProfile(); + DeviceProfile grid = mActivityContext.getDeviceProfile(); DragLayer.LayoutParams params = (DragLayer.LayoutParams) getLayoutParams(); params.gravity = gravity; @@ -185,14 +242,8 @@ public class ArrowTipView extends AbstractFloatingView { if (shouldAutoClose) { mHandler.postDelayed(() -> handleClose(true), AUTO_CLOSE_TIMEOUT_MILLIS); } - setAlpha(0); - animate() - .alpha(1f) - .withLayer() - .setStartDelay(SHOW_DELAY_MS) - .setDuration(SHOW_DURATION_MS) - .setInterpolator(Interpolators.DEACCEL) - .start(); + + mOpenAnimator.start(); return this; } @@ -273,7 +324,7 @@ public class ArrowTipView extends AbstractFloatingView { */ @Nullable private ArrowTipView showAtLocation(String text, @Px int arrowXCoord, @Px int yCoordDownPointingTip, @Px int yCoordUpPointingTip, boolean shouldAutoClose) { - ViewGroup parent = mActivity.getDragLayer(); + ViewGroup parent = mActivityContext.getDragLayer(); @Px int parentViewWidth = parent.getWidth(); @Px int parentViewHeight = parent.getHeight(); @Px int maxTextViewWidth = getContext().getResources() @@ -288,8 +339,10 @@ public class ArrowTipView extends AbstractFloatingView { TextView textView = findViewById(R.id.text); textView.setText(text); textView.setMaxWidth(maxTextViewWidth); - parent.addView(this); - requestLayout(); + if (parent.indexOfChild(this) < 0) { + parent.addView(this); + requestLayout(); + } post(() -> { // Adjust the tooltip horizontally. @@ -333,14 +386,8 @@ public class ArrowTipView extends AbstractFloatingView { if (shouldAutoClose) { mHandler.postDelayed(() -> handleClose(true), AUTO_CLOSE_TIMEOUT_MILLIS); } - setAlpha(0); - animate() - .alpha(1f) - .withLayer() - .setStartDelay(SHOW_DELAY_MS) - .setDuration(SHOW_DURATION_MS) - .setInterpolator(Interpolators.DEACCEL) - .start(); + + mOpenAnimator.start(); return this; } @@ -351,7 +398,7 @@ public class ArrowTipView extends AbstractFloatingView { Paint arrowPaint = arrowDrawable.getPaint(); @Px int arrowTipRadius = getContext().getResources() .getDimensionPixelSize(R.dimen.arrow_toast_corner_radius); - arrowPaint.setColor(ContextCompat.getColor(getContext(), R.color.arrow_tip_view_bg)); + arrowPaint.setColor(mArrowViewPaintColor); arrowPaint.setPathEffect(new CornerPathEffect(arrowTipRadius)); mArrowView.setBackground(arrowDrawable); // Add negative margin so that the rounded corners on base of arrow are not visible. @@ -378,4 +425,30 @@ public class ArrowTipView extends AbstractFloatingView { super.onConfigurationChanged(newConfig); close(/* animate= */ false); } + + /** + * Sets a custom animation to run on open of the ArrowTipView. + */ + public void setCustomOpenAnimation(AnimatorSet animator) { + mOpenAnimator = animator; + } + + /** + * Sets a custom animation to run on close of the ArrowTipView. + */ + public void setCustomCloseAnimation(AnimatorSet animator) { + mCloseAnimator = animator; + } + + private void setTextAlpha(int textAlpha) { + if (mTextAlpha != textAlpha) { + mTextAlpha = textAlpha; + TextView textView = findViewById(R.id.text); + textView.setTextColor(textView.getTextColors().withAlpha(mTextAlpha)); + } + } + + private int getTextAlpha() { + return mTextAlpha; + } } diff --git a/src/com/android/launcher3/views/ClipIconView.java b/src/com/android/launcher3/views/ClipIconView.java index 694deadb63..87e496e4c2 100644 --- a/src/com/android/launcher3/views/ClipIconView.java +++ b/src/com/android/launcher3/views/ClipIconView.java @@ -15,9 +15,9 @@ */ package com.android.launcher3.views; +import static com.android.app.animation.Interpolators.LINEAR; import static com.android.launcher3.Utilities.boundToRange; import static com.android.launcher3.Utilities.mapToRange; -import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION; import static java.lang.Math.max; diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java index 6b5c8df954..41b98c74a6 100644 --- a/src/com/android/launcher3/views/FloatingIconView.java +++ b/src/com/android/launcher3/views/FloatingIconView.java @@ -17,10 +17,10 @@ package com.android.launcher3.views; import static android.view.Gravity.LEFT; +import static com.android.app.animation.Interpolators.LINEAR; import static com.android.launcher3.Utilities.getBadge; import static com.android.launcher3.Utilities.getFullDrawable; import static com.android.launcher3.Utilities.mapToRange; -import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import static com.android.launcher3.views.IconLabelDotView.setIconAndDotVisible; @@ -289,12 +289,14 @@ public class FloatingIconView extends FrameLayout implements int width = (int) pos.width(); int height = (int) pos.height(); Object[] tmpObjArray = new Object[1]; + boolean[] outIsIconThemed = new boolean[1]; if (supportsAdaptiveIcons) { boolean shouldThemeIcon = btvIcon instanceof FastBitmapDrawable && ((FastBitmapDrawable) btvIcon).isThemed(); - drawable = getFullDrawable(l, info, width, height, shouldThemeIcon, tmpObjArray); + drawable = getFullDrawable( + l, info, width, height, shouldThemeIcon, tmpObjArray, outIsIconThemed); if (drawable instanceof AdaptiveIconDrawable) { - badge = getBadge(l, info, tmpObjArray[0]); + badge = getBadge(l, info, tmpObjArray[0], outIsIconThemed[0]); } else { // The drawable we get back is not an adaptive icon, so we need to use the // BubbleTextView icon that is already legacy treated. @@ -306,7 +308,7 @@ public class FloatingIconView extends FrameLayout implements drawable = btvIcon; } else { drawable = getFullDrawable(l, info, width, height, true /* shouldThemeIcon */, - tmpObjArray); + tmpObjArray, outIsIconThemed); } } } diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java index 4641e31b08..b62f60dc12 100644 --- a/src/com/android/launcher3/views/OptionsPopupView.java +++ b/src/com/android/launcher3/views/OptionsPopupView.java @@ -55,7 +55,6 @@ import com.android.launcher3.popup.ArrowPopup; import com.android.launcher3.shortcuts.DeepShortcutView; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.shared.TestProtocol; -import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.widget.picker.WidgetsFullSheet; import java.util.ArrayList; @@ -63,8 +62,10 @@ import java.util.List; /** * Popup shown on long pressing an empty space in launcher + * + * @param <T> The context showing this popup. */ -public class OptionsPopupView extends ArrowPopup<Launcher> +public class OptionsPopupView<T extends Context & ActivityContext> extends ArrowPopup<T> implements OnClickListener, OnLongClickListener { // An intent extra to indicate the horizontal scroll of the wallpaper. @@ -156,21 +157,27 @@ public class OptionsPopupView extends ArrowPopup<Launcher> } } - public static OptionsPopupView show(ActivityContext launcher, RectF targetRect, - List<OptionItem> items, boolean shouldAddArrow) { - return show(launcher, targetRect, items, shouldAddArrow, 0 /* width */); + public static <T extends Context & ActivityContext> OptionsPopupView<T> show( + ActivityContext activityContext, + RectF targetRect, + List<OptionItem> items, + boolean shouldAddArrow) { + return show(activityContext, targetRect, items, shouldAddArrow, 0 /* width */); } - public static OptionsPopupView show(ActivityContext launcher, RectF targetRect, - List<OptionItem> items, boolean shouldAddArrow, int width) { - OptionsPopupView popup = (OptionsPopupView) launcher.getLayoutInflater() - .inflate(R.layout.longpress_options_menu, launcher.getDragLayer(), false); + public static <T extends Context & ActivityContext> OptionsPopupView<T> show( + ActivityContext activityContext, + RectF targetRect, + List<OptionItem> items, + boolean shouldAddArrow, + int width) { + OptionsPopupView<T> popup = (OptionsPopupView<T>) activityContext.getLayoutInflater() + .inflate(R.layout.longpress_options_menu, activityContext.getDragLayer(), false); popup.mTargetRect = targetRect; popup.setShouldAddArrow(shouldAddArrow); for (OptionItem item : items) { - DeepShortcutView view = - (DeepShortcutView) popup.inflateAndAdd(R.layout.system_shortcut, popup); + DeepShortcutView view = popup.inflateAndAdd(R.layout.system_shortcut, popup); if (width > 0) { view.getLayoutParams().width = width; } @@ -190,14 +197,9 @@ public class OptionsPopupView extends ArrowPopup<Launcher> */ public static ArrayList<OptionItem> getOptions(Launcher launcher) { ArrayList<OptionItem> options = new ArrayList<>(); - boolean styleWallpaperExists = styleWallpapersExists(launcher); - int resString = styleWallpaperExists - ? R.string.styles_wallpaper_button_text : R.string.wallpaper_button_text; - int resDrawable = styleWallpaperExists - ? R.drawable.ic_palette : R.drawable.ic_wallpaper; options.add(new OptionItem(launcher, - resString, - resDrawable, + R.string.styles_wallpaper_button_text, + R.drawable.ic_palette, IGNORE, OptionsPopupView::startWallpaperPicker)); if (!WidgetsModel.GO_DISABLE_WIDGETS) { @@ -274,12 +276,8 @@ public class OptionsPopupView extends ArrowPopup<Launcher> .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) .putExtra(EXTRA_WALLPAPER_OFFSET, launcher.getWorkspace().getWallpaperOffsetForCenterPage()) - .putExtra(EXTRA_WALLPAPER_LAUNCH_SOURCE, "app_launched_launcher"); - if (!styleWallpapersExists(launcher)) { - intent.putExtra(EXTRA_WALLPAPER_FLAVOR, "wallpaper_only"); - } else { - intent.putExtra(EXTRA_WALLPAPER_FLAVOR, "focus_wallpaper"); - } + .putExtra(EXTRA_WALLPAPER_LAUNCH_SOURCE, "app_launched_launcher") + .putExtra(EXTRA_WALLPAPER_FLAVOR, "focus_wallpaper"); String pickerPackage = launcher.getString(R.string.wallpaper_picker_package); if (!TextUtils.isEmpty(pickerPackage)) { intent.setPackage(pickerPackage); @@ -290,7 +288,6 @@ public class OptionsPopupView extends ArrowPopup<Launcher> static WorkspaceItemInfo placeholderInfo(Intent intent) { WorkspaceItemInfo placeholderInfo = new WorkspaceItemInfo(); placeholderInfo.intent = intent; - placeholderInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; placeholderInfo.container = LauncherSettings.Favorites.CONTAINER_SETTINGS; return placeholderInfo; } @@ -323,9 +320,4 @@ public class OptionsPopupView extends ArrowPopup<Launcher> this.clickListener = clickListener; } } - - private static boolean styleWallpapersExists(Context context) { - return context.getPackageManager().resolveActivity( - PackageManagerHelper.getStyleWallpapersIntent(context), 0) != null; - } } diff --git a/src/com/android/launcher3/views/Snackbar.java b/src/com/android/launcher3/views/Snackbar.java index 2460be17c5..99040ff845 100644 --- a/src/com/android/launcher3/views/Snackbar.java +++ b/src/com/android/launcher3/views/Snackbar.java @@ -30,10 +30,10 @@ import android.widget.TextView; import androidx.annotation.Nullable; +import com.android.app.animation.Interpolators; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; -import com.android.launcher3.anim.Interpolators; import com.android.launcher3.compat.AccessibilityManagerCompat; import com.android.launcher3.dragndrop.DragLayer; @@ -175,7 +175,7 @@ public class Snackbar extends AbstractFloatingView { .scaleX(1) .scaleY(1) .setDuration(SHOW_DURATION_MS) - .setInterpolator(Interpolators.ACCEL_DEACCEL) + .setInterpolator(Interpolators.ACCELERATE_DECELERATE) .start(); int timeout = AccessibilityManagerCompat.getRecommendedTimeoutMillis(activity, TIMEOUT_DURATION_MS, FLAG_CONTENT_TEXT | FLAG_CONTENT_CONTROLS); @@ -190,7 +190,7 @@ public class Snackbar extends AbstractFloatingView { .withLayer() .setStartDelay(0) .setDuration(HIDE_DURATION_MS) - .setInterpolator(Interpolators.ACCEL) + .setInterpolator(Interpolators.ACCELERATE) .withEndAction(this::onClosed) .start(); } else { diff --git a/src/com/android/launcher3/views/WidgetsEduView.java b/src/com/android/launcher3/views/WidgetsEduView.java index c2947c7310..e70b1cbd16 100644 --- a/src/com/android/launcher3/views/WidgetsEduView.java +++ b/src/com/android/launcher3/views/WidgetsEduView.java @@ -15,9 +15,6 @@ */ package com.android.launcher3.views; -import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; - -import android.animation.PropertyValuesHolder; import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; @@ -119,14 +116,11 @@ public class WidgetsEduView extends AbstractSlideInView<Launcher> implements Ins } private void animateOpen() { - if (mIsOpen || mOpenCloseAnimator.isRunning()) { + if (mIsOpen || mOpenCloseAnimation.getAnimationPlayer().isRunning()) { return; } mIsOpen = true; - mOpenCloseAnimator.setValues( - PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED)); - mOpenCloseAnimator.setInterpolator(FAST_OUT_SLOW_IN); - mOpenCloseAnimator.start(); + setUpDefaultOpenAnimation().start(); } /** Shows widget education dialog. */ |