Merge "Correctly map the drag view position to the Workspace" into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 0df6c36..be8ebbb 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -332,3 +332,10 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "letter_fast_scroller"
+ namespace: "launcher"
+ description: "Change fast scroller to a lettered list"
+ bug: "358673724"
+}
diff --git a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
index 189deda..f7da34a 100644
--- a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
+++ b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
@@ -30,7 +30,7 @@
import com.android.quickstep.SystemUiProxy
import com.android.quickstep.TaskViewUtils
import com.android.quickstep.views.DesktopTaskView
-import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource
+import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource
import java.util.function.Consumer
/** Manage recents related operations with desktop tasks */
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index ff1ea98..221504d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -56,7 +56,6 @@
import com.android.launcher3.util.Executors
import java.io.PrintWriter
import kotlin.jvm.optionals.getOrNull
-import kotlin.math.max
/** Handles the insets that Taskbar provides to underlying apps and the IME. */
class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTaskbarController {
@@ -106,7 +105,8 @@
}
fun onTaskbarOrBubblebarWindowHeightOrInsetsChanged() {
- val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps
+ val taskbarStashController = controllers.taskbarStashController
+ val tappableHeight = taskbarStashController.tappableHeightToReportToApps
// We only report tappableElement height for unstashed, persistent taskbar,
// which is also when we draw the rounded corners above taskbar.
val insetsRoundedCornerFlag =
@@ -133,7 +133,7 @@
}
val bubbleControllers = controllers.bubbleControllers.getOrNull()
- val taskbarTouchableHeight = controllers.taskbarStashController.touchableHeight
+ val taskbarTouchableHeight = taskbarStashController.touchableHeight
val bubblesTouchableHeight =
bubbleControllers?.bubbleStashController?.getTouchableHeight() ?: 0
// reset touch bounds
@@ -147,12 +147,10 @@
defaultTouchableRegion.addBoundsToRegion(bubbleBarViewController.bubbleBarBounds)
}
}
- val taskbarUIController = controllers.uiController as? LauncherTaskbarUIController
- if (taskbarUIController?.isOnHome != true) {
- // only add the bars touch region if not on home
- val touchableHeight = max(taskbarTouchableHeight, bubblesTouchableHeight)
+ if (taskbarStashController.isInApp || taskbarStashController.isInOverview) {
+ // only add the taskbar touch region if not on home
val bottom = windowLayoutParams.height
- val top = bottom - touchableHeight
+ val top = bottom - taskbarTouchableHeight
val right = context.deviceProfile.widthPx
defaultTouchableRegion.addBoundsToRegion(Rect(/* left= */ 0, top, right, bottom))
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index b48ed60..56f88d1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -424,6 +424,11 @@
return hasAnyFlag(FLAGS_IN_APP);
}
+ /** Returns whether the taskbar is currently in overview screen. */
+ public boolean isInOverview() {
+ return hasAnyFlag(FLAG_IN_OVERVIEW);
+ }
+
/**
* Returns the height that taskbar will be touchable.
*/
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index d3b918e..aef21aa 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -150,6 +150,7 @@
private Runnable mOnControllerPreCreateCallback = NO_OP;
// Stored here as signals to determine if the mIconAlignController needs to be recreated.
+ private boolean mIsIconAlignedWithHotseat;
private boolean mIsHotseatIconOnTopWhenAligned;
private boolean mIsStashed;
@@ -687,15 +688,17 @@
mIconAlignControllerLazy = null;
return;
}
-
boolean isHotseatIconOnTopWhenAligned =
mControllers.uiController.isHotseatIconOnTopWhenAligned();
+ boolean isIconAlignedWithHotseat = mControllers.uiController.isIconAlignedWithHotseat();
boolean isStashed = mControllers.taskbarStashController.isStashed();
- // Re-create animation when mIsHotseatIconOnTopWhenAligned or mIsStashed changes.
+ // Re-create animation when any of these values change.
if (mIconAlignControllerLazy == null
|| mIsHotseatIconOnTopWhenAligned != isHotseatIconOnTopWhenAligned
+ || mIsIconAlignedWithHotseat != isIconAlignedWithHotseat
|| mIsStashed != isStashed) {
mIsHotseatIconOnTopWhenAligned = isHotseatIconOnTopWhenAligned;
+ mIsIconAlignedWithHotseat = isIconAlignedWithHotseat;
mIsStashed = isStashed;
mIconAlignControllerLazy = createIconAlignmentController(launcherDp);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index a36d5f0..cdd3e13 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -496,6 +496,11 @@
() -> mBubbleBarViewController.animateBubbleBarLocation(bubbleBarLocation));
}
+ /** Notifies WMShell to show the expanded view. */
+ void showExpandedView() {
+ mSystemUiProxy.showExpandedView();
+ }
+
//
// Loading data for the bubbles
//
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 1f0851f..c458936 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -244,7 +244,7 @@
if (mIsBarExpanded && mSelectedBubbleView != null) {
mSelectedBubbleView.markSeen();
}
- updateWidth();
+ updateLayoutParams();
},
/* onUpdate= */ animator -> {
updateBubblesLayoutProperties(mBubbleBarLocation);
@@ -733,7 +733,7 @@
@Override
public void onAnimationEnd() {
- updateWidth();
+ updateLayoutParams();
mBubbleAnimator = null;
}
@@ -791,7 +791,7 @@
@Override
public void onAnimationEnd() {
removeView(removedBubble);
- updateWidth();
+ updateLayoutParams();
mBubbleAnimator = null;
if (onEndRunnable != null) {
onEndRunnable.run();
@@ -823,7 +823,7 @@
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
super.addView(child, index, params);
- updateWidth();
+ updateLayoutParams();
updateBubbleAccessibilityStates();
updateContentDescription();
}
@@ -887,7 +887,7 @@
mSelectedBubbleView = null;
mBubbleBarBackground.showArrow(false);
}
- updateWidth();
+ updateLayoutParams();
updateBubbleAccessibilityStates();
updateContentDescription();
mDismissedByDragBubbleView = null;
@@ -937,12 +937,6 @@
}
}
- private void updateWidth() {
- LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
- lp.width = (int) (mIsBarExpanded ? expandedWidth() : collapsedWidth());
- setLayoutParams(lp);
- }
-
private void updateLayoutParams() {
LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
lp.height = (int) getBubbleBarExpandedHeight();
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 1d74b28..5c1a546 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -119,7 +119,8 @@
mBubbleDragController = bubbleControllers.bubbleDragController;
mTaskbarStashController = controllers.taskbarStashController;
mTaskbarInsetsController = controllers.taskbarInsetsController;
- mBubbleBarViewAnimator = new BubbleBarViewAnimator(mBarView, mBubbleStashController);
+ mBubbleBarViewAnimator = new BubbleBarViewAnimator(
+ mBarView, mBubbleStashController, mBubbleBarController::showExpandedView);
mTaskbarViewPropertiesProvider = taskbarViewPropertiesProvider;
onBubbleBarConfigurationChanged(/* animate= */ false);
mActivity.addOnDeviceProfileChangeListener(
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
index 2ed88d8..99c50f2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
@@ -36,6 +36,7 @@
constructor(
private val bubbleBarView: BubbleBarView,
private val bubbleStashController: BubbleStashController,
+ private val onExpanded: Runnable,
private val scheduler: Scheduler = HandlerScheduler(bubbleBarView)
) {
@@ -406,7 +407,7 @@
springBackAnimation.spring(DynamicAnimation.TRANSLATION_Y, ty)
springBackAnimation.addEndListener { _, _, _, _, _, _, _ ->
if (animatingBubble?.expand == true) {
- bubbleBarView.isExpanded = true
+ expandBubbleBar()
cancelHideAnimation()
} else {
moveToState(AnimatingBubble.State.IN)
@@ -417,7 +418,7 @@
ObjectAnimator.ofFloat(bubbleBarView, View.TRANSLATION_Y, ty - bubbleBarBounceDistanceInPx)
.withDuration(BUBBLE_BAR_BOUNCE_ANIMATION_DURATION_MS)
.withEndAction {
- if (animatingBubble?.expand == true) bubbleBarView.isExpanded = true
+ if (animatingBubble?.expand == true) expandBubbleBar()
springBackAnimation.start()
}
.start()
@@ -451,7 +452,7 @@
this.animatingBubble = animatingBubble.copy(expand = true)
// if we're fully in and waiting to hide, cancel the hide animation and clean up
if (animatingBubble.state == AnimatingBubble.State.IN) {
- bubbleBarView.isExpanded = true
+ expandBubbleBar()
cancelHideAnimation()
}
}
@@ -489,6 +490,11 @@
this.animatingBubble = animatingBubble.copy(state = state)
}
+ private fun expandBubbleBar() {
+ bubbleBarView.isExpanded = true
+ onExpanded.run()
+ }
+
/**
* Tracks the translation Y of the bubble bar during the animation. When the bubble bar expands
* as part of the animation, the expansion should start after the bubble bar reaches the peak
@@ -510,7 +516,7 @@
}
val expand = animatingBubble?.expand ?: false
if (reachedPeak && expand && !startedExpanding) {
- bubbleBarView.isExpanded = true
+ expandBubbleBar()
startedExpanding = true
}
previousTy = ty
diff --git a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
index fbc0d14..94f4920 100644
--- a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
+++ b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
@@ -24,8 +24,8 @@
import com.android.quickstep.views.RecentsView
import com.android.quickstep.views.RecentsViewContainer
import com.android.quickstep.views.TaskContainer
-import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource
/** A menu item, "Desktop", that allows the user to bring the current app into Desktop Windowing. */
class DesktopSystemShortcut(
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index e66da52..05bef35 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -20,7 +20,7 @@
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.util.SplitScreenUtils.convertShellSplitBoundsToLauncher;
-import static com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_FREEFORM;
+import static com.android.wm.shell.shared.GroupedRecentTaskInfo.TYPE_FREEFORM;
import android.app.ActivityManager;
import android.app.KeyguardManager;
@@ -40,8 +40,8 @@
import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
import com.android.wm.shell.recents.IRecentTasksListener;
+import com.android.wm.shell.shared.GroupedRecentTaskInfo;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
-import com.android.wm.shell.util.GroupedRecentTaskInfo;
import java.io.PrintWriter;
import java.util.ArrayList;
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index 3dec381..1be60de 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -17,7 +17,7 @@
package com.android.quickstep;
import static com.android.quickstep.util.SplitScreenUtils.convertShellSplitBoundsToLauncher;
-import static com.android.wm.shell.util.SplitBounds.KEY_EXTRA_SPLIT_BOUNDS;
+import static com.android.wm.shell.shared.split.SplitBounds.KEY_EXTRA_SPLIT_BOUNDS;
import android.app.WindowConfiguration;
import android.content.Context;
@@ -33,7 +33,7 @@
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
-import com.android.wm.shell.util.SplitBounds;
+import com.android.wm.shell.shared.split.SplitBounds;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index ead5b7b..4392255 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -82,7 +82,6 @@
import com.android.wm.shell.bubbles.IBubbles;
import com.android.wm.shell.bubbles.IBubblesListener;
import com.android.wm.shell.common.bubbles.BubbleBarLocation;
-import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource;
import com.android.wm.shell.common.pip.IPip;
import com.android.wm.shell.common.pip.IPipAnimationListener;
import com.android.wm.shell.desktopmode.IDesktopMode;
@@ -91,16 +90,18 @@
import com.android.wm.shell.onehanded.IOneHanded;
import com.android.wm.shell.recents.IRecentTasks;
import com.android.wm.shell.recents.IRecentTasksListener;
+import com.android.wm.shell.shared.GroupedRecentTaskInfo;
import com.android.wm.shell.shared.IShellTransitions;
import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
+import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
+import com.android.wm.shell.shared.split.SplitBounds;
import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
import com.android.wm.shell.splitscreen.ISplitScreen;
import com.android.wm.shell.splitscreen.ISplitScreenListener;
import com.android.wm.shell.splitscreen.ISplitSelectListener;
import com.android.wm.shell.startingsurface.IStartingWindow;
import com.android.wm.shell.startingsurface.IStartingWindowListener;
-import com.android.wm.shell.util.GroupedRecentTaskInfo;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -934,6 +935,17 @@
}
}
+ /** Tells SysUI to show the expanded view. */
+ public void showExpandedView() {
+ try {
+ if (mBubbles != null) {
+ mBubbles.showExpandedView();
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to call showExpandedView");
+ }
+ }
+
//
// Splitscreen
//
@@ -1517,7 +1529,7 @@
// Aidl bundles need to explicitly set class loader
// https://developer.android.com/guide/components/aidl#Bundles
if (extras != null) {
- extras.setClassLoader(getClass().getClassLoader());
+ extras.setClassLoader(SplitBounds.class.getClassLoader());
}
listener.onAnimationStart(new RecentsAnimationControllerCompat(controller), apps,
wallpapers, homeContentInsets, minimizedHomeBounds, extras);
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index 3ca7191..14f47d1 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -277,7 +277,7 @@
}
private void endRemoteAnimation() {
- if (mRecentsAnimationController != null) {
+ if (!mHomeLaunched && mRecentsAnimationController != null) {
mRecentsAnimationController.finishController(
false /* toRecents */, null /* callback */, false /* sendUserLeaveHint */);
}
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index ac4032c..e1013db 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -242,8 +242,7 @@
WorkspaceItemInfo app2 = appPairIcon.getInfo().getSecondApp();
ComponentKey app1Key = new ComponentKey(app1.getTargetComponent(), app1.user);
ComponentKey app2Key = new ComponentKey(app2.getTargetComponent(), app2.user);
- mSplitSelectStateController.setLaunchingCuj(cuj);
- InteractionJankMonitorWrapper.begin(appPairIcon, cuj);
+ mSplitSelectStateController.setLaunchingCuj(appPairIcon, cuj);
mSplitSelectStateController.findLastActiveTasksAndRunCallback(
Arrays.asList(app1Key, app2Key),
diff --git a/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt b/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt
index d58cb91..d982e81 100644
--- a/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt
@@ -17,14 +17,13 @@
package com.android.quickstep.util
import android.util.Log
-import android.view.WindowManager
import android.view.WindowManager.TRANSIT_OPEN
import android.view.WindowManager.TRANSIT_TO_FRONT
import android.window.TransitionInfo
import android.window.TransitionInfo.Change
import android.window.TransitionInfo.FLAG_FIRST_CUSTOM
import com.android.launcher3.util.SplitConfigurationOptions
-import com.android.wm.shell.util.SplitBounds
+import com.android.wm.shell.shared.split.SplitBounds
import java.lang.IllegalStateException
class SplitScreenUtils {
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 431cfbe..ae6757f 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -59,6 +59,7 @@
import android.util.Log;
import android.util.Pair;
import android.view.SurfaceControl;
+import android.view.View;
import android.window.IRemoteTransitionFinishedCallback;
import android.window.RemoteTransition;
import android.window.RemoteTransitionStub;
@@ -148,9 +149,10 @@
/**
* Should be a constant from {@link com.android.internal.jank.Cuj} or -1, does not need to be
- * set for all launches.
+ * set for all launches. Used in conjunction with {@link #mLaunchingViewCuj} below.
*/
private int mLaunchCuj = -1;
+ private View mLaunchingViewCuj;
private FloatingTaskView mFirstFloatingTaskView;
private SplitInstructionsView mSplitInstructionsView;
@@ -650,7 +652,12 @@
return mSplitAnimationController;
}
- public void setLaunchingCuj(int launchCuj) {
+ /**
+ * Set params to invoke a trace session for the given view and CUJ when we begin animating the
+ * split launch AFTER we get a response from Shell.
+ */
+ public void setLaunchingCuj(View launchingView, int launchCuj) {
+ mLaunchingViewCuj = launchingView;
mLaunchCuj = launchCuj;
}
@@ -688,6 +695,9 @@
&& mLaunchingTaskView.getRecentsView() != null
&& mLaunchingTaskView.getRecentsView().isTaskViewVisible(
mLaunchingTaskView);
+ if (mLaunchingViewCuj != null && mLaunchCuj != -1) {
+ InteractionJankMonitorWrapper.begin(mLaunchingViewCuj, mLaunchCuj);
+ }
mSplitAnimationController.playSplitLaunchAnimation(
shouldLaunchFromTaskView ? mLaunchingTaskView : null,
mLaunchingIconView,
@@ -750,6 +760,7 @@
InteractionJankMonitorWrapper.end(mLaunchCuj);
}
mLaunchCuj = -1;
+ mLaunchingViewCuj = null;
if (mSessionInstanceIds != null) {
mStatsLogManager.logger()
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index 56e91ed..828322b 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -39,7 +39,7 @@
import com.android.quickstep.TaskAnimationManager;
import com.android.systemui.shared.pip.PipSurfaceTransactionHelper;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
-import com.android.wm.shell.pip.PipContentOverlay;
+import com.android.wm.shell.shared.pip.PipContentOverlay;
/**
* Subclass of {@link RectFSpringAnim} that animates an Activity to PiP (picture-in-picture) window
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index e3c52d7..f1ff026 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -231,9 +231,9 @@
import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
-import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource;
import com.android.wm.shell.common.pip.IPipAnimationListener;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
+import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
import kotlin.Unit;
@@ -3273,12 +3273,12 @@
longRowWidth = largeTaskWidthAndSpacing;
}
- if (longRowWidth < mLastComputedGridSize.width()) {
- mClearAllShortTotalWidthTranslation =
- (mIsRtl
- ? mLastComputedTaskSize.right
- : deviceProfile.widthPx - mLastComputedTaskSize.left)
- - longRowWidth - deviceProfile.overviewGridSideMargin;
+ // If first task is not in the expected position (mLastComputedTaskSize) and being too close
+ // to ClearAllButton, then apply extra translation to ClearAllButton.
+ int firstTaskStart = mLastComputedGridSize.left + longRowWidth;
+ int expectedFirstTaskStart = mLastComputedTaskSize.right;
+ if (firstTaskStart < expectedFirstTaskStart) {
+ mClearAllShortTotalWidthTranslation = expectedFirstTaskStart - firstTaskStart;
clearAllShortTotalWidthTranslation = mIsRtl
? -mClearAllShortTotalWidthTranslation : mClearAllShortTotalWidthTranslation;
if (snappedTaskRowWidth == longRowWidth) {
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
index 4da06e1..7928ce9 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
@@ -64,6 +64,7 @@
private lateinit var bubble: BubbleBarBubble
private lateinit var bubbleBarView: BubbleBarView
private lateinit var bubbleStashController: BubbleStashController
+ private val onExpandedNoOp = Runnable {}
@Before
fun setUp() {
@@ -81,7 +82,12 @@
whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpandedNoOp,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -125,7 +131,12 @@
whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpandedNoOp,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -168,7 +179,12 @@
whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpandedNoOp,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -208,7 +224,12 @@
whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpandedNoOp,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -249,7 +270,12 @@
whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpandedNoOp,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -278,8 +304,15 @@
val handleAnimator = PhysicsAnimator.getInstance(handle)
whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
+ var notifiedExpanded = false
+ val onExpanded = Runnable { notifiedExpanded = true }
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpanded,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleInForStashed(bubble, isExpanding = true)
@@ -303,6 +336,7 @@
assertThat(animatorScheduler.delayedBlock).isNull()
verify(bubbleStashController).showBubbleBarImmediate()
+ assertThat(notifiedExpanded).isTrue()
}
@Test
@@ -314,8 +348,15 @@
val handleAnimator = PhysicsAnimator.getInstance(handle)
whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
+ var notifiedExpanded = false
+ val onExpanded = Runnable { notifiedExpanded = true }
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpanded,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -345,6 +386,7 @@
.isEqualTo(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS + BAR_TRANSLATION_Y_FOR_TASKBAR)
verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_TASKBAR)
assertThat(animator.isAnimating).isFalse()
+ assertThat(notifiedExpanded).isTrue()
}
@Test
@@ -356,8 +398,15 @@
val handleAnimator = PhysicsAnimator.getInstance(handle)
whenever(bubbleStashController.getStashedHandlePhysicsAnimator()).thenReturn(handleAnimator)
+ var notifiedExpanded = false
+ val onExpanded = Runnable { notifiedExpanded = true }
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpanded,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleInForStashed(bubble, isExpanding = false)
@@ -384,6 +433,7 @@
.isEqualTo(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS + BAR_TRANSLATION_Y_FOR_TASKBAR)
verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_TASKBAR)
assertThat(animator.isAnimating).isFalse()
+ assertThat(notifiedExpanded).isTrue()
}
@Test
@@ -400,7 +450,12 @@
val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpandedNoOp,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateToInitialState(bubble, isInApp = true, isExpanding = false)
@@ -442,8 +497,15 @@
val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+ var notifiedExpanded = false
+ val onExpanded = Runnable { notifiedExpanded = true }
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpanded,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateToInitialState(bubble, isInApp = true, isExpanding = true)
@@ -459,6 +521,7 @@
assertThat(animatorScheduler.delayedBlock).isNull()
verify(bubbleStashController).showBubbleBarImmediate()
+ assertThat(notifiedExpanded).isTrue()
}
@Test
@@ -471,7 +534,12 @@
val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpandedNoOp,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateToInitialState(bubble, isInApp = false, isExpanding = false)
@@ -502,8 +570,15 @@
whenever(bubbleStashController.bubbleBarTranslationY)
.thenReturn(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+ var notifiedExpanded = false
+ val onExpanded = Runnable { notifiedExpanded = true }
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpanded,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateToInitialState(bubble, isInApp = false, isExpanding = false)
@@ -533,6 +608,7 @@
verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_HOTSEAT)
assertThat(animator.isAnimating).isFalse()
verify(bubbleStashController).showBubbleBarImmediate()
+ assertThat(notifiedExpanded).isTrue()
}
@Test
@@ -542,8 +618,15 @@
whenever(bubbleStashController.bubbleBarTranslationY)
.thenReturn(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+ var notifiedExpanded = false
+ val onExpanded = Runnable { notifiedExpanded = true }
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpanded,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateToInitialState(bubble, isInApp = false, isExpanding = false)
@@ -566,6 +649,7 @@
verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_HOTSEAT)
assertThat(animator.isAnimating).isFalse()
+ assertThat(notifiedExpanded).isTrue()
}
@Test
@@ -578,7 +662,12 @@
val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpandedNoOp,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleBarForCollapsed(bubble, isExpanding = false)
@@ -617,8 +706,15 @@
val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+ var notifiedExpanded = false
+ val onExpanded = Runnable { notifiedExpanded = true }
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpanded,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleBarForCollapsed(bubble, isExpanding = true)
@@ -645,6 +741,7 @@
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
assertThat(bubbleBarView.isExpanded).isTrue()
verify(bubbleStashController).showBubbleBarImmediate()
+ assertThat(notifiedExpanded).isTrue()
}
@Test
@@ -656,8 +753,15 @@
val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+ var notifiedExpanded = false
+ val onExpanded = Runnable { notifiedExpanded = true }
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpanded,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleBarForCollapsed(bubble, isExpanding = false)
@@ -695,6 +799,7 @@
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
assertThat(bubbleBarView.isExpanded).isTrue()
verify(bubbleStashController).showBubbleBarImmediate()
+ assertThat(notifiedExpanded).isTrue()
}
@Test
@@ -706,8 +811,15 @@
val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+ var notifiedExpanded = false
+ val onExpanded = Runnable { notifiedExpanded = true }
val animator =
- BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+ BubbleBarViewAnimator(
+ bubbleBarView,
+ bubbleStashController,
+ onExpanded,
+ animatorScheduler
+ )
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animator.animateBubbleBarForCollapsed(bubble, isExpanding = false)
@@ -742,6 +854,7 @@
assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
assertThat(bubbleBarView.isExpanded).isTrue()
verify(bubbleStashController).showBubbleBarImmediate()
+ assertThat(notifiedExpanded).isTrue()
}
private fun setUpBubbleBar() {
diff --git a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
index d9d5585..885a7f6 100644
--- a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
@@ -39,8 +39,8 @@
import com.android.systemui.shared.recents.model.Task
import com.android.systemui.shared.recents.model.Task.TaskKey
import com.android.window.flags.Flags
-import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
diff --git a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
index cbc8441..244b897 100644
--- a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
+++ b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
@@ -39,7 +39,7 @@
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.views.TaskViewType;
import com.android.systemui.shared.recents.model.Task;
-import com.android.wm.shell.util.GroupedRecentTaskInfo;
+import com.android.wm.shell.shared.GroupedRecentTaskInfo;
import org.junit.Before;
import org.junit.Test;
diff --git a/res/drawable/bg_letter_list_text.xml b/res/drawable/bg_letter_list_text.xml
new file mode 100644
index 0000000..427702b
--- /dev/null
+++ b/res/drawable/bg_letter_list_text.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 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.
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+ <solid android:color="?attr/materialColorSurfaceContainer" />
+ <corners android:radius="100dp"/>
+ <size
+ android:width="@dimen/bg_letter_list_text_size"
+ android:height="@dimen/bg_letter_list_text_size"/>
+</shape>
\ No newline at end of file
diff --git a/res/layout/all_apps_fast_scroller.xml b/res/layout/all_apps_fast_scroller.xml
index 0f1d933..7e16ca5 100644
--- a/res/layout/all_apps_fast_scroller.xml
+++ b/res/layout/all_apps_fast_scroller.xml
@@ -36,4 +36,17 @@
android:layout_marginEnd="@dimen/fastscroll_end_margin"
launcher:canThumbDetach="true" />
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/scroll_letter_layout"
+ android:layout_width="@dimen/fastscroll_width"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentEnd="true"
+ android:layout_alignTop="@+id/all_apps_header"
+ android:layout_marginTop="@dimen/all_apps_header_bottom_padding"
+ android:layout_marginEnd="@dimen/fastscroll_list_letter_end_margin"
+ android:clipToPadding="false"
+ android:outlineProvider="none"
+ />
</merge>
\ No newline at end of file
diff --git a/res/layout/fast_scroller_letter_list_text_view.xml b/res/layout/fast_scroller_letter_list_text_view.xml
new file mode 100644
index 0000000..493b6fc
--- /dev/null
+++ b/res/layout/fast_scroller_letter_list_text_view.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 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.
+ -->
+
+<com.android.launcher3.allapps.LetterListTextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/fastscroll_list_letter_size"
+ android:layout_height="@dimen/fastscroll_list_letter_size"
+ android:textSize="@dimen/fastscroll_list_letter_text_size"
+ android:importantForAccessibility="no"
+ android:gravity="center"
+ android:clickable="false">
+</com.android.launcher3.allapps.LetterListTextView>
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 3b239ac..5ba00c0 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -81,6 +81,11 @@
<dimen name="fastscroll_popup_text_size">32dp</dimen>
<dimen name="fastscroll_popup_margin">19dp</dimen>
+ <dimen name="fastscroll_list_letter_size">5dp</dimen>
+ <dimen name="fastscroll_list_letter_text_size">14sp</dimen>
+ <dimen name="fastscroll_list_letter_end_margin">-10dp</dimen>
+ <dimen name="bg_letter_list_text_size">20sp</dimen>
+
<!--
Fast scroller draws the content horizontally centered. The end of the track should be
aligned at the end of the container.
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 0839b67..26e900d 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -1043,12 +1043,11 @@
/** Applies the given progress level to the this icon's progress bar. */
@Nullable
public PreloadIconDrawable applyProgressLevel() {
- if (!(getTag() instanceof ItemInfoWithIcon)
+ if (!(getTag() instanceof ItemInfoWithIcon info)
|| ((ItemInfoWithIcon) getTag()).isInactiveArchive()) {
return null;
}
- ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
int progressLevel = info.getProgressLevel();
if (progressLevel >= 100) {
setContentDescription(info.contentDescription != null
@@ -1068,6 +1067,10 @@
} else {
preloadIconDrawable = makePreloadIcon();
setIcon(preloadIconDrawable);
+ if (info.isArchived() && Flags.useNewIconForArchivedApps()) {
+ // reapply text without cloud icon as soon as unarchiving is triggered
+ applyLabel(info);
+ }
}
return preloadIconDrawable;
}
diff --git a/src/com/android/launcher3/FastScrollRecyclerView.java b/src/com/android/launcher3/FastScrollRecyclerView.java
index de1748b..6622e11 100644
--- a/src/com/android/launcher3/FastScrollRecyclerView.java
+++ b/src/com/android/launcher3/FastScrollRecyclerView.java
@@ -25,6 +25,7 @@
import android.view.accessibility.AccessibilityNodeInfo;
import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -54,9 +55,11 @@
super(context, attrs, defStyleAttr);
}
- public void bindFastScrollbar(RecyclerViewFastScroller scrollbar) {
+ public void bindFastScrollbar(RecyclerViewFastScroller scrollbar,
+ RecyclerViewFastScroller.FastScrollerLocation location) {
mScrollbar = scrollbar;
mScrollbar.setRecyclerView(this);
+ mScrollbar.setFastScrollerLocation(location);
onUpdateScrollbar(0);
}
@@ -163,6 +166,13 @@
public abstract void onUpdateScrollbar(int dy);
/**
+ * Return the fast scroll letter list view in the A-Z list.
+ */
+ public ConstraintLayout getLetterList() {
+ return null;
+ }
+
+ /**
* <p>Override in each subclass of this base class.
*/
public void onFastScrollCompleted() {}
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 227ac2b..cc4724c 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -29,6 +29,7 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.ScrollableLayoutManager.PREDICTIVE_BACK_MIN_SCALE;
+import static com.android.launcher3.views.RecyclerViewFastScroller.FastScrollerLocation.ALL_APPS_SCROLLER;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -65,6 +66,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.Px;
import androidx.annotation.VisibleForTesting;
+import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.graphics.ColorUtils;
import androidx.recyclerview.widget.RecyclerView;
@@ -168,6 +170,7 @@
protected FloatingHeaderView mHeader;
protected View mBottomSheetBackground;
protected RecyclerViewFastScroller mFastScroller;
+ private ConstraintLayout mFastScrollLetterLayout;
/**
* View that defines the search box. Result is rendered inside {@link #mSearchRecyclerView}.
@@ -282,6 +285,13 @@
mSearchRecyclerView = findViewById(R.id.search_results_list_view);
mFastScroller = findViewById(R.id.fast_scroller);
mFastScroller.setPopupView(findViewById(R.id.fast_scroller_popup));
+ mFastScrollLetterLayout = findViewById(R.id.scroll_letter_layout);
+ if (Flags.letterFastScroller()) {
+ // Set clip children to false otherwise the scroller letters will be clipped.
+ setClipChildren(false);
+ } else {
+ setClipChildren(true);
+ }
mSearchContainer = inflateSearchBar();
if (!isSearchBarFloating()) {
@@ -563,7 +573,8 @@
mActivityContext.hideKeyboard();
}
if (mAH.get(currentActivePage).mRecyclerView != null) {
- mAH.get(currentActivePage).mRecyclerView.bindFastScrollbar(mFastScroller);
+ mAH.get(currentActivePage).mRecyclerView.bindFastScrollbar(mFastScroller,
+ ALL_APPS_SCROLLER);
}
// Header keeps track of active recycler view to properly render header protection.
mHeader.setActiveRV(currentActivePage);
@@ -1500,6 +1511,10 @@
}
}
+ ConstraintLayout getFastScrollerLetterList() {
+ return mFastScrollLetterLayout;
+ }
+
/**
* redraws header protection
*/
@@ -1567,7 +1582,7 @@
void setup(@NonNull View rv, @Nullable Predicate<ItemInfo> matcher) {
mAppsList.updateItemFilter(matcher);
mRecyclerView = (AllAppsRecyclerView) rv;
- mRecyclerView.bindFastScrollbar(mFastScroller);
+ mRecyclerView.bindFastScrollbar(mFastScroller, ALL_APPS_SCROLLER);
mRecyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
mRecyclerView.setApps(mAppsList);
mRecyclerView.setLayoutManager(mLayoutManager);
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 2a47222..ae45a35 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -15,6 +15,9 @@
*/
package com.android.launcher3.allapps;
+import static androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT;
+import static androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT;
+
import static com.android.launcher3.config.FeatureFlags.ALL_APPS_GONE_VISIBILITY;
import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_RV_PREINFLATION;
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo;
@@ -36,22 +39,29 @@
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.LayoutInflater;
import android.view.View;
+import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.constraintlayout.widget.ConstraintSet;
import androidx.core.util.Consumer;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.FastScrollRecyclerView;
+import com.android.launcher3.Flags;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.views.ActivityContext;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -66,6 +76,7 @@
protected final int mNumAppsPerRow;
private final AllAppsFastScrollHelper mFastScrollHelper;
private int mCumulativeVerticalScroll;
+ private ConstraintLayout mLetterList;
protected AlphabeticalAppsList<?> mApps;
@@ -238,6 +249,9 @@
return;
}
+ if (Flags.letterFastScroller() && !mScrollbar.isDraggingThumb()) {
+ setLettersToScrollLayout(mApps.getFastScrollerSections());
+ }
// Only show the scrollbar if there is height to be scrolled
int availableScrollBarHeight = getAvailableScrollBarHeight();
int availableScrollHeight = getAvailableScrollHeight();
@@ -319,6 +333,80 @@
return false;
}
+ public void setLettersToScrollLayout(
+ List<AlphabeticalAppsList.FastScrollSectionInfo> fastScrollSections) {
+ if (mLetterList != null) {
+ mLetterList.removeAllViews();
+ }
+ Context context = getContext();
+ ActivityAllAppsContainerView<?> allAppsContainerView =
+ ActivityContext.lookupContext(context).getAppsView();
+ mLetterList = allAppsContainerView.getFastScrollerLetterList();
+ mLetterList.setPadding(0, getScrollBarTop(), 0, getScrollBarMarginBottom());
+ List<LetterListTextView> textViews = new ArrayList<>();
+ for (int i = 0; i < fastScrollSections.size(); i++) {
+ AlphabeticalAppsList.FastScrollSectionInfo sectionInfo = fastScrollSections.get(i);
+ LetterListTextView textView =
+ (LetterListTextView) LayoutInflater.from(context).inflate(
+ R.layout.fast_scroller_letter_list_text_view, mLetterList, false);
+ int viewId = View.generateViewId();
+ textView.setId(viewId);
+ sectionInfo.setId(viewId);
+ textView.setText(sectionInfo.sectionName);
+ if (i == fastScrollSections.size() - 1) {
+ // The last section info is just a duplicate so that user can scroll to the bottom.
+ textView.setVisibility(INVISIBLE);
+ }
+ ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(
+ MATCH_CONSTRAINT, WRAP_CONTENT);
+ lp.dimensionRatio = "v,1:1";
+ textView.setLayoutParams(lp);
+ textViews.add(textView);
+ mLetterList.addView(textView);
+ }
+ // Need to add an extra textview to be aligned.
+ LetterListTextView lastLetterListTextView = new LetterListTextView(context);
+ int currentId = View.generateViewId();
+ lastLetterListTextView.setId(currentId);
+ lastLetterListTextView.setVisibility(INVISIBLE);
+ textViews.add(lastLetterListTextView);
+ mLetterList.addView(lastLetterListTextView);
+ constraintTextViewsVertically(mLetterList, textViews);
+ mLetterList.setVisibility(VISIBLE);
+ }
+
+ private void constraintTextViewsVertically(ConstraintLayout constraintLayout,
+ List<LetterListTextView> textViews) {
+ ConstraintSet chain = new ConstraintSet();
+ chain.clone(constraintLayout);
+ for (int i = 0; i < textViews.size(); i++) {
+ LetterListTextView currentView = textViews.get(i);
+ if (i == 0) {
+ chain.connect(currentView.getId(), ConstraintSet.TOP, ConstraintSet.PARENT_ID,
+ ConstraintSet.TOP);
+ } else {
+ chain.connect(currentView.getId(), ConstraintSet.TOP, textViews.get(i-1).getId(),
+ ConstraintSet.BOTTOM);
+ }
+ chain.connect(currentView.getId(), ConstraintSet.START, constraintLayout.getId(),
+ ConstraintSet.START);
+ chain.connect(currentView.getId(), ConstraintSet.END, constraintLayout.getId(),
+ ConstraintSet.END);
+ }
+ int[] viewIds = textViews.stream().mapToInt(TextView::getId).toArray();
+ float[] weights = new float[textViews.size()];
+ Arrays.fill(weights,1); // fill with 1 for equal weights
+ chain.createVerticalChain(constraintLayout.getId(), ConstraintSet.TOP,
+ constraintLayout.getId(), ConstraintSet.BOTTOM, viewIds, weights,
+ ConstraintSet.CHAIN_SPREAD);
+ chain.applyTo(constraintLayout);
+ }
+
+ @Override
+ public ConstraintLayout getLetterList() {
+ return mLetterList;
+ }
+
private void logCumulativeVerticalScroll() {
ActivityContext context = ActivityContext.lookupContext(getContext());
StatsLogManager mgr = context.getStatsLogManager();
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 6dd811a..8e44d65 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -74,11 +74,17 @@
public final CharSequence sectionName;
// The item position
public final int position;
+ // The view id associated with this section
+ public int id = -1;
public FastScrollSectionInfo(CharSequence sectionName, int position) {
this.sectionName = sectionName;
this.position = position;
}
+
+ public void setId(int id) {
+ this.id = id;
+ }
}
diff --git a/src/com/android/launcher3/allapps/LetterListTextView.java b/src/com/android/launcher3/allapps/LetterListTextView.java
new file mode 100644
index 0000000..9326d79
--- /dev/null
+++ b/src/com/android/launcher3/allapps/LetterListTextView.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2024 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.allapps;
+
+import android.content.Context;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+import androidx.core.graphics.ColorUtils;
+
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.util.Themes;
+
+/**
+ * A TextView that is used to display the letter list in the fast scroller.
+ */
+public class LetterListTextView extends TextView {
+ private static final float ABSOLUTE_TRANSLATION_X = 30f;
+ private static final float ABSOLUTE_SCALE = 1.4f;
+ private final Drawable mLetterBackground;
+ private final int mLetterListTextWidthAndHeight;
+ private final int mTextColor;
+ private final int mBackgroundColor;
+ private final int mSelectedColor;
+
+ public LetterListTextView(Context context) {
+ this(context, null, 0);
+ }
+
+ public LetterListTextView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public LetterListTextView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ mLetterBackground = context.getDrawable(R.drawable.bg_letter_list_text);
+ mLetterListTextWidthAndHeight = context.getResources().getDimensionPixelSize(
+ R.dimen.fastscroll_list_letter_size);
+ mTextColor = Themes.getAttrColor(context, R.attr.materialColorOnSurface);
+ mBackgroundColor = Themes.getAttrColor(context, R.attr.materialColorSurfaceContainer);
+ mSelectedColor = Themes.getAttrColor(context, R.attr.materialColorOnSecondary);
+ }
+
+ @Override
+ public void onFinishInflate() {
+ super.onFinishInflate();
+ setBackground(mLetterBackground);
+ setTextColor(mTextColor);
+ setClickable(false);
+ setWidth(mLetterListTextWidthAndHeight);
+ setTextSize(mLetterListTextWidthAndHeight);
+ setVisibility(VISIBLE);
+ }
+
+ /**
+ * Animates the letter list text view based on the current finger position.
+ *
+ * @param currentFingerY The Y position of where the finger is placed on the fastScroller in
+ * pixels.
+ */
+ public void animateBasedOnYPosition(int currentFingerY) {
+ if (getBackground() == null) {
+ return;
+ }
+ float cutOffMin = currentFingerY - (getHeight() * 2);
+ float cutOffMax = currentFingerY + (getHeight() * 2);
+ float cutOffDistance = cutOffMax - cutOffMin;
+ // Update the background blend color
+ boolean isWithinAnimationBounds = getY() < cutOffMax && getY() > cutOffMin;
+ if (isWithinAnimationBounds) {
+ getBackground().setColorFilter(new PorterDuffColorFilter(
+ getBlendColorBasedOnYPosition(currentFingerY, cutOffDistance),
+ PorterDuff.Mode.MULTIPLY));
+ } else {
+ getBackground().setColorFilter(new PorterDuffColorFilter(
+ mBackgroundColor, PorterDuff.Mode.MULTIPLY));
+ }
+ translateBasedOnYPosition(currentFingerY, cutOffDistance, isWithinAnimationBounds);
+ scaleBasedOnYPosition(currentFingerY, cutOffDistance, isWithinAnimationBounds);
+ }
+
+ private int getBlendColorBasedOnYPosition(int y, float cutOffDistance) {
+ float raisedCosineBlend = (float) Math.cos(((y - getY()) / (cutOffDistance)) * Math.PI);
+ float blendRatio = Utilities.boundToRange(raisedCosineBlend, 0f, 1f);
+ return ColorUtils.blendARGB(mBackgroundColor, mSelectedColor, blendRatio);
+ }
+
+ private void scaleBasedOnYPosition(int y, float cutOffDistance,
+ boolean isWithinAnimationBounds) {
+ float raisedCosineScale = (float) Math.cos(((y - getY()) / (cutOffDistance)) * Math.PI)
+ * ABSOLUTE_SCALE;
+ if (isWithinAnimationBounds) {
+ raisedCosineScale = Utilities.boundToRange(raisedCosineScale, 1f, ABSOLUTE_SCALE);
+ setScaleX(raisedCosineScale);
+ setScaleY(raisedCosineScale);
+ } else {
+ setScaleX(1);
+ setScaleY(1);
+ }
+ }
+
+ private void translateBasedOnYPosition(int y, float cutOffDistance,
+ boolean isWithinAnimationBounds) {
+ float raisedCosineTranslation =
+ (float) Math.cos(((y - getY()) / (cutOffDistance)) * Math.PI)
+ * ABSOLUTE_TRANSLATION_X;
+ if (isWithinAnimationBounds) {
+ raisedCosineTranslation = -1 * Utilities.boundToRange(raisedCosineTranslation,
+ 0, ABSOLUTE_TRANSLATION_X);
+ setTranslationX(raisedCosineTranslation);
+ } else {
+ setTranslationX(0);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java b/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java
index 406f697..de2269c 100644
--- a/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java
+++ b/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java
@@ -18,10 +18,12 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.LauncherActivityInfo;
+import android.os.Build;
import android.os.UserHandle;
import androidx.annotation.NonNull;
+import com.android.launcher3.Flags;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.icons.BaseIconFactory.IconOptions;
@@ -64,9 +66,16 @@
@Override
public BitmapInfo loadIcon(@NonNull Context context, @NonNull LauncherActivityInfo object) {
try (LauncherIcons li = LauncherIcons.obtain(context)) {
- return li.createBadgedIconBitmap(LauncherAppState.getInstance(context)
- .getIconProvider().getIcon(object, li.mFillResIconDpi),
- new IconOptions().setUser(object.getUser()));
+ IconOptions iconOptions = new IconOptions().setUser(object.getUser());
+ iconOptions.mIsArchived = Flags.useNewIconForArchivedApps()
+ && Build.VERSION.SDK_INT >= 35
+ && object.getActivityInfo().isArchived;
+ return li.createBadgedIconBitmap(
+ LauncherAppState.getInstance(context)
+ .getIconProvider()
+ .getIcon(object, li.mFillResIconDpi),
+ iconOptions
+ );
}
}
}
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 269cb9f..605accf 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -209,7 +209,10 @@
mApp.getContext().getContentResolver(),
"launcher_broadcast_installed_apps",
/* def= */ 0);
- if (launcherBroadcastInstalledApps == 1 && mIsRestoreFromBackup) {
+ boolean shouldAttachArchivingExtras = mIsRestoreFromBackup
+ && (launcherBroadcastInstalledApps == 1
+ || Flags.enableFirstScreenBroadcastArchivingExtras());
+ if (shouldAttachArchivingExtras) {
List<FirstScreenBroadcastModel> broadcastModels =
FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
mPmHelper,
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index fa17b7b..63648dd 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -20,6 +20,9 @@
import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE;
+import static com.android.launcher3.views.RecyclerViewFastScroller.FastScrollerLocation.ALL_APPS_SCROLLER;
+import static com.android.launcher3.views.RecyclerViewFastScroller.FastScrollerLocation.WIDGET_SCROLLER;
+
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
@@ -40,11 +43,15 @@
import android.view.WindowInsets;
import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.FastScrollRecyclerView;
+import com.android.launcher3.Flags;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.allapps.LetterListTextView;
import com.android.launcher3.graphics.FastScrollThumbDrawable;
import com.android.launcher3.util.Themes;
@@ -55,6 +62,19 @@
* The track and scrollbar that shows when you scroll the list.
*/
public class RecyclerViewFastScroller extends View {
+
+ /** FastScrollerLocation describes what RecyclerView the fast scroller is dedicated to. */
+ public enum FastScrollerLocation {
+ UNKNOWN_SCROLLER(0),
+ ALL_APPS_SCROLLER(1),
+ WIDGET_SCROLLER(2);
+
+ public final int location;
+
+ FastScrollerLocation(int location) {
+ this.location = location;
+ }
+ }
private static final String TAG = "RecyclerViewFastScroller";
private static final boolean DEBUG = false;
private static final int FASTSCROLL_THRESHOLD_MILLIS = 40;
@@ -106,6 +126,8 @@
private final Point mThumbDrawOffset = new Point();
private final Paint mTrackPaint;
+ private final int mThumbColor;
+ private final int mThumbLetterScrollerColor;
private float mLastTouchY;
private boolean mIsDragging;
@@ -139,6 +161,7 @@
private int mDownX;
private int mDownY;
private int mLastY;
+ private FastScrollerLocation mFastScrollerLocation;
public RecyclerViewFastScroller(Context context) {
this(context, null);
@@ -151,13 +174,16 @@
public RecyclerViewFastScroller(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ mFastScrollerLocation = FastScrollerLocation.UNKNOWN_SCROLLER;
mTrackPaint = new Paint();
mTrackPaint.setColor(Themes.getAttrColor(context, android.R.attr.textColorPrimary));
mTrackPaint.setAlpha(MAX_TRACK_ALPHA);
+ mThumbColor = Themes.getColorAccent(context);
+ mThumbLetterScrollerColor = Themes.getAttrColor(context, R.attr.materialColorSurfaceBright);
mThumbPaint = new Paint();
mThumbPaint.setAntiAlias(true);
- mThumbPaint.setColor(Themes.getColorAccent(context));
+ mThumbPaint.setColor(mThumbColor);
mThumbPaint.setStyle(Paint.Style.FILL);
Resources res = getResources();
@@ -334,6 +360,18 @@
animatePopupVisibility(!TextUtils.isEmpty(sectionName));
mLastTouchY = boundedY;
setThumbOffsetY((int) mLastTouchY);
+ updateFastScrollerLetterList(y);
+ }
+
+ private void updateFastScrollerLetterList(int y) {
+ if (!shouldUseLetterFastScroller()) {
+ return;
+ }
+ ConstraintLayout mLetterList = mRv.getLetterList();
+ for (int i = 0; i < mLetterList.getChildCount(); i++) {
+ LetterListTextView currentLetter = (LetterListTextView) mLetterList.getChildAt(i);
+ currentLetter.animateBasedOnYPosition(y + mTouchOffsetY);
+ }
}
/** End any active fast scrolling touch handling, if applicable. */
@@ -359,15 +397,35 @@
mThumbDrawOffset.set(getWidth() / 2, mRv.getScrollBarTop());
// Draw the track
float halfW = mWidth / 2;
- canvas.drawRoundRect(-halfW, 0, halfW, mRv.getScrollbarTrackHeight(),
- mWidth, mWidth, mTrackPaint);
-
- canvas.translate(0, mThumbOffsetY);
+ boolean useLetterFastScroller = shouldUseLetterFastScroller();
+ if (useLetterFastScroller) {
+ float translateX;
+ if (mIsDragging) {
+ // halfW * 3 is half circle.
+ translateX = halfW * 3;
+ } else {
+ translateX = halfW * 5;
+ }
+ canvas.translate(translateX, mThumbOffsetY);
+ } else {
+ canvas.drawRoundRect(-halfW, 0, halfW, mRv.getScrollbarTrackHeight(),
+ mWidth, mWidth, mTrackPaint);
+ canvas.translate(0, mThumbOffsetY);
+ }
mThumbDrawOffset.y += mThumbOffsetY;
+
+ /* Draw half circle */
halfW += mThumbPadding;
float r = getScrollThumbRadius();
- mThumbBounds.set(-halfW, 0, halfW, mThumbHeight);
- canvas.drawRoundRect(mThumbBounds, r, r, mThumbPaint);
+ if (useLetterFastScroller) {
+ mThumbPaint.setColor(mThumbLetterScrollerColor);
+ mThumbBounds.set(0, 0, 0, mThumbHeight);
+ canvas.drawCircle(-halfW, halfW, r * 2, mThumbPaint);
+ } else {
+ mThumbPaint.setColor(mThumbColor);
+ mThumbBounds.set(-halfW, 0, halfW, mThumbHeight);
+ canvas.drawRoundRect(mThumbBounds, r, r, mThumbPaint);
+ }
mThumbBounds.roundOut(SYSTEM_GESTURE_EXCLUSION_RECT.get(0));
// swiping very close to the thumb area (not just within it's bound)
// will also prevent back gesture
@@ -380,6 +438,11 @@
canvas.restoreToCount(saveCount);
}
+ boolean shouldUseLetterFastScroller() {
+ return Flags.letterFastScroller()
+ && getScrollerLocation() == FastScrollerLocation.ALL_APPS_SCROLLER;
+ }
+
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
mSystemGestureInsets = insets.getSystemGestureInsets();
@@ -421,19 +484,25 @@
return isNearThumb(x, y);
}
- /**
- * Returns whether the specified x position is near the scroll bar.
- */
- public boolean isNearScrollBar(int x) {
- return x >= (getWidth() - mMaxWidth) / 2 - mScrollbarLeftOffsetTouchDelegate
- && x <= (getWidth() + mMaxWidth) / 2;
+ public FastScrollerLocation getScrollerLocation() {
+ return mFastScrollerLocation;
+ }
+
+ public void setFastScrollerLocation(@NonNull FastScrollerLocation location) {
+ mFastScrollerLocation = location;
}
private void animatePopupVisibility(boolean visible) {
if (mPopupVisible != visible) {
mPopupVisible = visible;
- mPopupView.animate().cancel();
- mPopupView.animate().alpha(visible ? 1f : 0f).setDuration(visible ? 200 : 150).start();
+ if (shouldUseLetterFastScroller()) {
+ mRv.getLetterList().animate().alpha(visible ? 1f : 0f)
+ .setDuration(visible ? 200 : 150).start();
+ } else {
+ mPopupView.animate().cancel();
+ mPopupView.animate().alpha(visible ? 1f : 0f)
+ .setDuration(visible ? 200 : 150).start();
+ }
}
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 2af8e6f..c8ad564 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.SEARCH;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_SEARCHED;
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
+import static com.android.launcher3.views.RecyclerViewFastScroller.FastScrollerLocation.WIDGET_SCROLLER;
import android.animation.Animator;
import android.content.Context;
@@ -119,7 +120,7 @@
WidgetsRecyclerView searchRecyclerView =
mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView;
if (mIsInSearchMode && searchRecyclerView != null) {
- searchRecyclerView.bindFastScrollbar(mFastScroller);
+ searchRecyclerView.bindFastScrollbar(mFastScroller, WIDGET_SCROLLER);
}
}
@@ -276,7 +277,7 @@
}
private void attachScrollbarToRecyclerView(WidgetsRecyclerView recyclerView) {
- recyclerView.bindFastScrollbar(mFastScroller);
+ recyclerView.bindFastScrollbar(mFastScroller, WIDGET_SCROLLER);
if (mCurrentWidgetsRecyclerView != recyclerView) {
// Only reset the scroll position & expanded apps if the currently shown recycler view
// has been updated.
@@ -290,10 +291,10 @@
protected void updateRecyclerViewVisibility(AdapterHolder adapterHolder) {
// The first item is always an empty space entry. Look for any more items.
boolean isWidgetAvailable = adapterHolder.mWidgetsListAdapter.hasVisibleEntries();
- adapterHolder.mWidgetsRecyclerView.setVisibility(isWidgetAvailable ? VISIBLE : GONE);
if (adapterHolder.mAdapterType == AdapterHolder.SEARCH) {
mNoWidgetsView.setText(R.string.no_search_results);
+ adapterHolder.mWidgetsRecyclerView.setVisibility(isWidgetAvailable ? VISIBLE : GONE);
} else if (adapterHolder.mAdapterType == AdapterHolder.WORK
&& mUserCache.getUserProfiles().stream()
.filter(userHandle -> mUserCache.getUserInfo(userHandle).isWork())
@@ -556,6 +557,8 @@
mNoWidgetsView.setVisibility(GONE);
} else {
mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.setVisibility(GONE);
+ mAdapters.get(getCurrentAdapterHolderType()).mWidgetsRecyclerView.setVisibility(
+ VISIBLE);
// Visibility of recommended widgets, recycler views and headers are handled in methods
// below.
post(this::onRecommendedWidgetsBound);
@@ -1057,7 +1060,7 @@
mWidgetsRecyclerView.setClipToOutline(true);
mWidgetsRecyclerView.setClipChildren(false);
mWidgetsRecyclerView.setAdapter(mWidgetsListAdapter);
- mWidgetsRecyclerView.bindFastScrollbar(mFastScroller);
+ mWidgetsRecyclerView.bindFastScrollbar(mFastScroller, WIDGET_SCROLLER);
mWidgetsRecyclerView.setItemAnimator(isTwoPane() ? null : mWidgetsListItemAnimator);
mWidgetsRecyclerView.setHeaderViewDimensionsProvider(WidgetsFullSheet.this);
if (!isTwoPane()) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
index 2653514..d329674 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -461,6 +461,13 @@
if (!isWidgetAvailable) {
mRightPane.removeAllViews();
mRightPane.addView(mNoWidgetsView);
+ // with no widgets message, no header is selected on left
+ if (mSuggestedWidgetsPackageUserKey != null
+ && mSuggestedWidgetsPackageUserKey.equals(mSelectedHeader)
+ && mSuggestedWidgetsHeader != null) {
+ mSuggestedWidgetsHeader.setExpanded(false);
+ }
+ mSelectedHeader = null;
}
super.updateRecyclerViewVisibility(adapterHolder);
}
diff --git a/tests/Android.bp b/tests/Android.bp
index 9945570..1fa6e05 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -160,7 +160,7 @@
}
filegroup {
- name: "launcher-testing-helpers-multivalent",
+ name: "launcher-testing-helpers-robo",
srcs: [
"src/**/*.java",
"src/**/*.kt",
@@ -183,7 +183,7 @@
filegroup {
name: "launcher-testing-helpers",
srcs: [
- ":launcher-testing-helpers-multivalent",
+ ":launcher-testing-helpers-robo",
"src/**/RoboApiWrapper.kt",
],
}
@@ -195,7 +195,7 @@
":launcher3-robo-src",
// Test util classes
- ":launcher-testing-helpers-multivalent",
+ ":launcher-testing-helpers-robo",
":launcher-testing-shared",
],
exclude_srcs: [