summaryrefslogtreecommitdiff
path: root/src/com/android/launcher3/views
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/launcher3/views')
-rw-r--r--src/com/android/launcher3/views/AbstractSlideInView.java199
-rw-r--r--src/com/android/launcher3/views/ActivityContext.java77
-rw-r--r--src/com/android/launcher3/views/ArrowTipView.java161
-rw-r--r--src/com/android/launcher3/views/ClipIconView.java2
-rw-r--r--src/com/android/launcher3/views/FloatingIconView.java10
-rw-r--r--src/com/android/launcher3/views/OptionsPopupView.java52
-rw-r--r--src/com/android/launcher3/views/Snackbar.java6
-rw-r--r--src/com/android/launcher3/views/WidgetsEduView.java10
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. */