Merge "Fixing widget not laid-out properly in preview" into sc-v2-dev
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index fc1556e..872633c 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -415,8 +415,8 @@
@Override
public Stream<SystemShortcut.Factory> getSupportedShortcuts() {
- return Stream.concat(super.getSupportedShortcuts(),
- Stream.of(WellbeingModel.SHORTCUT_FACTORY));
+ return Stream.concat(Stream.of(WellbeingModel.SHORTCUT_FACTORY),
+ super.getSupportedShortcuts());
}
@Override
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index dccc9e1..66ccee6 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -34,6 +34,7 @@
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
import static com.android.launcher3.anim.Interpolators.EXAGGERATED_EASE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_SCRIM_FOR_APP_LAUNCH;
import static com.android.launcher3.config.FeatureFlags.KEYGUARD_ANIMATION;
import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_TRANSITIONS;
@@ -508,20 +509,23 @@
launcherAnimator.play(scaleAnim);
});
- int scrimColor = Themes.getAttrColor(mLauncher, R.attr.overviewScrimColor);
- int scrimColorTrans = ColorUtils.setAlphaComponent(scrimColor, 0);
- int[] colors = isAppOpening
- ? new int[] {scrimColorTrans, scrimColor}
- : new int[] {scrimColor, scrimColorTrans};
- ScrimView scrimView = mLauncher.getScrimView();
- if (scrimView.getBackground() instanceof ColorDrawable) {
- scrimView.setBackgroundColor(colors[0]);
+ final boolean scrimEnabled = ENABLE_SCRIM_FOR_APP_LAUNCH.get();
+ if (scrimEnabled) {
+ int scrimColor = Themes.getAttrColor(mLauncher, R.attr.overviewScrimColor);
+ int scrimColorTrans = ColorUtils.setAlphaComponent(scrimColor, 0);
+ int[] colors = isAppOpening
+ ? new int[]{scrimColorTrans, scrimColor}
+ : new int[]{scrimColor, scrimColorTrans};
+ ScrimView scrimView = mLauncher.getScrimView();
+ if (scrimView.getBackground() instanceof ColorDrawable) {
+ scrimView.setBackgroundColor(colors[0]);
- ObjectAnimator scrim = ObjectAnimator.ofArgb(scrimView, VIEW_BACKGROUND_COLOR,
- colors);
- scrim.setDuration(CONTENT_SCRIM_DURATION);
- scrim.setInterpolator(DEACCEL_1_5);
- launcherAnimator.play(scrim);
+ ObjectAnimator scrim = ObjectAnimator.ofArgb(scrimView, VIEW_BACKGROUND_COLOR,
+ colors);
+ scrim.setDuration(CONTENT_SCRIM_DURATION);
+ scrim.setInterpolator(DEACCEL_1_5);
+ launcherAnimator.play(scrim);
+ }
}
// Pause page indicator animations as they lead to layer trashing.
@@ -532,7 +536,9 @@
SCALE_PROPERTY.set(view, 1f);
view.setLayerType(View.LAYER_TYPE_NONE, null);
});
- scrimView.setBackgroundColor(Color.TRANSPARENT);
+ if (scrimEnabled) {
+ mLauncher.getScrimView().setBackgroundColor(Color.TRANSPARENT);
+ }
mLauncher.getWorkspace().getPageIndicator().skipAnimationsToEnd();
};
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index f4168d9..255ba1e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -15,27 +15,29 @@
*/
package com.android.launcher3.taskbar;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME;
-import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_LAUNCHER_STATE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.graphics.Rect;
import android.view.MotionEvent;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatorListeners;
-import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.quickstep.AnimatedFloat;
+import com.android.quickstep.RecentsAnimationCallbacks;
+import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
+import com.android.quickstep.RecentsAnimationController;
+import com.android.systemui.shared.recents.model.ThumbnailData;
/**
@@ -51,12 +53,19 @@
final TaskbarDragLayer mTaskbarDragLayer;
final TaskbarView mTaskbarView;
+ private final AnimatedFloat mIconAlignmentForResumedState =
+ new AnimatedFloat(this::onIconAlignmentRatioChanged);
+ private final AnimatedFloat mIconAlignmentForGestureState =
+ new AnimatedFloat(this::onIconAlignmentRatioChanged);
+
private AnimatedFloat mTaskbarBackgroundAlpha;
private AlphaProperty mIconAlphaForHome;
- private @Nullable Animator mAnimator;
private boolean mIsAnimatingToLauncher;
private TaskbarKeyguardController mKeyguardController;
+ private LauncherState mTargetStateOverride = null;
+ private TaskbarControllers mControllers;
+
public LauncherTaskbarUIController(
BaseQuickstepLauncher launcher, TaskbarActivityContext context) {
mContext = context;
@@ -67,7 +76,6 @@
mTaskbarStateHandler = mLauncher.getTaskbarStateHandler();
mHotseatController = new TaskbarHotseatController(
mLauncher, mTaskbarView::updateHotseatItems);
-
}
@Override
@@ -77,21 +85,17 @@
MultiValueAlpha taskbarIconAlpha = taskbarControllers.taskbarViewController
.getTaskbarIconAlpha();
mIconAlphaForHome = taskbarIconAlpha.getProperty(ALPHA_INDEX_HOME);
- mTaskbarStateHandler.setAnimationController(taskbarIconAlpha.getProperty(
- ALPHA_INDEX_LAUNCHER_STATE));
+ mControllers = taskbarControllers;
+
mHotseatController.init();
- setTaskbarViewVisible(!mLauncher.hasBeenResumed());
mLauncher.setTaskbarUIController(this);
mKeyguardController = taskbarControllers.taskbarKeyguardController;
+ onLauncherResumedOrPaused(mLauncher.hasBeenResumed());
+ mIconAlignmentForResumedState.finishAnimation();
}
@Override
protected void onDestroy() {
- if (mAnimator != null) {
- // End this first, in case it relies on properties that are about to be cleaned up.
- mAnimator.end();
- }
- mTaskbarStateHandler.setAnimationController(null);
mHotseatController.cleanup();
setTaskbarViewVisible(true);
mLauncher.getHotseat().setIconsAlpha(1f);
@@ -100,7 +104,7 @@
@Override
protected boolean isTaskbarTouchable() {
- return !mIsAnimatingToLauncher;
+ return !mIsAnimatingToLauncher && mTargetStateOverride == null;
}
@Override
@@ -128,63 +132,82 @@
}
}
- long duration = QuickstepTransitionManager.CONTENT_ALPHA_DURATION;
- if (mAnimator != null) {
- mAnimator.cancel();
- }
- if (isResumed) {
- mAnimator = createAnimToLauncher(mLauncher.getStateManager().getState(), duration);
- } else {
- mAnimator = createAnimToApp(duration);
- }
- mAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimator = null;
- }
- });
- mAnimator.start();
+ ObjectAnimator anim = mIconAlignmentForResumedState.animateToValue(
+ getCurrentIconAlignmentRatio(), isResumed ? 1 : 0)
+ .setDuration(QuickstepTransitionManager.CONTENT_ALPHA_DURATION);
+
+ anim.addListener(AnimatorListeners.forEndCallback(() -> mIsAnimatingToLauncher = false));
+ anim.start();
+ mIsAnimatingToLauncher = isResumed;
}
/**
- * Create Taskbar animation when going from an app to Launcher.
+ * Create Taskbar animation when going from an app to Launcher as part of recents transition.
* @param toState If known, the state we will end up in when reaching Launcher.
- * TODO: Move this and createAnimToApp to TaskbarStateHandler using the BACKGROUND state
+ * @param callbacks callbacks to track the recents animation lifecycle. The state change is
+ * automatically reset once the recents animation finishes
*/
- public Animator createAnimToLauncher(@NonNull LauncherState toState, long duration) {
- PendingAnimation anim = new PendingAnimation(duration);
- mTaskbarStateHandler.setState(toState, anim);
-
- anim.setFloat(mTaskbarBackgroundAlpha, AnimatedFloat.VALUE, 0, LINEAR);
- mTaskbarView.alignIconsWithLauncher(mLauncher.getDeviceProfile(), anim);
-
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mIsAnimatingToLauncher = true;
- }
-
+ public Animator createAnimToLauncher(@NonNull LauncherState toState,
+ @NonNull RecentsAnimationCallbacks callbacks,
+ long duration) {
+ ObjectAnimator animator = mIconAlignmentForGestureState
+ .animateToValue(mIconAlignmentForGestureState.value, 1)
+ .setDuration(duration);
+ animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- mIsAnimatingToLauncher = false;
- setTaskbarViewVisible(false);
+ mTargetStateOverride = null;
}
- });
- return anim.buildAnim();
- }
-
- private Animator createAnimToApp(long duration) {
- PendingAnimation anim = new PendingAnimation(duration);
- anim.setFloat(mTaskbarBackgroundAlpha, AnimatedFloat.VALUE, 1, LINEAR);
- anim.addListener(AnimatorListeners.forEndCallback(mTaskbarView.resetIconPosition(anim)));
- anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
- setTaskbarViewVisible(true);
+ mTargetStateOverride = toState;
}
});
- return anim.buildAnim();
+ callbacks.addListener(new RecentsAnimationListener() {
+ @Override
+ public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
+ endGestureStateOverride();
+ }
+
+ @Override
+ public void onRecentsAnimationFinished(RecentsAnimationController controller) {
+ endGestureStateOverride();
+ }
+
+ private void endGestureStateOverride() {
+ callbacks.removeListener(this);
+ mIconAlignmentForGestureState
+ .animateToValue(mIconAlignmentForGestureState.value, 0)
+ .start();
+ }
+ });
+ return animator;
+ }
+
+ private float getCurrentIconAlignmentRatio() {
+ return Math.max(mIconAlignmentForResumedState.value, mIconAlignmentForGestureState.value);
+ }
+
+ private void onIconAlignmentRatioChanged() {
+ if (mControllers == null) {
+ return;
+ }
+ float alignment = getCurrentIconAlignmentRatio();
+ mControllers.taskbarViewController.setLauncherIconAlignment(
+ alignment, mLauncher.getDeviceProfile());
+
+ mTaskbarBackgroundAlpha.updateValue(1 - alignment);
+
+ LauncherState state = mTargetStateOverride != null ? mTargetStateOverride
+ : mLauncher.getStateManager().getState();
+ if ((state.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
+ // If the hotseat icons are visible, then switch taskbar in last frame
+ setTaskbarViewVisible(alignment < 1);
+ } else {
+ mLauncher.getHotseat().setIconsAlpha(1);
+ mIconAlphaForHome.setValue(1 - alignment);
+ }
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 000799b..106ebe5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -17,7 +17,6 @@
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
@@ -93,6 +92,7 @@
private final ViewCache mViewCache = new ViewCache();
private final boolean mIsSafeModeEnabled;
+ private boolean mIsDestroyed = false;
public TaskbarActivityContext(Context windowContext, DeviceProfile dp,
TaskbarNavButtonController buttonController) {
@@ -208,6 +208,7 @@
* Called when this instance of taskbar is no longer needed
*/
public void onDestroy() {
+ mIsDestroyed = true;
setUIController(TaskbarUIController.DEFAULT);
mControllers.onDestroy();
mWindowManager.removeViewImmediate(mDragLayer);
@@ -252,7 +253,7 @@
* Updates the TaskbarContainer height (pass deviceProfile.taskbarSize to reset).
*/
public void setTaskbarWindowHeight(int height) {
- if (mWindowLayoutParams.height == height) {
+ if (mWindowLayoutParams.height == height || mIsDestroyed) {
return;
}
if (height != MATCH_PARENT) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
index 20d4133..edd2a22 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
@@ -18,45 +18,33 @@
import static com.android.launcher3.LauncherState.TASKBAR;
import static com.android.launcher3.anim.Interpolators.LINEAR;
-import androidx.annotation.Nullable;
-
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.util.MultiValueAlpha;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.SystemUiProxy;
/**
- * StateHandler to animate Taskbar according to Launcher's state machine. Does nothing if Taskbar
- * isn't present (i.e. {@link #setAnimationController} is never called).
+ * StateHandler to animate Taskbar according to Launcher's state machine.
*/
public class TaskbarStateHandler implements StateManager.StateHandler<LauncherState> {
private final BaseQuickstepLauncher mLauncher;
- // Contains Taskbar-related properties we should aniamte. If null, don't do anything.
- private @Nullable MultiValueAlpha.AlphaProperty mTaskbarAlpha = null;
-
private AnimatedFloat mNavbarButtonAlpha = new AnimatedFloat(this::updateNavbarButtonAlpha);
public TaskbarStateHandler(BaseQuickstepLauncher launcher) {
mLauncher = launcher;
}
- public void setAnimationController(MultiValueAlpha.AlphaProperty taskbarAlpha) {
- mTaskbarAlpha = taskbarAlpha;
- // Reapply state.
- setState(mLauncher.getStateManager().getState());
- updateNavbarButtonAlpha();
- }
-
@Override
public void setState(LauncherState state) {
setState(state, PropertySetter.NO_ANIM_PROPERTY_SETTER);
+ // Force update the alpha in case it was not initialized properly
+ updateNavbarButtonAlpha();
}
@Override
@@ -69,12 +57,7 @@
* Sets the provided state
*/
public void setState(LauncherState toState, PropertySetter setter) {
- if (mTaskbarAlpha == null) {
- return;
- }
-
boolean isTaskbarVisible = (toState.getVisibleElements(mLauncher) & TASKBAR) != 0;
- setter.setFloat(mTaskbarAlpha, MultiValueAlpha.VALUE, isTaskbarVisible ? 1f : 0f, LINEAR);
// Make the nav bar visible in states that taskbar isn't visible.
// TODO: We should draw our own handle instead of showing the nav bar.
float navbarButtonAlpha = isTaskbarVisible ? 0f : 1f;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index a952182..7753f96 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -15,11 +15,6 @@
*/
package com.android.launcher3.taskbar;
-import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
-import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
-import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
@@ -34,10 +29,8 @@
import androidx.annotation.Nullable;
import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
-import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
@@ -105,51 +98,6 @@
mIconLongClickListener = mControllerCallbacks.getOnLongClickListener();
}
- /**
- * Aligns the icons in the taskbar to that of Launcher.
- */
- public void alignIconsWithLauncher(DeviceProfile launcherDp, PropertySetter setter) {
- Rect hotseatPadding = launcherDp.getHotseatLayoutPadding(getContext());
- float scaleUp = ((float) launcherDp.iconSizePx)
- / mActivityContext.getDeviceProfile().iconSizePx;
- int hotseatCellSize =
- (launcherDp.availableWidthPx - hotseatPadding.left - hotseatPadding.right)
- / launcherDp.numShownHotseatIcons;
-
- int offsetY = launcherDp.getTaskbarOffsetY();
- setter.setFloat(this, VIEW_TRANSLATE_Y, -offsetY, LINEAR);
- mActivityContext.setTaskbarWindowHeight(
- mActivityContext.getDeviceProfile().taskbarSize + offsetY);
-
- int count = getChildCount();
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- ItemInfo info = (ItemInfo) child.getTag();
- setter.setFloat(child, SCALE_PROPERTY, scaleUp, LINEAR);
-
- float childCenter = (child.getLeft() + child.getRight()) / 2;
- float hotseatIconCenter = hotseatPadding.left + hotseatCellSize * info.screenId
- + hotseatCellSize / 2;
- setter.setFloat(child, VIEW_TRANSLATE_X, hotseatIconCenter - childCenter, LINEAR);
- }
- }
-
- /**
- * Aligns the icons in the taskbar to that of Launcher.
- * @return a callback to be executed at the end of the setter
- */
- public Runnable resetIconPosition(PropertySetter setter) {
- int count = getChildCount();
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- setter.setFloat(child, SCALE_PROPERTY, 1, LINEAR);
- setter.setFloat(child, VIEW_TRANSLATE_X, 0, LINEAR);
- }
- setter.setFloat(this, VIEW_TRANSLATE_Y, 0, LINEAR);
- return () -> mActivityContext.setTaskbarWindowHeight(
- mActivityContext.getDeviceProfile().taskbarSize);
- }
-
private void removeAndRecycle(View view) {
removeView(view);
view.setOnClickListener(null);
@@ -195,6 +143,7 @@
// so if the info changes we need to reinflate. This should only happen if a new
// folder is dragged to the position that another folder previously existed.
removeAndRecycle(hotseatView);
+ hotseatView = null;
} else {
// View found
break;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 10cc926..c7ac4a4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -15,19 +15,29 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+
+import android.graphics.Rect;
import android.view.View;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.MultiValueAlpha;
/**
* Handles properties/data collection, then passes the results to TaskbarView to render.
*/
public class TaskbarViewController {
+ private static final Runnable NO_OP = () -> { };
public static final int ALPHA_INDEX_HOME = 0;
- public static final int ALPHA_INDEX_LAUNCHER_STATE = 1;
- public static final int ALPHA_INDEX_IME = 2;
- public static final int ALPHA_INDEX_KEYGUARD = 3;
+ public static final int ALPHA_INDEX_IME = 1;
+ public static final int ALPHA_INDEX_KEYGUARD = 2;
private final TaskbarActivityContext mActivity;
private final TaskbarView mTaskbarView;
@@ -36,10 +46,15 @@
// Initialized in init.
private TaskbarControllers mControllers;
+ // Animation to align icons with Launcher, created lazily. This allows the controller to be
+ // active only during the animation and does not need to worry about layout changes.
+ private AnimatorPlaybackController mIconAlignControllerLazy = null;
+ private Runnable mOnControllerPreCreateCallback = NO_OP;
+
public TaskbarViewController(TaskbarActivityContext activity, TaskbarView taskbarView) {
mActivity = activity;
mTaskbarView = taskbarView;
- mTaskbarIconAlpha = new MultiValueAlpha(mTaskbarView, 4);
+ mTaskbarIconAlpha = new MultiValueAlpha(mTaskbarView, 3);
mTaskbarIconAlpha.setUpdateVisibility(true);
}
@@ -72,6 +87,60 @@
}
/**
+ * Sets the taskbar icon alignment relative to Launcher hotseat icons
+ * @param alignmentRatio [0, 1]
+ * 0 => not aligned
+ * 1 => fully aligned
+ */
+ public void setLauncherIconAlignment(float alignmentRatio, DeviceProfile launcherDp) {
+ if (mIconAlignControllerLazy == null) {
+ mIconAlignControllerLazy = createIconAlignmentController(launcherDp);
+ }
+ mIconAlignControllerLazy.setPlayFraction(alignmentRatio);
+ if (alignmentRatio <= 0 || alignmentRatio >= 1) {
+ // Cleanup lazy controller so that it is created again in next animation
+ mIconAlignControllerLazy = null;
+ }
+ }
+
+ /**
+ * Creates an animation for aligning the taskbar icons with the provided Launcher device profile
+ */
+ private AnimatorPlaybackController createIconAlignmentController(DeviceProfile launcherDp) {
+ mOnControllerPreCreateCallback.run();
+ PendingAnimation setter = new PendingAnimation(100);
+ Rect hotseatPadding = launcherDp.getHotseatLayoutPadding(mActivity);
+ float scaleUp = ((float) launcherDp.iconSizePx) / mActivity.getDeviceProfile().iconSizePx;
+ int hotseatCellSize =
+ (launcherDp.availableWidthPx - hotseatPadding.left - hotseatPadding.right)
+ / launcherDp.numShownHotseatIcons;
+
+ int offsetY = launcherDp.getTaskbarOffsetY();
+ setter.setFloat(mTaskbarView, VIEW_TRANSLATE_Y, -offsetY, LINEAR);
+
+ int collapsedHeight = mActivity.getDeviceProfile().taskbarSize;
+ int expandedHeight = collapsedHeight + offsetY;
+ setter.addOnFrameListener(anim -> mActivity.setTaskbarWindowHeight(
+ anim.getAnimatedFraction() > 0 ? expandedHeight : collapsedHeight));
+
+ int count = mTaskbarView.getChildCount();
+ for (int i = 0; i < count; i++) {
+ View child = mTaskbarView.getChildAt(i);
+ ItemInfo info = (ItemInfo) child.getTag();
+ setter.setFloat(child, SCALE_PROPERTY, scaleUp, LINEAR);
+
+ float childCenter = (child.getLeft() + child.getRight()) / 2;
+ float hotseatIconCenter = hotseatPadding.left + hotseatCellSize * info.screenId
+ + hotseatCellSize / 2;
+ setter.setFloat(child, VIEW_TRANSLATE_X, hotseatIconCenter - childCenter, LINEAR);
+ }
+
+ AnimatorPlaybackController controller = setter.createPlaybackController();
+ mOnControllerPreCreateCallback = () -> controller.setPlayFraction(0);
+ return controller;
+ }
+
+ /**
* Callbacks for {@link TaskbarView} to interact with its controller.
*/
public class TaskbarViewCallbacks {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index f0b02b3..ec9893c 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -192,7 +192,7 @@
@Override
public Stream<SystemShortcut.Factory> getSupportedShortcuts() {
return Stream.concat(
- super.getSupportedShortcuts(), Stream.of(mHotseatPredictionController));
+ Stream.of(mHotseatPredictionController), super.getSupportedShortcuts());
}
/**
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 0ebaea2..a8658a7 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1107,7 +1107,8 @@
mActivityRestartListener);
mParallelRunningAnim = mActivityInterface.getParallelAnimationToLauncher(
- mGestureState.getEndTarget(), duration);
+ mGestureState.getEndTarget(), duration,
+ mTaskAnimationManager.getCurrentCallbacks());
if (mParallelRunningAnim != null) {
mParallelRunningAnim.start();
}
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index a45ced4..2699b07 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -346,7 +346,8 @@
* an optional additional animation with the same duration.
*/
public @Nullable Animator getParallelAnimationToLauncher(
- GestureState.GestureEndTarget endTarget, long duration) {
+ GestureState.GestureEndTarget endTarget, long duration,
+ RecentsAnimationCallbacks callbacks) {
if (endTarget == RECENTS) {
ACTIVITY_TYPE activity = getCreatedActivity();
if (activity == null) {
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 30abfbb..799a4c2 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -284,14 +284,15 @@
@Override
public @Nullable Animator getParallelAnimationToLauncher(GestureEndTarget endTarget,
- long duration) {
+ long duration, RecentsAnimationCallbacks callbacks) {
LauncherTaskbarUIController uiController = getTaskbarController();
- Animator superAnimator = super.getParallelAnimationToLauncher(endTarget, duration);
- if (uiController == null) {
+ Animator superAnimator = super.getParallelAnimationToLauncher(
+ endTarget, duration, callbacks);
+ if (uiController == null || callbacks == null) {
return superAnimator;
}
LauncherState toState = stateFromGestureEndTarget(endTarget);
- Animator taskbarAnimator = uiController.createAnimToLauncher(toState, duration);
+ Animator taskbarAnimator = uiController.createAnimToLauncher(toState, callbacks, duration);
if (superAnimator == null) {
return taskbarAnimator;
} else {
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 9731bf1..1c178ad 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -28,6 +28,7 @@
import android.os.SystemProperties;
import android.util.Log;
+import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import com.android.launcher3.Utilities;
@@ -261,6 +262,11 @@
mLastAppearedTaskTarget = null;
}
+ @Nullable
+ public RecentsAnimationCallbacks getCurrentCallbacks() {
+ return mCallbacks;
+ }
+
public void dump() {
// TODO
}
diff --git a/res/drawable/ic_block_no_shadow.xml b/res/drawable/ic_block_no_shadow.xml
index be9aa07..6ac61f4 100644
--- a/res/drawable/ic_block_no_shadow.xml
+++ b/res/drawable/ic_block_no_shadow.xml
@@ -16,8 +16,8 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
- android:viewportHeight="20.0"
- android:viewportWidth="20.0"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0"
android:tint="?android:attr/textColorPrimary">
<path
android:fillColor="@android:color/white"
diff --git a/res/drawable/ic_drag_handle.xml b/res/drawable/ic_drag_handle.xml
index 0181ff1..9db75f4 100644
--- a/res/drawable/ic_drag_handle.xml
+++ b/res/drawable/ic_drag_handle.xml
@@ -19,7 +19,7 @@
android:height="@dimen/deep_shortcut_drag_handle_size"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
- android:tint="?android:attr/textColorHint" >
+ android:tint="?android:attr/textColorPrimary" >
<path
android:pathData="M20,9H4v2h16V9z M4,15h16v-2H4V15z"
diff --git a/res/drawable/ic_uninstall_no_shadow.xml b/res/drawable/ic_uninstall_no_shadow.xml
index 14cecac..fbabdd2 100644
--- a/res/drawable/ic_uninstall_no_shadow.xml
+++ b/res/drawable/ic_uninstall_no_shadow.xml
@@ -16,8 +16,8 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
- android:viewportWidth="20.0"
- android:viewportHeight="20.0"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
android:tint="?android:attr/textColorPrimary" >
<path
android:fillColor="@android:color/white"
diff --git a/res/layout/system_shortcut.xml b/res/layout/system_shortcut.xml
index 6337fae..2cdf1f4 100644
--- a/res/layout/system_shortcut.xml
+++ b/res/layout/system_shortcut.xml
@@ -45,6 +45,6 @@
android:layout_height="@dimen/system_shortcut_icon_size"
android:layout_marginStart="@dimen/system_shortcut_margin_start"
android:layout_gravity="start|center_vertical"
- android:backgroundTint="?android:attr/textColorTertiary"/>
+ android:backgroundTint="?android:attr/textColorPrimary"/>
</com.android.launcher3.shortcuts.DeepShortcutView>
diff --git a/res/layout/widget_shortcut_container.xml b/res/layout/widget_shortcut_container.xml
new file mode 100644
index 0000000..a4d8eb4
--- /dev/null
+++ b/res/layout/widget_shortcut_container.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/system_shortcut_full"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/system_shortcut_header_height"
+ android:orientation="horizontal"
+ android:gravity="end|center_vertical"
+ android:elevation="@dimen/deep_shortcuts_elevation"
+ android:tag="@string/popup_container_iterate_children"
+ android:clipToPadding="true">
+</LinearLayout>
diff --git a/res/values-v28/styles.xml b/res/values-v28/styles.xml
deleted file mode 100644
index 7df9ce5..0000000
--- a/res/values-v28/styles.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* Copyright (C) 2019 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.
-*/
--->
-<resources>
- <style name="TextHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle" >
- <item name="android:textFontWeight">400</item>
- </style>
-</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a94ff06..c828146 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -98,7 +98,7 @@
<dimen name="all_apps_header_tab_height">48dp</dimen>
<dimen name="all_apps_tabs_indicator_height">2dp</dimen>
<dimen name="all_apps_header_top_padding">36dp</dimen>
- <dimen name="all_apps_header_bottom_padding">16dp</dimen>
+ <dimen name="all_apps_header_bottom_padding">6dp</dimen>
<dimen name="all_apps_work_profile_tab_footer_top_padding">16dp</dimen>
<dimen name="all_apps_work_profile_tab_footer_bottom_padding">20dp</dimen>
<dimen name="all_apps_tabs_vertical_padding">6dp</dimen>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 38bc272..7274aa9 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -214,7 +214,9 @@
<item name="disabledIconAlpha">.54</item>
</style>
- <style name="BaseIconUnBounded" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle">
+ <style name="BaseIconRoot" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle"/>
+
+ <style name="BaseIconUnBounded" parent="BaseIconRoot">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">match_parent</item>
<item name="android:layout_gravity">center</item>
@@ -276,7 +278,7 @@
<style name="DropTargetButton" parent="DropTargetButtonBase" />
- <style name="TextHeadline" parent="@android:style/TextAppearance.DeviceDefault" />
+ <style name="TextHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle" />
<style name="PrimaryHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle"/>
diff --git a/robolectric_tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java b/robolectric_tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java
index c7286e5..2d87957 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java
@@ -36,6 +36,10 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
@RunWith(RobolectricTestRunner.class)
public final class LauncherAppWidgetProviderInfoTest {
@@ -234,10 +238,11 @@
Mockito.when(profile.getCellSize()).thenReturn(new Point(CELL_SIZE, CELL_SIZE));
InvariantDeviceProfile idp = new InvariantDeviceProfile();
- idp.supportedProfiles.add(profile);
+ List<DeviceProfile> supportedProfiles = new ArrayList<>(idp.supportedProfiles);
+ supportedProfiles.add(profile);
+ idp.supportedProfiles = Collections.unmodifiableList(supportedProfiles);
idp.numColumns = NUM_OF_COLS;
idp.numRows = NUM_OF_ROWS;
return idp;
}
-
}
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 7db34a5..85d17cf 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -36,8 +36,6 @@
import android.widget.PopupWindow;
import android.widget.TextView;
-import androidx.appcompat.content.res.AppCompatResources;
-
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
@@ -82,6 +80,8 @@
private boolean mAccessibleDrag;
/** An item must be dragged at least this many pixels before this drop target is enabled. */
private final int mDragDistanceThreshold;
+ /** The size of the drawable shown in the drop target. */
+ private final int mDrawableSize;
protected CharSequence mText;
protected ColorStateList mOriginalTextColor;
@@ -103,6 +103,7 @@
Resources resources = getResources();
mDragDistanceThreshold = resources.getDimensionPixelSize(R.dimen.drag_distanceThreshold);
+ mDrawableSize = resources.getDimensionPixelSize(R.dimen.drop_target_text_size);
}
@Override
@@ -120,14 +121,18 @@
}
protected void setDrawable(int resId) {
+ mDrawable = getContext().getDrawable(resId).mutate();
+ mDrawable.setBounds(0, 0, mDrawableSize, mDrawableSize);
+ setDrawable(mDrawable);
+ }
+
+ private void setDrawable(Drawable drawable) {
// We do not set the drawable in the xml as that inflates two drawables corresponding to
// drawableLeft and drawableStart.
if (mTextVisible) {
- setCompoundDrawablesRelativeWithIntrinsicBounds(resId, 0, 0, 0);
- mDrawable = getCompoundDrawablesRelative()[0];
+ setCompoundDrawablesRelative(drawable, null, null, null);
} else {
- setCompoundDrawablesRelativeWithIntrinsicBounds(0, resId, 0, 0);
- mDrawable = getCompoundDrawablesRelative()[1];
+ setCompoundDrawablesRelative(null, drawable, null, null);
}
}
@@ -238,11 +243,8 @@
return;
}
final DragLayer dragLayer = mLauncher.getDragLayer();
- final Rect from = new Rect();
- dragLayer.getViewRectRelativeToSelf(d.dragView, from);
-
final Rect to = getIconRect(d);
- final float scale = (float) to.width() / from.width();
+ final float scale = (float) to.width() / d.dragView.getMeasuredWidth();
d.dragView.detachContentView(/* reattachToPreviousParent= */ true);
mDropTargetBar.deferOnDragEnd();
@@ -252,9 +254,9 @@
mLauncher.getStateManager().goToState(NORMAL);
};
- dragLayer.animateView(d.dragView, from, to, scale, 1f, 1f, 0.1f, 0.1f,
+ dragLayer.animateView(d.dragView, to, scale, 0.1f, 0.1f,
DRAG_VIEW_DROP_DURATION,
- Interpolators.DEACCEL_2, Interpolators.LINEAR, onAnimationEndRunnable,
+ Interpolators.DEACCEL_2, onAnimationEndRunnable,
DragLayer.ANIMATION_END_DISAPPEAR, null);
}
@@ -329,11 +331,7 @@
if (mTextVisible != isVisible || !TextUtils.equals(newText, getText())) {
mTextVisible = isVisible;
setText(newText);
- if (mTextVisible) {
- setCompoundDrawablesRelativeWithIntrinsicBounds(mDrawable, null, null, null);
- } else {
- setCompoundDrawablesRelativeWithIntrinsicBounds(null, mDrawable, null, null);
- }
+ setDrawable(mDrawable);
}
}
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 115d3ae..a2bd201 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -138,7 +138,10 @@
public int defaultLayoutId;
int demoModeLayoutId;
- public final List<DeviceProfile> supportedProfiles = new ArrayList<>();
+ /**
+ * An immutable list of supported profiles.
+ */
+ public List<DeviceProfile> supportedProfiles = Collections.EMPTY_LIST;
@Nullable public DevicePaddings devicePaddings;
@@ -313,10 +316,10 @@
// Supported overrides: numRows, numColumns, iconSize
applyPartnerDeviceProfileOverrides(context, metrics);
- supportedProfiles.clear();
+ final List<DeviceProfile> localSupportedProfiles = new ArrayList<>();
defaultWallpaperSize = new Point(displayInfo.currentSize);
for (WindowBounds bounds : displayInfo.supportedBounds) {
- supportedProfiles.add(new DeviceProfile.Builder(context, this, displayInfo)
+ localSupportedProfiles.add(new DeviceProfile.Builder(context, this, displayInfo)
.setUseTwoPanels(isSplitDisplay)
.setWindowBounds(bounds).build());
@@ -334,6 +337,7 @@
defaultWallpaperSize.x =
Math.max(defaultWallpaperSize.x, Math.round(parallaxFactor * displayWidth));
}
+ supportedProfiles = Collections.unmodifiableList(localSupportedProfiles);
ComponentName cn = new ComponentName(context.getPackageName(), getClass().getName());
defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index aba8a40..a08fa1f 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -2732,9 +2732,6 @@
public void animateWidgetDrop(ItemInfo info, CellLayout cellLayout, final DragView dragView,
final Runnable onCompleteRunnable, int animationType, final View finalView,
boolean external) {
- Rect from = new Rect();
- mLauncher.getDragLayer().getViewRectRelativeToSelf(dragView, from);
-
int[] finalPos = new int[2];
float scaleXY[] = new float[2];
boolean scalePreview = !(info instanceof PendingAddShortcutInfo);
@@ -2778,8 +2775,8 @@
}
}
};
- dragLayer.animateViewIntoPosition(dragView, from.left, from.top, finalPos[0],
- finalPos[1], 1, 1, 1, scaleXY[0], scaleXY[1], onComplete, endStyle,
+ dragLayer.animateViewIntoPosition(dragView, finalPos[0],
+ finalPos[1], 1, scaleXY[0], scaleXY[1], onComplete, endStyle,
duration, this);
}
}
@@ -2838,6 +2835,10 @@
removeWorkspaceItem(mDragInfo.cell);
}
} else if (mDragInfo != null) {
+ // When drag is cancelled, reattach content view back to its original parent.
+ if (mDragInfo.cell instanceof LauncherAppWidgetHostView) {
+ d.dragView.detachContentView(/* reattachToPreviousParent= */ true);
+ }
final CellLayout cellLayout = mLauncher.getCellLayout(
mDragInfo.container, mDragInfo.screenId);
if (cellLayout != null) {
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 7003df1..39d1a00 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -21,6 +21,8 @@
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
@@ -81,10 +83,7 @@
ScrimView.ScrimDrawingController {
public static final float PULL_MULTIPLIER = .02f;
- public static final float FLING_VELOCITY_MULTIPLIER = 2000f;
-
- // Starts the springs after at least 25% of the animation has passed.
- public static final float FLING_ANIMATION_THRESHOLD = 0.25f;
+ public static final float FLING_VELOCITY_MULTIPLIER = 1200f;
private final Paint mHeaderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -645,20 +644,18 @@
/**
* Adds an update listener to {@param animator} that adds springs to the animation.
*/
- public void addSpringFromFlingUpdateListener(ValueAnimator animator, float velocity) {
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- boolean shouldSpring = true;
-
+ public void addSpringFromFlingUpdateListener(ValueAnimator animator,
+ float velocity /* release velocity */,
+ float progress /* portion of the distance to travel*/) {
+ animator.addListener(new AnimatorListenerAdapter() {
@Override
- public void onAnimationUpdate(ValueAnimator valueAnimator) {
- if (shouldSpring
- && valueAnimator.getAnimatedFraction() >= FLING_ANIMATION_THRESHOLD) {
- absorbSwipeUpVelocity(Math.max(100, Math.abs(
- Math.round(velocity * FLING_VELOCITY_MULTIPLIER))));
- // calculate the velocity of using the not user controlled interpolator
- // of when the container reach the end.
- shouldSpring = false;
- }
+ public void onAnimationStart(Animator animator) {
+ float distance = (float) ((1 - progress) * getHeight()); // px
+ float settleVelocity = Math.min(0, distance
+ / (AllAppsTransitionController.INTERP_COEFF * animator.getDuration())
+ + velocity);
+ absorbSwipeUpVelocity(Math.max(1000, Math.abs(
+ Math.round(settleVelocity * FLING_VELOCITY_MULTIPLIER))));
}
});
}
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 8ec8269..a0551f0 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -57,6 +57,8 @@
*/
public class AllAppsTransitionController
implements StateHandler<LauncherState>, OnDeviceProfileChangeListener {
+ // This constant should match the second derivative of the animator interpolator.
+ public static final float INTERP_COEFF = 1.7f;
private static final float CONTENT_VISIBLE_MAX_THRESHOLD = 0.5f;
public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PROGRESS =
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 5e3177a..fe2c50c 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -220,6 +220,10 @@
"ENABLE_TWO_PANEL_HOME", true,
"Uses two panel on home screen. Only applicable on large screen devices.");
+ public static final BooleanFlag ENABLE_SCRIM_FOR_APP_LAUNCH = getDebugFlag(
+ "ENABLE_SCRIM_FOR_APP_LAUNCH", false,
+ "Enables scrim during app launch animation.");
+
public static final BooleanFlag ENABLE_SPLIT_SELECT = getDebugFlag(
"ENABLE_SPLIT_SELECT", false, "Uses new split screen selection overview UI");
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 011325d..5ee4203 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -17,14 +17,19 @@
package com.android.launcher3.dragndrop;
+import static android.animation.ObjectAnimator.ofFloat;
+
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
+import static com.android.launcher3.Utilities.mapRange;
+import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.animation.TypeEvaluator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
@@ -44,10 +49,11 @@
import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Workspace;
+import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.anim.SpringProperty;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.graphics.Scrim;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
-import com.android.launcher3.util.Thunk;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.BaseDragLayer;
@@ -69,11 +75,9 @@
private DragController mDragController;
// Variables relating to animation of views after drop
- private ValueAnimator mDropAnim = null;
+ private Animator mDropAnim = null;
- @Thunk DragView mDropView = null;
- @Thunk int mAnchorViewInitialScrollX = 0;
- @Thunk View mAnchorView = null;
+ private DragView mDropView = null;
private boolean mHoverPointClosesFolder = false;
@@ -220,12 +224,7 @@
public void animateViewIntoPosition(DragView dragView, final int[] pos, float alpha,
float scaleX, float scaleY, int animationEndStyle, Runnable onFinishRunnable,
int duration) {
- Rect r = new Rect();
- getViewRectRelativeToSelf(dragView, r);
- final int fromX = r.left;
- final int fromY = r.top;
-
- animateViewIntoPosition(dragView, fromX, fromY, pos[0], pos[1], alpha, 1, 1, scaleX, scaleY,
+ animateViewIntoPosition(dragView, pos[0], pos[1], alpha, scaleX, scaleY,
onFinishRunnable, animationEndStyle, duration, null);
}
@@ -241,11 +240,6 @@
parentChildren.measureChild(child);
parentChildren.layoutChild(child);
- Rect dragViewBounds = new Rect();
- getViewRectRelativeToSelf(dragView, dragViewBounds);
- final int fromX = dragViewBounds.left;
- final int fromY = dragViewBounds.top;
-
float coord[] = new float[2];
float childScale = child.getScaleX();
@@ -288,51 +282,50 @@
child.setVisibility(INVISIBLE);
Runnable onCompleteRunnable = () -> child.setVisibility(VISIBLE);
- animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1, 1, 1, toScale, toScale,
+ animateViewIntoPosition(dragView, toX, toY, 1, toScale, toScale,
onCompleteRunnable, ANIMATION_END_DISAPPEAR, duration, anchorView);
}
- public void animateViewIntoPosition(final DragView view, final int fromX, final int fromY,
- final int toX, final int toY, float finalAlpha, float initScaleX, float initScaleY,
- float finalScaleX, float finalScaleY, Runnable onCompleteRunnable,
- int animationEndStyle, int duration, View anchorView) {
- Rect from = new Rect(fromX, fromY, fromX +
- view.getMeasuredWidth(), fromY + view.getMeasuredHeight());
- Rect to = new Rect(toX, toY, toX + view.getMeasuredWidth(), toY + view.getMeasuredHeight());
- animateView(view, from, to, finalAlpha, initScaleX, initScaleY, finalScaleX, finalScaleY, duration,
- null, null, onCompleteRunnable, animationEndStyle, anchorView);
- }
-
/**
* This method animates a view at the end of a drag and drop animation.
- *
+ */
+ public void animateViewIntoPosition(final DragView view,
+ final int toX, final int toY, float finalAlpha,
+ float finalScaleX, float finalScaleY, Runnable onCompleteRunnable,
+ int animationEndStyle, int duration, View anchorView) {
+ Rect to = new Rect(toX, toY, toX + view.getMeasuredWidth(), toY + view.getMeasuredHeight());
+ animateView(view, to, finalAlpha, finalScaleX, finalScaleY, duration,
+ null, onCompleteRunnable, animationEndStyle, anchorView);
+ }
+
+ /**
+ * This method animates a view at the end of a drag and drop animation.
* @param view The view to be animated. This view is drawn directly into DragLayer, and so
* doesn't need to be a child of DragLayer.
- * @param from The initial location of the view. Only the left and top parameters are used.
* @param to The final location of the view. Only the left and top parameters are used. This
- * location doesn't account for scaling, and so should be centered about the desired
- * final location (including scaling).
+* location doesn't account for scaling, and so should be centered about the desired
+* final location (including scaling).
* @param finalAlpha The final alpha of the view, in case we want it to fade as it animates.
* @param finalScaleX The final scale of the view. The view is scaled about its center.
* @param finalScaleY The final scale of the view. The view is scaled about its center.
* @param duration The duration of the animation.
* @param motionInterpolator The interpolator to use for the location of the view.
- * @param alphaInterpolator The interpolator to use for the alpha of the view.
* @param onCompleteRunnable Optional runnable to run on animation completion.
* @param animationEndStyle Whether or not to fade out the view once the animation completes.
- * {@link #ANIMATION_END_DISAPPEAR} or {@link #ANIMATION_END_REMAIN_VISIBLE}.
+* {@link #ANIMATION_END_DISAPPEAR} or {@link #ANIMATION_END_REMAIN_VISIBLE}.
* @param anchorView If not null, this represents the view which the animated view stays
- * anchored to in case scrolling is currently taking place. Note: currently this is
- * only used for the X dimension for the case of the workspace.
*/
- public void animateView(final DragView view, final Rect from, final Rect to,
- final float finalAlpha, final float initScaleX, final float initScaleY,
- final float finalScaleX, final float finalScaleY, int duration,
- final Interpolator motionInterpolator, final Interpolator alphaInterpolator,
- final Runnable onCompleteRunnable, final int animationEndStyle, View anchorView) {
+ public void animateView(final DragView view, final Rect to,
+ final float finalAlpha, final float finalScaleX, final float finalScaleY, int duration,
+ final Interpolator motionInterpolator, final Runnable onCompleteRunnable,
+ final int animationEndStyle, View anchorView) {
+ view.cancelAnimation();
+ view.requestLayout();
+
+ final int[] from = getViewLocationRelativeToSelf(view);
// Calculate the duration of the animation based on the object's distance
- final float dist = (float) Math.hypot(to.left - from.left, to.top - from.top);
+ final float dist = (float) Math.hypot(to.left - from[0], to.top - from[1]);
final Resources res = getResources();
final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
@@ -346,93 +339,45 @@
}
// Fall back to cubic ease out interpolator for the animation if none is specified
- TimeInterpolator interpolator = null;
- if (alphaInterpolator == null || motionInterpolator == null) {
- interpolator = DEACCEL_1_5;
- }
+ TimeInterpolator interpolator =
+ motionInterpolator == null ? DEACCEL_1_5 : motionInterpolator;
// Animate the view
- final float initAlpha = view.getAlpha();
- final float dropViewScale = view.getScaleX();
- AnimatorUpdateListener updateCb = new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- final float percent = (Float) animation.getAnimatedValue();
- final int width = view.getMeasuredWidth();
- final int height = view.getMeasuredHeight();
+ PendingAnimation anim = new PendingAnimation(duration);
+ anim.add(ofFloat(view, View.SCALE_X, finalScaleX), interpolator, SpringProperty.DEFAULT);
+ anim.add(ofFloat(view, View.SCALE_Y, finalScaleY), interpolator, SpringProperty.DEFAULT);
+ anim.setViewAlpha(view, finalAlpha, interpolator);
+ anim.setFloat(view, VIEW_TRANSLATE_Y, to.top, interpolator);
- float alphaPercent = alphaInterpolator == null ? percent :
- alphaInterpolator.getInterpolation(percent);
- float motionPercent = motionInterpolator == null ? percent :
- motionInterpolator.getInterpolation(percent);
-
- float initialScaleX = initScaleX * dropViewScale;
- float initialScaleY = initScaleY * dropViewScale;
- float scaleX = finalScaleX * percent + initialScaleX * (1 - percent);
- float scaleY = finalScaleY * percent + initialScaleY * (1 - percent);
- float alpha = finalAlpha * alphaPercent + initAlpha * (1 - alphaPercent);
-
- float fromLeft = from.left + (initialScaleX - 1f) * width / 2;
- float fromTop = from.top + (initialScaleY - 1f) * height / 2;
-
- int x = (int) (fromLeft + Math.round(((to.left - fromLeft) * motionPercent)));
- int y = (int) (fromTop + Math.round(((to.top - fromTop) * motionPercent)));
-
- int anchorAdjust = mAnchorView == null ? 0 : (int) (mAnchorView.getScaleX() *
- (mAnchorViewInitialScrollX - mAnchorView.getScrollX()));
-
- int xPos = x - mDropView.getScrollX() + anchorAdjust;
- int yPos = y - mDropView.getScrollY();
-
- mDropView.setTranslationX(xPos);
- mDropView.setTranslationY(yPos);
- mDropView.setScaleX(scaleX);
- mDropView.setScaleY(scaleY);
- mDropView.setAlpha(alpha);
- }
- };
- animateView(view, updateCb, duration, interpolator, onCompleteRunnable, animationEndStyle,
- anchorView);
+ ObjectAnimator xMotion = ofFloat(view, VIEW_TRANSLATE_X, to.left);
+ if (anchorView != null) {
+ final int startScroll = anchorView.getScrollX();
+ TypeEvaluator<Float> evaluator = (f, s, e) -> mapRange(f, s, e)
+ + (anchorView.getScaleX() * (startScroll - anchorView.getScrollX()));
+ xMotion.setEvaluator(evaluator);
+ }
+ anim.add(xMotion, interpolator, SpringProperty.DEFAULT);
+ if (onCompleteRunnable != null) {
+ anim.addListener(forEndCallback(onCompleteRunnable));
+ }
+ playDropAnimation(view, anim.buildAnim(), animationEndStyle);
}
- public void animateView(final DragView view, AnimatorUpdateListener updateCb, int duration,
- TimeInterpolator interpolator, final Runnable onCompleteRunnable,
- final int animationEndStyle, View anchorView) {
+ /**
+ * Runs a previously constructed drop animation
+ */
+ public void playDropAnimation(final DragView view, Animator animator, int animationEndStyle) {
// Clean up the previous animations
if (mDropAnim != null) mDropAnim.cancel();
// Show the drop view if it was previously hidden
mDropView = view;
- mDropView.cancelAnimation();
- mDropView.requestLayout();
-
- // Set the anchor view if the page is scrolling
- if (anchorView != null) {
- mAnchorViewInitialScrollX = anchorView.getScrollX();
- }
- mAnchorView = anchorView;
-
// Create and start the animation
- mDropAnim = new ValueAnimator();
- mDropAnim.setInterpolator(interpolator);
- mDropAnim.setDuration(duration);
- mDropAnim.setFloatValues(0f, 1f);
- mDropAnim.addUpdateListener(updateCb);
- mDropAnim.addListener(new AnimatorListenerAdapter() {
- public void onAnimationEnd(Animator animation) {
- if (onCompleteRunnable != null) {
- onCompleteRunnable.run();
- }
- switch (animationEndStyle) {
- case ANIMATION_END_DISAPPEAR:
- clearAnimatedView();
- break;
- case ANIMATION_END_REMAIN_VISIBLE:
- break;
- }
- mDropAnim = null;
- }
- });
+ mDropAnim = animator;
+ mDropAnim.addListener(forEndCallback(() -> mDropAnim = null));
+ if (animationEndStyle == ANIMATION_END_DISAPPEAR) {
+ mDropAnim.addListener(forEndCallback(this::clearAnimatedView));
+ }
mDropAnim.start();
}
diff --git a/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java b/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
index 3457804..54967a9 100644
--- a/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
+++ b/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
@@ -34,7 +34,6 @@
float totalScale = scaleForItem(curNumItems);
float transX;
float transY;
- float overlayAlpha = 0;
if (index == EXIT_INDEX) {
// 0 1 * <-- Exit position (row 0, col 2)
@@ -55,10 +54,9 @@
transY = mTmpPoint[1];
if (params == null) {
- params = new PreviewItemDrawingParams(transX, transY, totalScale, overlayAlpha);
+ params = new PreviewItemDrawingParams(transX, transY, totalScale);
} else {
params.update(transX, transY, totalScale);
- params.overlayAlpha = overlayAlpha;
}
return params;
}
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index 57b289e..4fe85be 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -79,7 +79,7 @@
private final TimeInterpolator mLargeFolderPreviewItemOpenInterpolator;
private final TimeInterpolator mLargeFolderPreviewItemCloseInterpolator;
- private final PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
+ private final PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0);
private final FolderGridOrganizer mPreviewVerifier;
private ObjectAnimator mBgColorAnimator;
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index ed2d0a9..aedb224 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -113,7 +113,7 @@
FolderGridOrganizer mPreviewVerifier;
ClippedFolderIconLayoutRule mPreviewLayoutRule;
private PreviewItemManager mPreviewItemManager;
- private PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
+ private PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0);
private List<WorkspaceItemInfo> mCurrentPreviewItems = new ArrayList<>();
boolean mAnimating = false;
@@ -336,8 +336,6 @@
if (animateView != null && mActivity instanceof Launcher) {
final Launcher launcher = (Launcher) mActivity;
DragLayer dragLayer = launcher.getDragLayer();
- Rect from = new Rect();
- dragLayer.getViewRectRelativeToSelf(animateView, from);
Rect to = finalRect;
if (to == null) {
to = new Rect();
@@ -391,7 +389,7 @@
to.offset(center[0] - animateView.getMeasuredWidth() / 2,
center[1] - animateView.getMeasuredHeight() / 2);
- float finalAlpha = index < MAX_NUM_ITEMS_IN_PREVIEW ? 0.5f : 0f;
+ float finalAlpha = index < MAX_NUM_ITEMS_IN_PREVIEW ? 1f : 0f;
float finalScale = scale * scaleRelativeToDragLayer;
@@ -402,15 +400,19 @@
finalScale *= containerScale;
}
- dragLayer.animateView(animateView, from, to, finalAlpha,
- 1, 1, finalScale, finalScale, DROP_IN_ANIMATION_DURATION,
- Interpolators.DEACCEL_2, Interpolators.ACCEL_2,
- null, DragLayer.ANIMATION_END_DISAPPEAR, null);
+ final int finalIndex = index;
+ dragLayer.animateView(animateView, to, finalAlpha,
+ finalScale, finalScale, DROP_IN_ANIMATION_DURATION,
+ Interpolators.DEACCEL_2,
+ () -> {
+ mPreviewItemManager.hidePreviewItem(finalIndex, false);
+ mFolder.showItem(item);
+ },
+ DragLayer.ANIMATION_END_DISAPPEAR, null);
mFolder.hideItem(item);
if (!itemAdded) mPreviewItemManager.hidePreviewItem(index, true);
- final int finalIndex = index;
FolderNameInfos nameInfos = new FolderNameInfos();
if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
@@ -430,8 +432,6 @@
private void showFinalView(int finalIndex, final WorkspaceItemInfo item,
FolderNameInfos nameInfos, InstanceId instanceId) {
postDelayed(() -> {
- mPreviewItemManager.hidePreviewItem(finalIndex, false);
- mFolder.showItem(item);
setLabelSuggestion(nameInfos, instanceId);
invalidate();
}, DROP_IN_ANIMATION_DURATION);
diff --git a/src/com/android/launcher3/folder/FolderPreviewItemAnim.java b/src/com/android/launcher3/folder/FolderPreviewItemAnim.java
index edfd2ba..e20bafb 100644
--- a/src/com/android/launcher3/folder/FolderPreviewItemAnim.java
+++ b/src/com/android/launcher3/folder/FolderPreviewItemAnim.java
@@ -45,7 +45,7 @@
};
private static final PreviewItemDrawingParams sTmpParams =
- new PreviewItemDrawingParams(0, 0, 0, 0);
+ new PreviewItemDrawingParams(0, 0, 0);
private static final float[] sTempParamsArray = new float[3];
private final ObjectAnimator mAnimator;
diff --git a/src/com/android/launcher3/folder/PreviewItemDrawingParams.java b/src/com/android/launcher3/folder/PreviewItemDrawingParams.java
index 5746be8..58efdc1 100644
--- a/src/com/android/launcher3/folder/PreviewItemDrawingParams.java
+++ b/src/com/android/launcher3/folder/PreviewItemDrawingParams.java
@@ -27,17 +27,15 @@
float transX;
float transY;
float scale;
- float overlayAlpha;
public FolderPreviewItemAnim anim;
public boolean hidden;
public Drawable drawable;
public WorkspaceItemInfo item;
- PreviewItemDrawingParams(float transX, float transY, float scale, float overlayAlpha) {
+ PreviewItemDrawingParams(float transX, float transY, float scale) {
this.transX = transX;
this.transY = transY;
this.scale = scale;
- this.overlayAlpha = overlayAlpha;
}
public void update(float transX, float transY, float scale) {
diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java
index baafbc9..a6674fc 100644
--- a/src/com/android/launcher3/folder/PreviewItemManager.java
+++ b/src/com/android/launcher3/folder/PreviewItemManager.java
@@ -260,7 +260,7 @@
params.remove(params.size() - 1);
}
while (items.size() > params.size()) {
- params.add(new PreviewItemDrawingParams(0, 0, 0, 0));
+ params.add(new PreviewItemDrawingParams(0, 0, 0));
}
int numItemsInFirstPagePreview = page == 0 ? items.size() : MAX_NUM_ITEMS_IN_PREVIEW;
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 7bfa3ef..3c0a54a 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -212,7 +212,8 @@
}
if (si.isPromise() && isNewApkAvailable) {
- boolean isTargetValid = true;
+ boolean isTargetValid = !cn.getClassName().equals(
+ IconCache.EMPTY_CLASS_NAME);
if (si.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
List<ShortcutInfo> shortcut =
new ShortcutRequest(context, mUser)
@@ -225,7 +226,7 @@
si.updateFromDeepShortcutInfo(shortcut.get(0), context);
infoUpdated = true;
}
- } else if (!cn.getClassName().equals(IconCache.EMPTY_CLASS_NAME)) {
+ } else if (isTargetValid) {
isTargetValid = context.getSystemService(LauncherApps.class)
.isActivityEnabled(cn, mUser);
}
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 332390d..2ae12ac 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -96,6 +96,8 @@
private int mNumNotifications;
private ViewGroup mNotificationContainer;
+ private ViewGroup mWidgetContainer;
+
private ViewGroup mDeepShortcutContainer;
private ViewGroup mSystemShortcutContainer;
@@ -234,7 +236,7 @@
@Override
protected List<View> getChildrenForColorExtraction() {
- return Arrays.asList(mSystemShortcutContainer, mDeepShortcutContainer,
+ return Arrays.asList(mSystemShortcutContainer, mWidgetContainer, mDeepShortcutContainer,
mNotificationContainer);
}
@@ -298,10 +300,24 @@
updateHiddenShortcuts();
if (!systemShortcuts.isEmpty()) {
- mSystemShortcutContainer = inflateAndAdd(R.layout.system_shortcut_icons, this);
for (SystemShortcut shortcut : systemShortcuts) {
- initializeSystemShortcut(
- R.layout.system_shortcut_icon_only, mSystemShortcutContainer, shortcut);
+ if (shortcut instanceof SystemShortcut.Widgets) {
+ if (mWidgetContainer == null) {
+ mWidgetContainer = inflateAndAdd(R.layout.widget_shortcut_container,
+ this);
+ }
+ initializeSystemShortcut(R.layout.system_shortcut, mWidgetContainer,
+ shortcut);
+ }
+ }
+ mSystemShortcutContainer = inflateAndAdd(R.layout.system_shortcut_icons, this);
+
+ for (SystemShortcut shortcut : systemShortcuts) {
+ if (!(shortcut instanceof SystemShortcut.Widgets)) {
+ initializeSystemShortcut(
+ R.layout.system_shortcut_icon_only, mSystemShortcutContainer,
+ shortcut);
+ }
}
}
} else {
@@ -524,25 +540,34 @@
mLauncher.getPopupDataProvider().setChangeListener(null);
}
+ private View getWidgetsView(ViewGroup container) {
+ for (int i = container.getChildCount() - 1; i >= 0; --i) {
+ View systemShortcutView = container.getChildAt(i);
+ if (systemShortcutView.getTag() instanceof SystemShortcut.Widgets) {
+ return systemShortcutView;
+ }
+ }
+ return null;
+ }
+
@Override
public void onWidgetsBound() {
ItemInfo itemInfo = (ItemInfo) mOriginalIcon.getTag();
SystemShortcut widgetInfo = SystemShortcut.WIDGETS.getShortcut(mLauncher, itemInfo);
- View widgetsView = null;
- int count = mSystemShortcutContainer.getChildCount();
- for (int i = 0; i < count; i++) {
- View systemShortcutView = mSystemShortcutContainer.getChildAt(i);
- if (systemShortcutView.getTag() instanceof SystemShortcut.Widgets) {
- widgetsView = systemShortcutView;
- break;
- }
+ View widgetsView = getWidgetsView(PopupContainerWithArrow.this);
+ if (widgetsView == null && mWidgetContainer != null) {
+ widgetsView = getWidgetsView(mWidgetContainer);
}
if (widgetInfo != null && widgetsView == null) {
// We didn't have any widgets cached but now there are some, so enable the shortcut.
if (mSystemShortcutContainer != PopupContainerWithArrow.this) {
- initializeSystemShortcut(R.layout.system_shortcut_icon_only,
- mSystemShortcutContainer, widgetInfo);
+ if (mWidgetContainer == null) {
+ mWidgetContainer = inflateAndAdd(R.layout.widget_shortcut_container,
+ PopupContainerWithArrow.this);
+ }
+ initializeSystemShortcut(R.layout.system_shortcut, mWidgetContainer,
+ widgetInfo);
} else {
// If using the expanded system shortcut (as opposed to just the icon), we need
// to reopen the container to ensure measurements etc. all work out. While this
@@ -554,8 +579,10 @@
}
} else if (widgetInfo == null && widgetsView != null) {
// No widgets exist, but we previously added the shortcut so remove it.
- if (mSystemShortcutContainer != PopupContainerWithArrow.this) {
- mSystemShortcutContainer.removeView(widgetsView);
+ if (mSystemShortcutContainer
+ != PopupContainerWithArrow.this
+ && mWidgetContainer != null) {
+ mWidgetContainer.removeView(widgetsView);
} else {
close(false);
PopupContainerWithArrow.showForIcon(mOriginalIcon);
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index a086635..90f37f3 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -335,12 +335,10 @@
mCurrentAnimation.dispatchOnStart();
if (targetState == LauncherState.ALL_APPS && !UNSTABLE_SPRINGS.get()) {
if (mAllAppsOvershootStarted) {
-
mLauncher.getAppsView().onRelease();
mAllAppsOvershootStarted = false;
-
} else {
- mLauncher.getAppsView().addSpringFromFlingUpdateListener(anim, velocity);
+ mLauncher.getAppsView().addSpringFromFlingUpdateListener(anim, velocity, progress);
}
}
anim.start();
diff --git a/src/com/android/launcher3/util/FlingAnimation.java b/src/com/android/launcher3/util/FlingAnimation.java
index c9aa51c..ac864e9 100644
--- a/src/com/android/launcher3/util/FlingAnimation.java
+++ b/src/com/android/launcher3/util/FlingAnimation.java
@@ -1,12 +1,14 @@
package com.android.launcher3.util;
import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
@@ -35,7 +37,7 @@
protected final float mUX, mUY;
protected Rect mIconRect;
- protected Rect mFrom;
+ protected RectF mFrom;
protected int mDuration;
protected float mAnimationTimeFraction;
@@ -55,17 +57,17 @@
@Override
public void run() {
mIconRect = mDropTarget.getIconRect(mDragObject);
+ mDragObject.dragView.cancelAnimation();
+ mDragObject.dragView.requestLayout();
// Initiate from
- mFrom = new Rect();
- mDragLayer.getViewRectRelativeToSelf(mDragObject.dragView, mFrom);
- float scale = mDragObject.dragView.getScaleX();
- float xOffset = ((scale - 1f) * mDragObject.dragView.getMeasuredWidth()) / 2f;
- float yOffset = ((scale - 1f) * mDragObject.dragView.getMeasuredHeight()) / 2f;
- mFrom.left += xOffset;
- mFrom.right -= xOffset;
- mFrom.top += yOffset;
- mFrom.bottom -= yOffset;
+ Rect from = new Rect();
+ mDragLayer.getViewRectRelativeToSelf(mDragObject.dragView, from);
+
+ mFrom = new RectF(from);
+ mFrom.inset(
+ ((1 - mDragObject.dragView.getScaleX()) * from.width()) / 2f,
+ ((1 - mDragObject.dragView.getScaleY()) * from.height()) / 2f);
mDuration = Math.abs(mUY) > Math.abs(mUX) ? initFlingUpDuration() : initFlingLeftDuration();
mAnimationTimeFraction = ((float) mDuration) / (mDuration + DRAG_END_DELAY);
@@ -95,17 +97,15 @@
}
};
- Runnable onAnimationEndRunnable = new Runnable() {
- @Override
- public void run() {
- mLauncher.getStateManager().goToState(NORMAL);
- mDropTarget.completeDrop(mDragObject);
- }
- };
-
mDropTarget.onDrop(mDragObject, mDragOptions);
- mDragLayer.animateView(mDragObject.dragView, this, duration, tInterpolator,
- onAnimationEndRunnable, DragLayer.ANIMATION_END_DISAPPEAR, null);
+ ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
+ anim.setDuration(duration).setInterpolator(tInterpolator);
+ anim.addUpdateListener(this);
+ anim.addListener(forEndCallback(() -> {
+ mLauncher.getStateManager().goToState(NORMAL);
+ mDropTarget.completeDrop(mDragObject);
+ }));
+ mDragLayer.playDropAnimation(mDragObject.dragView, anim, DragLayer.ANIMATION_END_DISAPPEAR);
}
/**
@@ -129,7 +129,7 @@
}
double t = (-mUY - Math.sqrt(d)) / mAY;
- float sX = -mFrom.exactCenterX() + mIconRect.exactCenterX();
+ float sX = -mFrom.centerX() + mIconRect.exactCenterX();
// Find horizontal acceleration such that: u*t + a*t*t/2 = s
mAX = (float) ((sX - t * mUX) * 2 / (t * t));
@@ -157,7 +157,7 @@
}
double t = (-mUX - Math.sqrt(d)) / mAX;
- float sY = -mFrom.exactCenterY() + mIconRect.exactCenterY();
+ float sY = -mFrom.centerY() + mIconRect.exactCenterY();
// Find vertical acceleration such that: u*t + a*t*t/2 = s
mAY = (float) ((sY - t * mUY) * 2 / (t * t));
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index 01c0b56..76dfb3c 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -430,18 +430,20 @@
}
public void getViewRectRelativeToSelf(View v, Rect r) {
+ int[] loc = getViewLocationRelativeToSelf(v);
+ r.set(loc[0], loc[1], loc[0] + v.getMeasuredWidth(), loc[1] + v.getMeasuredHeight());
+ }
+
+ protected int[] getViewLocationRelativeToSelf(View v) {
int[] loc = new int[2];
getLocationInWindow(loc);
int x = loc[0];
int y = loc[1];
v.getLocationInWindow(loc);
- int vX = loc[0];
- int vY = loc[1];
-
- int left = vX - x;
- int top = vY - y;
- r.set(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
+ loc[0] -= x;
+ loc[1] -= y;
+ return loc;
}
@Override
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 6f47df0..06bc26a 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -293,7 +293,7 @@
try {
final AppIconMenu menu = allApps.
getAppIcon(APP_NAME).
- openMenu();
+ openDeepShortcutMenu();
executeOnLauncher(
launcher -> assertTrue("Launcher internal state didn't switch to Showing Menu",
@@ -341,7 +341,7 @@
try {
final AppIconMenu menu = allApps
.getAppIcon(APP_NAME)
- .openMenu();
+ .openDeepShortcutMenu();
final AppIconMenuItem menuItem0 = menu.getMenuItem(0);
final AppIconMenuItem menuItem2 = menu.getMenuItem(2);
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
index 56723b1..57fd08a 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
@@ -51,6 +51,16 @@
}
}
+ /**
+ * Long-clicks the icon to open its menu, and looks at the deep shortcuts container only.
+ */
+ public AppIconMenu openDeepShortcutMenu() {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+ return new AppIconMenu(mLauncher, mLauncher.clickAndGet(
+ mObject, "deep_shortcuts_container", LONG_CLICK_EVENT));
+ }
+ }
+
@Override
protected void addExpectedEventsForLongClick() {
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT);