Merge "Enable 3 button nav for taskbar" into sc-v2-dev
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..7d0afe1 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,22 @@
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();
+ onIconAlignmentRatioChanged();
}
@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);
+ mIconAlignmentForResumedState.finishAnimation();
+ mIconAlignmentForGestureState.finishAnimation();
+
mHotseatController.cleanup();
setTaskbarViewVisible(true);
mLauncher.getHotseat().setIconsAlpha(1f);
@@ -100,7 +109,7 @@
@Override
protected boolean isTaskbarTouchable() {
- return !mIsAnimatingToLauncher;
+ return !mIsAnimatingToLauncher && mTargetStateOverride == null;
}
@Override
@@ -128,63 +137,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 59586ab..4142610 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/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index c684543..ac121ab 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -19,12 +19,15 @@
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
+import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.R;
+import com.android.launcher3.testing.TestLogging;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.BaseDragLayer;
import com.android.systemui.shared.system.ViewTreeObserverWrapper;
@@ -128,4 +131,10 @@
mTaskbarBackgroundPaint.setAlpha((int) (alpha * 255));
invalidate();
}
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev);
+ return super.dispatchTouchEvent(ev);
+ }
}
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/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 0ebaea2..82eaecd 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();
}
@@ -1381,11 +1382,17 @@
/**
* Cancels any running animation so that the active target can be overriden by a new swipe
- * handle (in case of quick switch).
+ * handler (in case of quick switch).
*/
private void cancelCurrentAnimation() {
mCanceled = true;
mCurrentShift.cancelAnimation();
+
+ // Cleanup when switching handlers
+ mInputConsumerProxy.unregisterCallback();
+ mActivityInitListener.unregister();
+ ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mActivityRestartListener);
+ mTaskSnapshot = null;
}
private void invalidateHandler() {
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/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 8ed6c14..8b64105 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -337,6 +337,7 @@
private float mFullscreenProgress;
private float mGridProgress;
private float mNonGridScale = 1;
+ private float mDismissScale = 1;
private final FullscreenDrawParams mCurrentFullscreenParams;
private final StatefulActivity mActivity;
@@ -916,9 +917,6 @@
if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
setPivotX(getLayoutDirection() == LAYOUT_DIRECTION_RTL ? 0 : right - left);
setPivotY(mSnapshotView.getTop());
- mSnapshotView.setPivotX(
- getLayoutDirection() == LAYOUT_DIRECTION_RTL ? 0 : right - left);
- mSnapshotView.setPivotY(0);
} else {
setPivotX((right - left) * 0.5f);
setPivotY(mSnapshotView.getTop() + mSnapshotView.getHeight() * 0.5f);
@@ -950,8 +948,8 @@
}
private void setSnapshotScale(float dismissScale) {
- mSnapshotView.setScaleX(dismissScale);
- mSnapshotView.setScaleY(dismissScale);
+ mDismissScale = dismissScale;
+ applyScale();
}
/**
@@ -969,6 +967,7 @@
private void applyScale() {
float scale = 1;
scale *= getPersistentScale();
+ scale *= mDismissScale;
setScaleX(scale);
setScaleY(scale);
}
diff --git a/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java b/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java
index ea7b7f5..f33abb0 100644
--- a/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java
+++ b/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java
@@ -114,6 +114,7 @@
@Test
@NavigationModeSwitch(mode = ZERO_BUTTON)
+ @Suppress // until b/190618549 is fixed
public void testSwipeUpFromApp() throws Exception {
try {
// Go to overview once so that all views are initialized and cached
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_corp_off.xml b/res/drawable/ic_corp_off.xml
index 62a9787..117258e 100644
--- a/res/drawable/ic_corp_off.xml
+++ b/res/drawable/ic_corp_off.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2020 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2020 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.
@@ -16,10 +15,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/textColorHint" >
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?android:attr/textColorHint">
<path
- android:pathData="M22 7.95c.05-1.11-.84-2-1.95-1.95H16V3.95c0-1.11-.84-2-1.95-1.95h-4C8.94 1.95 8 2.84 8 3.95v.32l14 14V7.95zM14 6h-4V4h4v2zm7.54 14.28l-7.56-7.56v.01l-1.7-1.7h.01L7.21 5.95 3.25 1.99 1.99 3.27 4.69 6h-.64c-1.11 0-1.99.86-1.99 1.97l-.01 11.02c0 1.11.89 2.01 2 2.01h15.64l2.05 2.02L23 21.75l-1.46-1.47z"
- android:fillColor="@android:color/white"/>
+ android:fillColor="@android:color/white"
+ android:pathData="M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v1.17L10.83,8L20,8v9.17l1.98,1.98c0,-0.05 0.02,-0.1 0.02,-0.16L22,8c0,-1.11 -0.89,-2 -2,-2zM14,6h-4L10,4h4v2zM19,19L8,8 6,6 2.81,2.81 1.39,4.22 3.3,6.13C2.54,6.41 2.01,7.14 2.01,8L2,19c0,1.11 0.89,2 2,2h14.17l1.61,1.61 1.41,-1.41 -0.37,-0.37L19,19zM4,19L4,8h1.17l11,11L4,19z" />
</vector>
\ No newline at end of file
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/drawable/work_card_btn.xml b/res/drawable/rounded_action_button.xml
similarity index 84%
rename from res/drawable/work_card_btn.xml
rename to res/drawable/rounded_action_button.xml
index 3c93919..0c8755f 100644
--- a/res/drawable/work_card_btn.xml
+++ b/res/drawable/rounded_action_button.xml
@@ -18,10 +18,10 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
- <corners android:radius="@dimen/work_edu_card_margin" />
+ <corners android:radius="@dimen/rounded_button_radius" />
<stroke android:width="1dp" android:color="?androidprv:attr/colorAccentPrimaryVariant" />
<padding
- android:left="@dimen/work_fab_radius"
- android:right="@dimen/work_fab_radius" />
+ android:left="@dimen/rounded_button_padding"
+ android:right="@dimen/rounded_button_padding" />
</shape>
diff --git a/res/layout/work_apps_edu.xml b/res/layout/work_apps_edu.xml
index ffbf962..97feb23 100644
--- a/res/layout/work_apps_edu.xml
+++ b/res/layout/work_apps_edu.xml
@@ -47,7 +47,8 @@
android:textColor="?attr/workProfileOverlayTextColor"
android:text="@string/work_profile_edu_accept"
android:textAlignment="center"
- android:background="@drawable/work_card_btn"
+ android:background="@drawable/rounded_action_button"
+
android:textSize="14sp" />
</LinearLayout>
</com.android.launcher3.allapps.WorkEduCard>
\ No newline at end of file
diff --git a/res/layout/work_apps_paused.xml b/res/layout/work_apps_paused.xml
index 14dcb8c..3819256 100644
--- a/res/layout/work_apps_paused.xml
+++ b/res/layout/work_apps_paused.xml
@@ -48,6 +48,6 @@
android:textColor="?attr/workProfileOverlayTextColor"
android:text="@string/work_apps_enable_btn_text"
android:textAlignment="center"
- android:background="@drawable/work_card_btn"
+ android:background="@drawable/rounded_action_button"
android:textSize="14sp" />
</com.android.launcher3.allapps.WorkPausedCard>
\ No newline at end of file
diff --git a/res/layout/work_mode_fab.xml b/res/layout/work_mode_fab.xml
index 4209192..1771d37 100644
--- a/res/layout/work_mode_fab.xml
+++ b/res/layout/work_mode_fab.xml
@@ -25,7 +25,6 @@
android:background="@drawable/work_apps_toggle_background"
android:drawablePadding="16dp"
android:drawableStart="@drawable/ic_corp_off"
- android:elevation="10dp"
android:layout_marginBottom="@dimen/work_fab_margin"
android:layout_marginEnd="@dimen/work_fab_margin"
android:text="@string/work_apps_pause_btn_text" />
\ No newline at end of file
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..7fda1e5 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -48,7 +48,7 @@
<dimen name="workspace_page_indicator_overlap_workspace">0dp</dimen>
<!-- Drop target bar -->
- <dimen name="dynamic_grid_drop_target_size">48dp</dimen>
+ <dimen name="dynamic_grid_drop_target_size">52dp</dimen>
<dimen name="drop_target_vertical_gap">20dp</dimen>
<!-- App Widget resize frame -->
@@ -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>
@@ -120,11 +120,16 @@
<!-- Floating action button inside work tab to toggle work profile -->
<dimen name="work_fab_height">48dp</dimen>
<dimen name="work_fab_radius">24dp</dimen>
- <dimen name="work_fab_margin">18dp</dimen>
+ <dimen name="work_fab_margin">16dp</dimen>
<dimen name="work_profile_footer_padding">20dp</dimen>
<dimen name="work_profile_footer_text_size">16sp</dimen>
<dimen name="work_edu_card_margin">16dp</dimen>
+ <!-- rounded button shown inside card views, and snack bars -->
+ <dimen name="rounded_button_height">32dp</dimen>
+ <dimen name="rounded_button_radius">16dp</dimen>
+ <dimen name="rounded_button_padding">8dp</dimen>
+
<!-- Widget tray -->
<dimen name="widget_cell_vertical_padding">8dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 9823df3..60c0774 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -190,11 +190,11 @@
<!-- Widgets: -->
<skip />
- <!-- Text to show user in place of a gadget when we can't display it properly -->
- <string name="gadget_error_text">Problem loading widget</string>
+ <!-- Error text that lets a user know that the widget can't load. -->
+ <string name="gadget_error_text">Can\'t load widget</string>
- <!-- Text to show user in place of a gadget when it is not yet initialized. -->
- <string name="gadget_setup_text">Setup</string>
+ <!-- Instructional text to encourage a user to finish setting up the widget. -->
+ <string name="gadget_setup_text">Tap to finish setup</string>
<!-- Text to inform the user that they can't uninstall a system application -->
<string name="uninstall_system_app_text">This is a system app and can\'t be uninstalled.</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 38bc272..8072d0c 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>
@@ -264,9 +266,8 @@
<!-- Drop targets -->
<style name="DropTargetButtonBase" parent="@android:style/TextAppearance.DeviceDefault">
- <item name="android:drawablePadding">7.5dp</item>
- <item name="android:paddingLeft">16dp</item>
- <item name="android:paddingRight">16dp</item>
+ <item name="android:drawablePadding">8dp</item>
+ <item name="android:padding">16dp</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textSize">@dimen/drop_target_text_size</item>
<item name="android:singleLine">true</item>
@@ -276,7 +277,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..13d5570 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
@@ -122,13 +123,9 @@
protected void setDrawable(int resId) {
// 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];
- } else {
- setCompoundDrawablesRelativeWithIntrinsicBounds(0, resId, 0, 0);
- mDrawable = getCompoundDrawablesRelative()[1];
- }
+ mDrawable = getContext().getDrawable(resId).mutate();
+ mDrawable.setBounds(0, 0, mDrawableSize, mDrawableSize);
+ setCompoundDrawablesRelative(mDrawable, null, null, null);
}
public void setDropTargetBar(DropTargetBar dropTargetBar) {
@@ -238,11 +235,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 +246,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 +323,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);
- }
+ setCompoundDrawablesRelative(mDrawable, null, null, null);
}
}
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/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 4579705..9a7ddbc 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -31,7 +31,7 @@
import com.android.launcher3.CellLayout.ContainerType;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import com.android.launcher3.widget.NavigableAppWidgetHostView;
public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon.FolderIconParent {
static final String TAG = "ShortcutAndWidgetContainer";
@@ -104,9 +104,9 @@
public void setupLp(View child) {
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
- if (child instanceof LauncherAppWidgetHostView) {
+ if (child instanceof NavigableAppWidgetHostView) {
DeviceProfile profile = mActivity.getDeviceProfile();
- ((LauncherAppWidgetHostView) child).getWidgetInset(profile, mTempRect);
+ ((NavigableAppWidgetHostView) child).getWidgetInset(profile, mTempRect);
lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
profile.appWidgetScale.x, profile.appWidgetScale.y, mBorderSpacing, mTempRect);
} else {
@@ -129,8 +129,8 @@
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
final DeviceProfile dp = mActivity.getDeviceProfile();
- if (child instanceof LauncherAppWidgetHostView) {
- ((LauncherAppWidgetHostView) child).getWidgetInset(dp, mTempRect);
+ if (child instanceof NavigableAppWidgetHostView) {
+ ((NavigableAppWidgetHostView) child).getWidgetInset(dp, mTempRect);
lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
dp.appWidgetScale.x, dp.appWidgetScale.y, mBorderSpacing, mTempRect);
} else {
@@ -176,16 +176,16 @@
*/
public void layoutChild(View child) {
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
- if (child instanceof LauncherAppWidgetHostView) {
- LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) child;
+ if (child instanceof NavigableAppWidgetHostView) {
+ NavigableAppWidgetHostView nahv = (NavigableAppWidgetHostView) child;
// Scale and center the widget to fit within its cells.
DeviceProfile profile = mActivity.getDeviceProfile();
float scaleX = profile.appWidgetScale.x;
float scaleY = profile.appWidgetScale.y;
- lahv.setScaleToFit(Math.min(scaleX, scaleY));
- lahv.setTranslationForCentering(-(lp.width - (lp.width * scaleX)) / 2.0f,
+ nahv.setScaleToFit(Math.min(scaleX, scaleY));
+ nahv.setTranslationForCentering(-(lp.width - (lp.width * scaleX)) / 2.0f,
-(lp.height - (lp.height * scaleY)) / 2.0f);
}
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 2ef9e3e..3cabc87 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -123,7 +123,8 @@
public static final boolean ATLEAST_R = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R;
- public static final boolean ATLEAST_S = BuildCompat.isAtLeastS();
+ public static final boolean ATLEAST_S = BuildCompat.isAtLeastS()
+ || Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
/**
* Set on a motion event dispatched from the nav bar. See {@link MotionEvent#setEdgeFlags(int)}.
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..8076b27 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);
@@ -132,7 +131,6 @@
private ScrimView mScrimView;
private int mHeaderColor;
-
public AllAppsContainerView(Context context) {
this(context, null);
}
@@ -572,6 +570,10 @@
return mViewPager == null ? getActiveRecyclerView() : mViewPager;
}
+ public int getCurrentPage() {
+ return mViewPager != null ? mViewPager.getCurrentPage() : AdapterHolder.MAIN;
+ }
+
/**
* Handles selection on focused view and returns success
*/
@@ -645,20 +647,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/allapps/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkModeSwitch.java
index 866694f..6d57aa6 100644
--- a/src/com/android/launcher3/allapps/WorkModeSwitch.java
+++ b/src/com/android/launcher3/allapps/WorkModeSwitch.java
@@ -15,9 +15,11 @@
*/
package com.android.launcher3.allapps;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TURN_OFF_WORK_APPS_TAP;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.content.Context;
+import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Build;
import android.os.Process;
@@ -26,12 +28,16 @@
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
+import android.view.WindowInsets;
import android.widget.Button;
+import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.android.launcher3.Insettable;
+import com.android.launcher3.Launcher;
import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.KeyboardInsetAnimationCallback;
import com.android.launcher3.pm.UserCache;
/**
@@ -42,6 +48,10 @@
private Rect mInsets = new Rect();
private boolean mWorkEnabled;
+
+ @Nullable
+ private KeyboardInsetAnimationCallback mKeyboardInsetAnimationCallback;
+
public WorkModeSwitch(Context context) {
this(context, null, 0);
}
@@ -58,6 +68,10 @@
protected void onFinishInflate() {
super.onFinishInflate();
setOnClickListener(this);
+ if (Utilities.ATLEAST_R) {
+ mKeyboardInsetAnimationCallback = new KeyboardInsetAnimationCallback(this);
+ setWindowInsetsAnimationCallback(mKeyboardInsetAnimationCallback);
+ }
}
@Override
@@ -92,6 +106,8 @@
public void onClick(View view) {
if (Utilities.ATLEAST_P) {
setEnabled(false);
+ Launcher.fromContext(getContext()).getStatsLogManager().logger().log(
+ LAUNCHER_TURN_OFF_WORK_APPS_TAP);
UI_HELPER_EXECUTOR.post(() -> setWorkProfileEnabled(getContext(), false));
}
}
@@ -117,4 +133,16 @@
}
return showConfirm;
}
+
+ @Override
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ if (Utilities.ATLEAST_R) {
+ setTranslationY(0);
+ if (insets.isVisible(WindowInsets.Type.ime())) {
+ Insets keyboardInsets = insets.getInsets(WindowInsets.Type.ime());
+ setTranslationY(mInsets.bottom - keyboardInsets.bottom);
+ }
+ }
+ return insets;
+ }
}
diff --git a/src/com/android/launcher3/allapps/WorkPausedCard.java b/src/com/android/launcher3/allapps/WorkPausedCard.java
index 3955a9a..7908b63 100644
--- a/src/com/android/launcher3/allapps/WorkPausedCard.java
+++ b/src/com/android/launcher3/allapps/WorkPausedCard.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.allapps;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TURN_ON_WORK_APPS_TAP;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.content.Context;
@@ -61,6 +62,7 @@
public void onClick(View view) {
if (Utilities.ATLEAST_P) {
setEnabled(false);
+ mLauncher.getStatsLogManager().logger().log(LAUNCHER_TURN_ON_WORK_APPS_TAP);
UI_HELPER_EXECUTOR.post(() -> WorkModeSwitch.setWorkProfileEnabled(getContext(), true));
}
}
diff --git a/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java b/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java
new file mode 100644
index 0000000..ef4ada3
--- /dev/null
+++ b/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.anim;
+
+import android.os.Build;
+import android.view.View;
+import android.view.WindowInsets;
+import android.view.WindowInsetsAnimation;
+
+import androidx.annotation.RequiresApi;
+
+import com.android.launcher3.Utilities;
+
+import java.util.List;
+
+/**
+ * Callback that animates views above the IME
+ */
+@RequiresApi(api = Build.VERSION_CODES.R)
+public class KeyboardInsetAnimationCallback extends WindowInsetsAnimation.Callback {
+ private final View mView;
+
+ private float mInitialTranslation;
+ private float mTerminalTranslation;
+
+ public KeyboardInsetAnimationCallback(View view) {
+ super(DISPATCH_MODE_STOP);
+ mView = view;
+ }
+
+ @Override
+ public void onPrepare(WindowInsetsAnimation animation) {
+ mInitialTranslation = mView.getTranslationY();
+ }
+
+
+ @Override
+ public WindowInsets onProgress(WindowInsets windowInsets, List<WindowInsetsAnimation> list) {
+ if (list.size() == 0) {
+ mView.setTranslationY(mInitialTranslation);
+ return windowInsets;
+ }
+ float progress = list.get(0).getInterpolatedFraction();
+
+ mView.setTranslationY(
+ Utilities.mapRange(progress, mInitialTranslation, mTerminalTranslation));
+
+ return windowInsets;
+ }
+
+ @Override
+ public WindowInsetsAnimation.Bounds onStart(WindowInsetsAnimation animation,
+ WindowInsetsAnimation.Bounds bounds) {
+ mTerminalTranslation = mView.getTranslationY();
+ mView.setTranslationY(mInitialTranslation);
+ return super.onStart(animation, bounds);
+ }
+}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 5e3177a..1c16b1c 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -99,6 +99,9 @@
public static final BooleanFlag ENABLE_DEVICE_SEARCH = new DeviceFlag(
"ENABLE_DEVICE_SEARCH", true, "Allows on device search in all apps");
+ public static final BooleanFlag IME_STICKY_SNACKBAR_EDU = getDebugFlag(
+ "IME_STICKY_SNACKBAR_EDU", true, "Show sticky IME edu in AllApps");
+
public static final BooleanFlag ENABLE_PEOPLE_TILE_PREVIEW = getDebugFlag(
"ENABLE_PEOPLE_TILE_PREVIEW", false,
"Experimental: Shows conversation shortcuts on home screen as search results");
@@ -220,6 +223,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..54967a99 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/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 5dcd75a..22bb56c 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -17,7 +17,6 @@
package com.android.launcher3.folder;
import static android.text.TextUtils.isEmpty;
-import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherState.NORMAL;
@@ -39,7 +38,6 @@
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
-import android.os.Build;
import android.text.InputType;
import android.text.Selection;
import android.text.TextUtils;
@@ -54,15 +52,12 @@
import android.view.View;
import android.view.ViewDebug;
import android.view.WindowInsets;
-import android.view.WindowInsetsAnimation;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.EditorInfo;
import android.widget.TextView;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
import androidx.core.content.res.ResourcesCompat;
import com.android.launcher3.AbstractFloatingView;
@@ -83,6 +78,7 @@
import com.android.launcher3.Workspace.ItemOperator;
import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
import com.android.launcher3.accessibility.FolderAccessibilityHelper;
+import com.android.launcher3.anim.KeyboardInsetAnimationCallback;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragController.DragListener;
@@ -164,9 +160,9 @@
private final Alarm mReorderAlarm = new Alarm();
private final Alarm mOnExitAlarm = new Alarm();
private final Alarm mOnScrollHintAlarm = new Alarm();
- @Thunk final Alarm mScrollPauseAlarm = new Alarm();
+ final Alarm mScrollPauseAlarm = new Alarm();
- @Thunk final ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
+ final ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
private AnimatorSet mCurrentAnimator;
private boolean mIsAnimatingClosed = false;
@@ -182,9 +178,11 @@
private CharSequence mFromTitle;
private FromState mFromLabelState;
- @Thunk FolderIcon mFolderIcon;
+ @Thunk
+ FolderIcon mFolderIcon;
- @Thunk FolderPagedView mContent;
+ @Thunk
+ FolderPagedView mContent;
public FolderNameEditText mFolderName;
private PageIndicatorDots mPageIndicator;
@@ -192,7 +190,8 @@
private int mFooterHeight;
// Cell ranks used for drag and drop
- @Thunk int mTargetRank, mPrevTargetRank, mEmptyCellRank;
+ @Thunk
+ int mTargetRank, mPrevTargetRank, mEmptyCellRank;
private Path mClipPath;
@@ -203,7 +202,8 @@
@ViewDebug.IntToString(from = STATE_ANIMATING, to = "STATE_ANIMATING"),
@ViewDebug.IntToString(from = STATE_OPEN, to = "STATE_OPEN"),
})
- @Thunk int mState = STATE_NONE;
+ @Thunk
+ int mState = STATE_NONE;
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mRearrangeOnClose = false;
boolean mItemsInvalidated = false;
@@ -221,12 +221,15 @@
// Folder scrolling
private int mScrollAreaOffset;
- @Thunk int mScrollHintDir = SCROLL_NONE;
- @Thunk int mCurrentScrollDir = SCROLL_NONE;
+ @Thunk
+ int mScrollHintDir = SCROLL_NONE;
+ @Thunk
+ int mCurrentScrollDir = SCROLL_NONE;
private StatsLogManager mStatsLogManager;
- @Nullable private FolderWindowInsetsAnimationCallback mFolderWindowInsetsAnimationCallback;
+ @Nullable
+ private KeyboardInsetAnimationCallback mKeyboardInsetAnimationCallback;
private GradientDrawable mBackground;
@@ -234,7 +237,7 @@
* Used to inflate the Workspace from XML.
*
* @param context The application's context.
- * @param attrs The attributes set containing the Workspace's customization values.
+ * @param attrs The attributes set containing the Workspace's customization values.
*/
public Folder(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -246,7 +249,8 @@
mStatsLogManager = StatsLogManager.newInstance(context);
// We need this view to be focusable in touch mode so that when text editing of the folder
// name is complete, we have something to focus on, thus hiding the cursor and giving
- // reliable behavior when clicking the text field (since it will always gain focus on click).
+ // reliable behavior when clicking the text field (since it will always gain focus on
+ // click).
setFocusableInTouchMode(true);
}
@@ -286,10 +290,8 @@
mFooterHeight = getResources().getDimensionPixelSize(R.dimen.folder_label_height);
if (Utilities.ATLEAST_R) {
- mFolderWindowInsetsAnimationCallback =
- new FolderWindowInsetsAnimationCallback(DISPATCH_MODE_STOP, this);
-
- setWindowInsetsAnimationCallback(mFolderWindowInsetsAnimationCallback);
+ mKeyboardInsetAnimationCallback = new KeyboardInsetAnimationCallback(this);
+ setWindowInsetsAnimationCallback(mKeyboardInsetAnimationCallback);
}
}
@@ -311,14 +313,14 @@
if (options.isAccessibleDrag) {
mDragController.addDragListener(new AccessibleDragListenerAdapter(
mContent, FolderAccessibilityHelper::new) {
- @Override
- protected void enableAccessibleDrag(boolean enable) {
- super.enableAccessibleDrag(enable);
- mFooter.setImportantForAccessibility(enable
- ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
- : IMPORTANT_FOR_ACCESSIBILITY_AUTO);
- }
- });
+ @Override
+ protected void enableAccessibleDrag(boolean enable) {
+ super.enableAccessibleDrag(enable);
+ mFooter.setImportantForAccessibility(enable
+ ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
+ : IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+ }
+ });
}
mLauncherDelegate.beginDragShared(v, this, options);
@@ -539,7 +541,6 @@
*
* @param activityContext The main ActivityContext in which to inflate this Folder. It must also
* be an instance or ContextWrapper around the Launcher activity context.
- *
* @return A new UserFolder.
*/
@SuppressLint("InflateParams")
@@ -677,6 +678,7 @@
mFolderIcon.setIconVisible(false);
mFolderIcon.drawLeaveBehindIfExists();
}
+
@Override
public void onAnimationEnd(Animator animation) {
mState = STATE_OPEN;
@@ -691,7 +693,7 @@
int footerWidth = mContent.getDesiredWidth()
- mFooter.getPaddingLeft() - mFooter.getPaddingRight();
- float textWidth = mFolderName.getPaint().measureText(mFolderName.getText().toString());
+ float textWidth = mFolderName.getPaint().measureText(mFolderName.getText().toString());
float translation = (footerWidth - textWidth) / 2;
mFolderName.setTranslationX(mContent.mIsRtl ? -translation : translation);
mPageIndicator.prepareEntryAnimation();
@@ -705,9 +707,9 @@
@Override
public void onAnimationEnd(Animator animation) {
mFolderName.animate().setDuration(FOLDER_NAME_ANIMATION_DURATION)
- .translationX(0)
- .setInterpolator(AnimationUtils.loadInterpolator(
- getContext(), android.R.interpolator.fast_out_slow_in));
+ .translationX(0)
+ .setInterpolator(AnimationUtils.loadInterpolator(
+ getContext(), android.R.interpolator.fast_out_slow_in));
mPageIndicator.playEntryAnimation();
if (updateAnimationFlag) {
@@ -794,8 +796,8 @@
@Override
public void onAnimationEnd(Animator animation) {
- if (Utilities.ATLEAST_R && mFolderWindowInsetsAnimationCallback != null) {
- setWindowInsetsAnimationCallback(mFolderWindowInsetsAnimationCallback);
+ if (Utilities.ATLEAST_R && mKeyboardInsetAnimationCallback != null) {
+ setWindowInsetsAnimationCallback(mKeyboardInsetAnimationCallback);
}
closeComplete(true);
announceAccessibilityChanges();
@@ -1109,7 +1111,7 @@
sTempRect.set(mActivityContext.getFolderBoundingBox());
int left = Utilities.boundToRange(centeredLeft, sTempRect.left, sTempRect.right - width);
int top = Utilities.boundToRange(centeredTop, sTempRect.top, sTempRect.bottom - height);
- int[] inOutPosition = new int[] {left, top};
+ int[] inOutPosition = new int[]{left, top};
mActivityContext.updateOpenFolderPosition(inOutPosition, sTempRect, width, height);
left = inOutPosition[0];
top = inOutPosition[1];
@@ -1193,7 +1195,7 @@
return mInfo.contents.size();
}
- @Thunk void replaceFolderWithFinalItem() {
+ void replaceFolderWithFinalItem() {
mLauncherDelegate.replaceFolderWithFinalItem(this);
mDestroyed = true;
}
@@ -1352,6 +1354,7 @@
v.setVisibility(INVISIBLE);
}
}
+
public void showItem(WorkspaceItemInfo info) {
View v = getViewForInfo(info);
if (v != null) {
@@ -1646,55 +1649,4 @@
return windowBottomPx - folderBottomPx;
}
-
- /** Callback that animates a folder sliding up above the ime. */
- @RequiresApi(api = Build.VERSION_CODES.R)
- private static class FolderWindowInsetsAnimationCallback
- extends WindowInsetsAnimation.Callback {
-
- private final Folder mFolder;
- float mFolderTranslationStart;
- float mFolderTranslationEnd;
-
- FolderWindowInsetsAnimationCallback(int dispatchMode, Folder folder) {
- super(dispatchMode);
-
- mFolder = folder;
- }
-
- @Override
- public void onPrepare(@NonNull WindowInsetsAnimation animation) {
- mFolderTranslationStart = mFolder.getTranslationY();
- }
-
- @NonNull
- @Override
- public WindowInsetsAnimation.Bounds onStart(
- @NonNull WindowInsetsAnimation animation,
- @NonNull WindowInsetsAnimation.Bounds bounds) {
- mFolderTranslationEnd = mFolder.getTranslationY();
-
- mFolder.setTranslationY(mFolderTranslationStart);
-
- return super.onStart(animation, bounds);
- }
-
- @NonNull
- @Override
- public WindowInsets onProgress(@NonNull WindowInsets windowInsets,
- @NonNull List<WindowInsetsAnimation> list) {
- if (list.size() == 0) {
- mFolder.setTranslationY(0);
-
- return windowInsets;
- }
- float progress = list.get(0).getInterpolatedFraction();
-
- mFolder.setTranslationY(
- Utilities.mapRange(progress, mFolderTranslationStart, mFolderTranslationEnd));
-
- return windowInsets;
- }
-
- }
}
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/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 952b850..c6add31 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -84,6 +84,7 @@
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.widget.NavigableAppWidgetHostView;
import com.android.launcher3.widget.custom.CustomWidgetManager;
import java.util.ArrayList;
@@ -353,7 +354,12 @@
private void inflateAndAddWidgets(
LauncherAppWidgetInfo info, LauncherAppWidgetProviderInfo providerInfo) {
- AppWidgetHostView view = new AppWidgetHostView(mContext);
+ AppWidgetHostView view = new NavigableAppWidgetHostView(this) {
+ @Override
+ protected boolean shouldAllowDirectClick() {
+ return false;
+ }
+ };
view.setAppWidget(-1, providerInfo);
view.updateAppWidget(null);
view.setTag(info);
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 345a2ac..ddff338 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -479,7 +479,13 @@
LAUNCHER_THEMED_ICON_ENABLED(836),
@UiEvent(doc = "User disabled themed icons option in wallpaper & style settings.")
- LAUNCHER_THEMED_ICON_DISABLED(837)
+ LAUNCHER_THEMED_ICON_DISABLED(837),
+
+ @UiEvent(doc = "User tapped on 'Turn on work apps' button in all apps window.")
+ LAUNCHER_TURN_ON_WORK_APPS_TAP(838),
+
+ @UiEvent(doc = "User tapped on 'Turn off work apps' button in all apps window.")
+ LAUNCHER_TURN_OFF_WORK_APPS_TAP(839)
;
// ADD MORE
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 7bfa3ef..82b0f7c 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -29,6 +29,7 @@
import android.os.UserManager;
import android.util.Log;
+import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
@@ -123,6 +124,14 @@
activitiesLists.put(
packages[i], appsList.updatePackage(context, packages[i], mUser));
app.getWidgetCache().removePackage(packages[i], mUser);
+
+ // The update may have changed which shortcuts/widgets are available.
+ // Refresh the widgets for the package if we have an activity running.
+ Launcher launcher = Launcher.ACTIVITY_TRACKER.getCreatedActivity();
+ if (launcher != null) {
+ launcher.refreshAndBindWidgetsForPackageUser(
+ new PackageUserKey(packages[i], mUser));
+ }
}
}
// Since package was just updated, the target must be available now.
@@ -212,7 +221,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 +235,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/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/util/OnboardingPrefs.java b/src/com/android/launcher3/util/OnboardingPrefs.java
index 2e279fa..c395d6c 100644
--- a/src/com/android/launcher3/util/OnboardingPrefs.java
+++ b/src/com/android/launcher3/util/OnboardingPrefs.java
@@ -37,6 +37,7 @@
public static final String HOTSEAT_DISCOVERY_TIP_COUNT = "launcher.hotseat_discovery_tip_count";
public static final String HOTSEAT_LONGPRESS_TIP_SEEN = "launcher.hotseat_longpress_tip_seen";
public static final String SEARCH_EDU_SEEN = "launcher.search_edu";
+ public static final String SEARCH_SNACKBAR_COUNT = "launcher.keyboard_snackbar_count";
/**
* Events that either have happened or have not (booleans).
@@ -47,23 +48,28 @@
SEARCH_EDU_SEEN
})
@Retention(RetentionPolicy.SOURCE)
- public @interface EventBoolKey {}
+ public @interface EventBoolKey {
+ }
/**
* Events that occur multiple times, which we count up to a max defined in {@link #MAX_COUNTS}.
*/
@StringDef(value = {
HOME_BOUNCE_COUNT,
- HOTSEAT_DISCOVERY_TIP_COUNT
+ HOTSEAT_DISCOVERY_TIP_COUNT,
+ SEARCH_SNACKBAR_COUNT
})
@Retention(RetentionPolicy.SOURCE)
- public @interface EventCountKey {}
+ public @interface EventCountKey {
+ }
private static final Map<String, Integer> MAX_COUNTS;
+
static {
Map<String, Integer> maxCounts = new ArrayMap<>(4);
maxCounts.put(HOME_BOUNCE_COUNT, 3);
maxCounts.put(HOTSEAT_DISCOVERY_TIP_COUNT, 5);
+ maxCounts.put(SEARCH_SNACKBAR_COUNT, 3);
MAX_COUNTS = Collections.unmodifiableMap(maxCounts);
}
@@ -103,6 +109,7 @@
/**
* Add 1 to the given event count, if we haven't already reached the max count.
+ *
* @return Whether we have now reached the max count.
*/
public boolean incrementEventCount(@EventCountKey String eventKey) {
diff --git a/src/com/android/launcher3/util/UiThreadHelper.java b/src/com/android/launcher3/util/UiThreadHelper.java
index cb721e6..0f40179 100644
--- a/src/com/android/launcher3/util/UiThreadHelper.java
+++ b/src/com/android/launcher3/util/UiThreadHelper.java
@@ -21,6 +21,7 @@
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -42,15 +43,30 @@
private static final int MSG_HIDE_KEYBOARD = 1;
private static final int MSG_SET_ORIENTATION = 2;
private static final int MSG_RUN_COMMAND = 3;
+ private static final String STATS_LOGGER_KEY = "STATS_LOGGER_KEY";
@SuppressLint("NewApi")
public static void hideKeyboardAsync(ActivityContext activityContext, IBinder token) {
View root = activityContext.getDragLayer();
- Message.obtain(HANDLER.get(root.getContext()),
- MSG_HIDE_KEYBOARD, token).sendToTarget();
- Launcher.cast(activityContext).getStatsLogManager().logger().log(
- LAUNCHER_ALLAPPS_KEYBOARD_CLOSED);
+ // Since the launcher context cannot be accessed directly from callback, adding secondary
+ // message to log keyboard close event asynchronously.
+ Bundle mHideKeyboardLoggerMsg = new Bundle();
+ mHideKeyboardLoggerMsg.putParcelable(
+ STATS_LOGGER_KEY,
+ Message.obtain(
+ HANDLER.get(root.getContext()),
+ () -> Launcher.cast(activityContext)
+ .getStatsLogManager()
+ .logger()
+ .log(LAUNCHER_ALLAPPS_KEYBOARD_CLOSED)
+ )
+ );
+
+ Message mHideKeyboardMsg = Message.obtain(HANDLER.get(root.getContext()), MSG_HIDE_KEYBOARD,
+ token);
+ mHideKeyboardMsg.setData(mHideKeyboardLoggerMsg);
+ mHideKeyboardMsg.sendToTarget();
}
public static void setOrientationAsync(Activity activity, int orientation) {
@@ -81,7 +97,11 @@
public boolean handleMessage(Message message) {
switch (message.what) {
case MSG_HIDE_KEYBOARD:
- mIMM.hideSoftInputFromWindow((IBinder) message.obj, 0);
+ if (mIMM.hideSoftInputFromWindow((IBinder) message.obj, 0)) {
+ // log keyboard close event only when keyboard is actually closed
+ ((Message) message.getData().getParcelable(STATS_LOGGER_KEY))
+ .sendToTarget();
+ }
return true;
case MSG_SET_ORIENTATION:
((Activity) message.obj).setRequestedOrientation(message.arg1);
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/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java b/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java
index 6163b51..d12fe74 100644
--- a/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java
@@ -26,7 +26,6 @@
import android.view.ViewDebug;
import android.view.ViewGroup;
-import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Reorderable;
import com.android.launcher3.dragndrop.DraggableView;
@@ -59,7 +58,7 @@
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mChildrenFocused;
- protected final BaseActivity mActivity;
+ protected final ActivityContext mActivity;
public NavigableAppWidgetHostView(Context context) {
super(context);
diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
index 3308eec..47a8914 100644
--- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
@@ -97,9 +97,9 @@
@Override
public void updateAppWidget(RemoteViews remoteViews) {
- super.updateAppWidget(remoteViews);
WidgetManagerHelper widgetManagerHelper = new WidgetManagerHelper(getContext());
if (widgetManagerHelper.isAppWidgetRestored(mInfo.appWidgetId)) {
+ super.updateAppWidget(remoteViews);
reInflate();
}
}
@@ -149,7 +149,7 @@
// The view displays three modes,
// 1) App icon in the center
// 2) Preload icon in the center
- // 3) Setup icon in the center and app icon in the top right corner.
+ // 3) App icon in the center with a setup icon on the top left corner.
if (mDisabledForSafeMode) {
FastBitmapDrawable disabledIcon = info.newIcon(getContext());
disabledIcon.setIsDisabled(true);
diff --git a/src/com/android/launcher3/widget/util/WidgetSizes.java b/src/com/android/launcher3/widget/util/WidgetSizes.java
index 5c8ea72..fcc0dde 100644
--- a/src/com/android/launcher3/widget/util/WidgetSizes.java
+++ b/src/com/android/launcher3/widget/util/WidgetSizes.java
@@ -99,11 +99,13 @@
*/
public static Bundle getWidgetSizeOptions(Context context, ComponentName provider, int spanX,
int spanY) {
+ boolean shouldInsetWidgets =
+ LauncherAppState.getIDP(context).getDeviceProfile(context).shouldInsetWidgets();
ArrayList<SizeF> sizes = getWidgetSizes(context, spanX, spanY);
Rect padding = getDefaultPaddingForWidget(context, provider, null);
float density = context.getResources().getDisplayMetrics().density;
- float xPaddingDips = (padding.left + padding.right) / density;
- float yPaddingDips = (padding.top + padding.bottom) / density;
+ float xPaddingDips = shouldInsetWidgets ? (padding.left + padding.right) / density : 0;
+ float yPaddingDips = shouldInsetWidgets ? (padding.top + padding.bottom) / density : 0;
ArrayList<SizeF> paddedSizes = sizes.stream()
.map(size -> new SizeF(
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
index 51c5b12..a66b031 100644
--- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
+++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
@@ -15,6 +15,7 @@
import android.util.Log;
import androidx.annotation.Nullable;
+import androidx.collection.ArrayMap;
import com.android.launcher3.AppFilter;
import com.android.launcher3.InvariantDeviceProfile;
@@ -37,6 +38,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -158,34 +160,29 @@
Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + rawWidgetsShortcuts.size());
}
- // Temporary list for {@link PackageItemInfos} to avoid having to go through
+ // Temporary cache for {@link PackageItemInfos} to avoid having to go through
// {@link mPackageItemInfos} to locate the key to be used for {@link #mWidgetsList}
- HashMap<WidgetPackageOrCategoryKey, PackageItemInfo> tmpPackageItemInfos = new HashMap<>();
+ PackageItemInfoCache packageItemInfoCache = new PackageItemInfoCache();
- // Clear the lists only if this is an update on all widgets and shortcuts. If packageUser
- // isn't null, only updates the shortcuts and widgets for the app represented in
- // packageUser.
if (packageUser == null) {
+ // Clear the list if this is an update on all widgets and shortcuts.
mWidgetsList.clear();
+ } else {
+ // Otherwise, only clear the widgets and shortcuts for the changed package.
+ mWidgetsList.remove(
+ packageItemInfoCache.getOrCreate(new WidgetPackageOrCategoryKey(packageUser)));
}
+
// add and update.
mWidgetsList.putAll(rawWidgetsShortcuts.stream()
.filter(new WidgetValidityCheck(app))
- .collect(Collectors.groupingBy(item -> {
- WidgetPackageOrCategoryKey packageUserKey = getWidgetPackageOrCategoryKey(item);
- PackageItemInfo pInfo = tmpPackageItemInfos.get(packageUserKey);
- if (pInfo == null) {
- pInfo = new PackageItemInfo(item.componentName.getPackageName(),
- packageUserKey.mCategory);
- pInfo.user = item.user;
- tmpPackageItemInfos.put(packageUserKey, pInfo);
- }
- return pInfo;
- })));
+ .collect(Collectors.groupingBy(item ->
+ packageItemInfoCache.getOrCreate(getWidgetPackageOrCategoryKey(item))
+ )));
// Update each package entry
IconCache iconCache = app.getIconCache();
- for (PackageItemInfo p : tmpPackageItemInfos.values()) {
+ for (PackageItemInfo p : packageItemInfoCache.values()) {
iconCache.getTitleAndIconForApp(p, true /* userLowResIcon */);
}
}
@@ -289,6 +286,10 @@
public final UserHandle mUser;
private final int mHashCode;
+ WidgetPackageOrCategoryKey(PackageUserKey key) {
+ this(key.mPackageName, key.mUser);
+ }
+
WidgetPackageOrCategoryKey(String packageName, UserHandle user) {
this(packageName, PackageItemInfo.NO_CATEGORY, user);
}
@@ -310,4 +311,22 @@
return mHashCode;
}
}
+
+ private static final class PackageItemInfoCache {
+ private final Map<WidgetPackageOrCategoryKey, PackageItemInfo> mMap = new ArrayMap<>();
+
+ PackageItemInfo getOrCreate(WidgetPackageOrCategoryKey key) {
+ PackageItemInfo pInfo = mMap.get(key);
+ if (pInfo == null) {
+ pInfo = new PackageItemInfo(key.mPackage, key.mCategory);
+ pInfo.user = key.mUser;
+ mMap.put(key, pInfo);
+ }
+ return pInfo;
+ }
+
+ Collection<PackageItemInfo> values() {
+ return mMap.values();
+ }
+ }
}
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index f5c1efa..96e8222 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -39,6 +39,7 @@
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
+import android.os.DeadObjectException;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -269,6 +270,9 @@
try (ContentProviderClient client = getContext().getContentResolver()
.acquireContentProviderClient(mTestProviderUri)) {
return client.call(request, null, null);
+ } catch (DeadObjectException e) {
+ fail("Launcher crashed");
+ return null;
} catch (RemoteException e) {
throw new RuntimeException(e);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index 51e331d..99d9889 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -185,8 +185,12 @@
targetAppSelector);
if (headerTitle != null) {
// If we find the header and it has not been expanded, let's click it to see the
- // widgets list.
- if (!hasHeaderExpanded) {
+ // widgets list. Note that we wait until the header is out of the gesture region at
+ // the bottom of the screen, because tapping there in Launcher3 causes NexusLauncher
+ // to briefly appear to handle the gesture, which can break our test.
+ boolean isHeaderOutOfGestureRegion = headerTitle.getVisibleCenter().y
+ < mLauncher.getBottomGestureStartOnScreen();
+ if (!hasHeaderExpanded && isHeaderOutOfGestureRegion) {
log("Header has not been expanded. Click to expand.");
hasHeaderExpanded = true;
mLauncher.clickLauncherObject(headerTitle);