Merge "[HSUM] Update createTestWidgetItem to use current user for test widget" into main
diff --git a/Android.bp b/Android.bp
index 73d0fce..6bd8602 100644
--- a/Android.bp
+++ b/Android.bp
@@ -475,6 +475,9 @@
],
manifest: "quickstep/AndroidManifest.xml",
min_sdk_version: "current",
+ lint: {
+ disabled_checks: ["MissingClass"],
+ },
}
// Library with all the source code and dependencies for building Launcher Go
diff --git a/aconfig/launcher_overview.aconfig b/aconfig/launcher_overview.aconfig
index 93d8d54..b299edf 100644
--- a/aconfig/launcher_overview.aconfig
+++ b/aconfig/launcher_overview.aconfig
@@ -61,4 +61,14 @@
namespace: "launcher_overview"
description: "Enables the non-overlapping layout for desktop windows in Overview mode."
bug: "378011776"
+}
+
+flag {
+ name: "enable_use_top_visible_activity_for_exclude_from_recent_task"
+ namespace: "launcher_overview"
+ description: "Enables using the top visible activity for exclude from recent task instead of the activity indicies."
+ bug: "342627272"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
\ No newline at end of file
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 8c39585..201c5f6 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -81,7 +81,7 @@
android:stateNotNeeded="true"
android:theme="@style/LauncherTheme"
android:screenOrientation="behind"
- android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
+ android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:enableOnBackInvokedCallback="false"
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index a7f6b36..3aac1b6 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -28,7 +28,11 @@
launcher:focusBorderColor="@color/materialColorOutline"
launcher:hoverBorderColor="@color/materialColorPrimary">
- <include layout="@layout/task_thumbnail_deprecated" />
+ <ViewStub
+ android:id="@+id/snapshot"
+ android:inflatedId="@id/snapshot"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
<!-- Filtering affects only alpha instead of the visibility since visibility can be altered
separately through RecentsView#resetFromSplitSelectionState() -->
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index 4c650b9..3e6f5ed 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -33,10 +33,17 @@
launcher:focusBorderColor="@color/materialColorOutline"
launcher:hoverBorderColor="@color/materialColorPrimary">
- <include layout="@layout/task_thumbnail_deprecated"/>
+ <ViewStub
+ android:id="@+id/snapshot"
+ android:inflatedId="@id/snapshot"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
- <include layout="@layout/task_thumbnail_deprecated"
- android:id="@+id/bottomright_snapshot" />
+ <ViewStub
+ android:id="@+id/bottomright_snapshot"
+ android:inflatedId="@id/bottomright_snapshot"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
<!-- Filtering affects only alpha instead of the visibility since visibility can be altered
separately through RecentsView#resetFromSplitSelectionState() -->
diff --git a/quickstep/res/layout/task_thumbnail.xml b/quickstep/res/layout/task_thumbnail.xml
index afbcdb5..3b96615 100644
--- a/quickstep/res/layout/task_thumbnail.xml
+++ b/quickstep/res/layout/task_thumbnail.xml
@@ -15,7 +15,6 @@
-->
<com.android.quickstep.task.thumbnail.TaskThumbnailView
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/snapshot"
android:layout_width="match_parent"
android:layout_height="match_parent" >
@@ -53,10 +52,7 @@
android:id="@+id/splash_icon"
android:layout_width="@dimen/task_thumbnail_splash_icon_size"
android:layout_height="@dimen/task_thumbnail_splash_icon_size"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
+ android:layout_gravity="center"
android:scaleType="fitCenter"
android:alpha="0"
android:importantForAccessibility="no" />
diff --git a/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchTransitionManager.kt b/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchTransitionManager.kt
index 645bef6..6e36305 100644
--- a/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchTransitionManager.kt
+++ b/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchTransitionManager.kt
@@ -45,7 +45,8 @@
}
remoteWindowLimitUnminimizeTransition =
RemoteTransition(
- DesktopAppLaunchTransition(context, MAIN_EXECUTOR, AppLaunchType.UNMINIMIZE)
+ DesktopAppLaunchTransition(context, MAIN_EXECUTOR, AppLaunchType.UNMINIMIZE),
+ "DesktopWindowLimitUnminimize"
)
systemUiProxy.registerRemoteTransition(
remoteWindowLimitUnminimizeTransition,
diff --git a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
index ac1ffa6..8b064d3 100644
--- a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
+++ b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
@@ -31,6 +31,8 @@
import com.android.quickstep.SystemUiProxy
import com.android.quickstep.TaskViewUtils
import com.android.quickstep.views.DesktopTaskView
+import com.android.quickstep.views.TaskContainer
+import com.android.quickstep.views.TaskView
import com.android.window.flags.Flags
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource
import java.util.function.Consumer
@@ -62,8 +64,12 @@
}
/** Launch desktop tasks from recents view */
- fun moveToDesktop(taskId: Int, transitionSource: DesktopModeTransitionSource) {
- systemUiProxy.moveToDesktop(taskId, transitionSource)
+ fun moveToDesktop(taskContainer: TaskContainer, transitionSource: DesktopModeTransitionSource) {
+ systemUiProxy.moveToDesktop(
+ taskContainer.task.key.id,
+ transitionSource,
+ /* transition = */ null,
+ )
}
/** Move task to external display from recents view */
@@ -72,7 +78,7 @@
}
private class RemoteDesktopLaunchTransitionRunner(
- private val desktopTaskView: DesktopTaskView,
+ private val taskView: TaskView,
private val animated: Boolean,
private val stateManager: StateManager<*, *>,
private val depthController: DepthController?,
@@ -99,7 +105,7 @@
MAIN_EXECUTOR.execute {
val animator =
TaskViewUtils.composeRecentsDesktopLaunchAnimator(
- desktopTaskView,
+ taskView,
stateManager,
depthController,
info,
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
index 3114bc8..cb811d6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.launcher3.desktop.DesktopAppLaunchTransition.AppLaunchType.UNMINIMIZE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@@ -285,8 +286,8 @@
) {
// This app is being unminimized - use our own transition runner.
remoteTransition = new RemoteTransition(
- new DesktopAppLaunchTransition(
- context, MAIN_EXECUTOR, AppLaunchType.UNMINIMIZE));
+ new DesktopAppLaunchTransition(context, MAIN_EXECUTOR, UNMINIMIZE),
+ "DesktopKeyboardQuickSwitchUnminimize");
}
mControllers.taskbarActivityContext.handleGroupTaskLaunch(
task,
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index cb4e5e2..9ee4b95 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -866,13 +866,19 @@
TaskbarNavButtonController navButtonController) {
final RectF rect = new RectF();
buttonView.setOnTouchListener((v, event) -> {
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ int motionEventAction = event.getAction();
+ if (motionEventAction == MotionEvent.ACTION_DOWN) {
rect.set(0, 0, v.getWidth(), v.getHeight());
}
- boolean isCancelled = event.getAction() == MotionEvent.ACTION_CANCEL
- || !rect.contains(event.getX(), event.getY());
- if (event.getAction() == MotionEvent.ACTION_MOVE && !isCancelled) return false;
- int motionEventAction = event.getAction();
+ boolean isCancelled = motionEventAction == MotionEvent.ACTION_CANCEL
+ || (!rect.contains(event.getX(), event.getY())
+ && (motionEventAction == MotionEvent.ACTION_MOVE
+ || motionEventAction == MotionEvent.ACTION_UP));
+ if (motionEventAction != MotionEvent.ACTION_DOWN
+ && motionEventAction != MotionEvent.ACTION_UP && !isCancelled) {
+ // return early. we don't care about any other cases than DOWN, UP and CANCEL
+ return false;
+ }
int keyEventAction = motionEventAction == MotionEvent.ACTION_DOWN
? KeyEvent.ACTION_DOWN : ACTION_UP;
navButtonController.sendBackKeyEvent(keyEventAction, isCancelled);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 0f639f9..8e2246b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -196,6 +196,12 @@
private boolean mIsFullscreen;
// The size we should return to when we call setTaskbarWindowFullscreen(false)
private int mLastRequestedNonFullscreenSize;
+ /**
+ * When this is true, the taskbar window size is not updated. Requests to update the window
+ * size are stored in {@link #mLastRequestedNonFullscreenSize} and will take effect after
+ * bubbles no longer animate and {@link #setTaskbarWindowForAnimatingBubble()} is called.
+ */
+ private boolean mIsTaskbarSizeFrozenForAnimatingBubble;
private NavigationMode mNavMode;
private boolean mImeDrawsImeNavBar;
@@ -442,6 +448,8 @@
onNavButtonsDarkIntensityChanged(sharedState.navButtonsDarkIntensity);
onNavigationBarLumaSamplingEnabled(sharedState.mLumaSamplingDisplayId,
sharedState.mIsLumaSamplingEnabled);
+ setWallpaperVisible(sharedState.wallpaperVisible);
+ onTransitionModeUpdated(sharedState.barMode, true /* checkBarModes */);
if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
// W/ the flag not set this entire class gets re-created, which resets the value of
@@ -496,6 +504,13 @@
return getBubbleControllers() != null && BubbleBarController.isBubbleBarEnabled();
}
+ private boolean isBubbleBarAnimating() {
+ return mControllers
+ .bubbleControllers
+ .map(controllers -> controllers.bubbleBarViewController.isAnimatingNewBubble())
+ .orElse(false);
+ }
+
/**
* Returns if software keyboard is docked or input toolbar is placed at the taskbar area
*/
@@ -892,7 +907,8 @@
ActivityOptions options = ActivityOptions.makeRemoteTransition(
new RemoteTransition(
new DesktopAppLaunchTransition(
- /* context= */ this, getMainExecutor(), launchType)));
+ /* context= */ this, getMainExecutor(), launchType),
+ "TaskbarDesktopLaunch"));
return new ActivityOptionsWrapper(options, new RunnableList());
}
@@ -1062,6 +1078,25 @@
}
/**
+ * Updates the taskbar window size according to whether bubbles are animating.
+ *
+ * <p>This method should be called when bubbles start animating and again after the animation is
+ * complete.
+ */
+ public void setTaskbarWindowForAnimatingBubble() {
+ if (isBubbleBarAnimating()) {
+ // the default window size accounts for the bubble flyout
+ setTaskbarWindowSize(getDefaultTaskbarWindowSize());
+ mIsTaskbarSizeFrozenForAnimatingBubble = true;
+ } else {
+ mIsTaskbarSizeFrozenForAnimatingBubble = false;
+ setTaskbarWindowSize(
+ mLastRequestedNonFullscreenSize != 0
+ ? mLastRequestedNonFullscreenSize : getDefaultTaskbarWindowSize());
+ }
+ }
+
+ /**
* Called when drag ends or when a view is removed from the DragLayer.
*/
void onDragEndOrViewRemoved() {
@@ -1097,11 +1132,13 @@
size = mDeviceProfile.heightPx;
} else {
mLastRequestedNonFullscreenSize = size;
- if (mIsFullscreen) {
- // We still need to be fullscreen, so defer any change to our height until we call
- // setTaskbarWindowFullscreen(false). For example, this could happen when dragging
- // from the gesture region, as the drag will cancel the gesture and reset launcher's
- // state, which in turn normally would reset the taskbar window height as well.
+ if (mIsFullscreen || mIsTaskbarSizeFrozenForAnimatingBubble) {
+ // We either still need to be fullscreen or a bubble is still animating, so defer
+ // any change to our height until setTaskbarWindowFullscreen(false) is called or
+ // setTaskbarWindowForAnimatingBubble() is called after the bubble animation
+ // completed. For example, this could happen when dragging from the gesture region,
+ // as the drag will cancel the gesture and reset launcher's state, which in turn
+ // normally would reset the taskbar window height as well.
return;
}
}
@@ -1285,9 +1322,25 @@
} else if (tag instanceof TaskItemInfo info) {
RemoteTransition remoteTransition = canUnminimizeDesktopTask(info.getTaskId())
? createUnminimizeRemoteTransition() : null;
- UI_HELPER_EXECUTOR.execute(() ->
- SystemUiProxy.INSTANCE.get(this).showDesktopApp(
- info.getTaskId(), remoteTransition));
+
+ if (areDesktopTasksVisible() && recents != null) {
+ TaskView taskView = recents.getTaskViewByTaskId(info.getTaskId());
+ if (taskView == null) return;
+ RunnableList runnableList = taskView.launchWithAnimation();
+ if (runnableList != null) {
+ runnableList.add(() ->
+ // wrapped it in runnable here since we need the post for DW to be
+ // ready. if we don't other DW will be gone and only the launched task
+ // will show.
+ UI_HELPER_EXECUTOR.execute(() ->
+ SystemUiProxy.INSTANCE.get(this).showDesktopApp(
+ info.getTaskId(), remoteTransition)));
+ }
+ } else {
+ UI_HELPER_EXECUTOR.execute(() ->
+ SystemUiProxy.INSTANCE.get(this).showDesktopApp(
+ info.getTaskId(), remoteTransition));
+ }
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(
/* stash= */ true);
} else if (tag instanceof WorkspaceItemInfo) {
@@ -1445,8 +1498,8 @@
private RemoteTransition createUnminimizeRemoteTransition() {
return new RemoteTransition(
- new DesktopAppLaunchTransition(
- this, getMainExecutor(), AppLaunchType.UNMINIMIZE));
+ new DesktopAppLaunchTransition(this, getMainExecutor(), AppLaunchType.UNMINIMIZE),
+ "TaskbarDesktopUnminimize");
}
/**
@@ -1531,7 +1584,17 @@
.launchAppPair((AppPairIcon) launchingIconView,
-1 /*cuj*/)));
} else {
- startItemInfoActivity(itemInfos.get(0), foundTask);
+ if (areDesktopTasksVisible()) {
+ RunnableList runnableList = recents.launchDesktopTaskView();
+ // Wrapping it in runnable so we post after DW is ready for the app
+ // launch.
+ if (runnableList != null) {
+ runnableList.add(() -> UI_HELPER_EXECUTOR.execute(
+ () -> startItemInfoActivity(itemInfos.get(0), foundTask)));
+ }
+ } else {
+ startItemInfoActivity(itemInfos.get(0), foundTask);
+ }
}
}
);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
index bdc7f92..444c356 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
@@ -49,6 +49,8 @@
public static final int FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS = 1 << 6;
// User has multi instance window open.
public static final int FLAG_AUTOHIDE_SUSPEND_MULTI_INSTANCE_MENU_OPEN = 1 << 7;
+ // User has taskbar overflow open.
+ public static final int FLAG_AUTOHIDE_SUSPEND_TASKBAR_OVERFLOW = 1 << 8;
@IntDef(flag = true, value = {
FLAG_AUTOHIDE_SUSPEND_FULLSCREEN,
@@ -59,6 +61,7 @@
FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR,
FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS,
FLAG_AUTOHIDE_SUSPEND_MULTI_INSTANCE_MENU_OPEN,
+ FLAG_AUTOHIDE_SUSPEND_TASKBAR_OVERFLOW,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AutohideSuspendFlag {}
@@ -138,6 +141,8 @@
"FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR");
appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_MULTI_INSTANCE_MENU_OPEN,
"FLAG_AUTOHIDE_SUSPEND_MULTI_INSTANCE_MENU_OPEN");
+ appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_TASKBAR_OVERFLOW,
+ "FLAG_AUTOHIDE_SUSPEND_TASKBAR_OVERFLOW");
return str.toString();
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 2db7961..250e33a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -1018,7 +1018,12 @@
@Override
public void onRecentsAnimationFinished(RecentsAnimationController controller) {
- endGestureStateOverride(!controller.getFinishTargetIsLauncher(), false /*canceled*/);
+ endGestureStateOverride(!controller.getFinishTargetIsLauncher(),
+ controller.getLauncherIsVisibleAtFinish(), false /*canceled*/);
+ }
+
+ private void endGestureStateOverride(boolean finishedToApp, boolean canceled) {
+ endGestureStateOverride(finishedToApp, finishedToApp, canceled);
}
/**
@@ -1028,11 +1033,13 @@
*
* @param finishedToApp {@code true} if the recents animation finished to showing an app and
* not workspace or overview
+ * @param launcherIsVisible {code true} if launcher is visible at finish
* @param canceled {@code true} if the recents animation was canceled instead of
* finishing
* to completion
*/
- private void endGestureStateOverride(boolean finishedToApp, boolean canceled) {
+ private void endGestureStateOverride(boolean finishedToApp, boolean launcherIsVisible,
+ boolean canceled) {
mCallbacks.removeListener(this);
mTaskBarRecentsAnimationListener = null;
((RecentsView) mLauncher.getOverviewPanel()).setTaskLaunchListener(null);
@@ -1041,18 +1048,27 @@
mSkipNextRecentsAnimEnd = false;
return;
}
- updateStateForUserFinishedToApp(finishedToApp);
+ updateStateForUserFinishedToApp(finishedToApp, launcherIsVisible);
}
}
/**
+ * @see #updateStateForUserFinishedToApp(boolean, boolean)
+ */
+ private void updateStateForUserFinishedToApp(boolean finishedToApp) {
+ updateStateForUserFinishedToApp(finishedToApp, !finishedToApp);
+ }
+
+ /**
* Updates the visible state immediately to ensure a seamless handoff.
*
* @param finishedToApp True iff user is in an app.
+ * @param launcherIsVisible True iff launcher is still visible (ie. transparent app)
*/
- private void updateStateForUserFinishedToApp(boolean finishedToApp) {
+ private void updateStateForUserFinishedToApp(boolean finishedToApp,
+ boolean launcherIsVisible) {
// Update the visible state immediately to ensure a seamless handoff
- boolean launcherVisible = !finishedToApp;
+ boolean launcherVisible = !finishedToApp || launcherIsVisible;
updateStateForFlag(FLAG_TRANSITION_TO_VISIBLE, false);
updateStateForFlag(FLAG_VISIBLE, launcherVisible);
applyState();
@@ -1061,7 +1077,7 @@
if (DEBUG) {
Log.d(TAG, "endGestureStateOverride - FLAG_IN_APP: " + finishedToApp);
}
- controller.updateStateForFlag(FLAG_IN_APP, finishedToApp);
+ controller.updateStateForFlag(FLAG_IN_APP, finishedToApp && !launcherIsVisible);
controller.applyState();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index ff8e4a8..9407e73 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -113,7 +113,7 @@
private static final Uri NAV_BAR_KIDS_MODE = Settings.Secure.getUriFor(
Settings.Secure.NAV_BAR_KIDS_MODE);
- private final Context mContext;
+ private final Context mWindowContext;
private final @Nullable Context mNavigationBarPanelContext;
private WindowManager mWindowManager;
private boolean mAddedWindow;
@@ -231,7 +231,7 @@
@NonNull DesktopVisibilityController desktopVisibilityController) {
Display display =
context.getSystemService(DisplayManager.class).getDisplay(context.getDisplayId());
- mContext = context.createWindowContext(display,
+ mWindowContext = context.createWindowContext(display,
ENABLE_TASKBAR_NAVBAR_UNIFICATION ? TYPE_NAVIGATION_BAR : TYPE_NAVIGATION_BAR_PANEL,
null);
mAllAppsActionManager = allAppsActionManager;
@@ -240,30 +240,47 @@
: null;
mDesktopVisibilityController = desktopVisibilityController;
if (enableTaskbarNoRecreate()) {
- mWindowManager = mContext.getSystemService(WindowManager.class);
- FrameLayout taskbarRootLayout = new FrameLayout(mContext) {
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- // The motion events can be outside the view bounds of task bar, and hence
- // manually dispatching them to the drag layer here.
- TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
- if (taskbar != null && taskbar.getDragLayer().isAttachedToWindow()) {
- return taskbar.getDragLayer().dispatchTouchEvent(ev);
- }
- return super.dispatchTouchEvent(ev);
- }
- };
- addTaskbarRootLayoutToMap(getDefaultDisplayId(), taskbarRootLayout);
+ mWindowManager = mWindowContext.getSystemService(WindowManager.class);
+ createTaskbarRootLayout(getDefaultDisplayId());
}
- mDefaultNavButtonController = new TaskbarNavButtonController(
+ mDefaultNavButtonController = createDefaultNavButtonController(context, navCallbacks);
+ mDefaultComponentCallbacks = createDefaultComponentCallbacks();
+ SettingsCache.INSTANCE.get(mWindowContext)
+ .register(USER_SETUP_COMPLETE_URI, mOnSettingsChangeListener);
+ SettingsCache.INSTANCE.get(mWindowContext)
+ .register(NAV_BAR_KIDS_MODE, mOnSettingsChangeListener);
+ Log.d(TASKBAR_NOT_DESTROYED_TAG, "registering component callbacks from constructor.");
+ mWindowContext.registerComponentCallbacks(mDefaultComponentCallbacks);
+ mShutdownReceiver.register(mWindowContext, Intent.ACTION_SHUTDOWN);
+ UI_HELPER_EXECUTOR.execute(() -> {
+ mSharedState.taskbarSystemActionPendingIntent = PendingIntent.getBroadcast(
+ mWindowContext,
+ SYSTEM_ACTION_ID_TASKBAR,
+ new Intent(ACTION_SHOW_TASKBAR).setPackage(mWindowContext.getPackageName()),
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+ mTaskbarBroadcastReceiver.register(
+ mWindowContext, RECEIVER_NOT_EXPORTED, ACTION_SHOW_TASKBAR);
+ });
+
+ debugWhyTaskbarNotDestroyed("TaskbarManager created");
+ recreateTaskbar();
+ }
+
+ @NonNull
+ private TaskbarNavButtonController createDefaultNavButtonController(Context context,
+ TaskbarNavButtonCallbacks navCallbacks) {
+ return new TaskbarNavButtonController(
context,
navCallbacks,
- SystemUiProxy.INSTANCE.get(mContext),
- ContextualEduStatsManager.INSTANCE.get(mContext),
+ SystemUiProxy.INSTANCE.get(mWindowContext),
+ ContextualEduStatsManager.INSTANCE.get(mWindowContext),
new Handler(),
- new ContextualSearchInvoker(mContext));
- mDefaultComponentCallbacks = new ComponentCallbacks() {
- private Configuration mOldConfig = mContext.getResources().getConfiguration();
+ new ContextualSearchInvoker(mWindowContext));
+ }
+
+ private ComponentCallbacks createDefaultComponentCallbacks() {
+ return new ComponentCallbacks() {
+ private Configuration mOldConfig = mWindowContext.getResources().getConfiguration();
@Override
public void onConfigurationChanged(Configuration newConfig) {
@@ -273,7 +290,7 @@
"TaskbarManager#mComponentCallbacks.onConfigurationChanged: " + newConfig);
// TODO: adapt this logic to be specific to different displays.
DeviceProfile dp = mUserUnlocked
- ? LauncherAppState.getIDP(mContext).getDeviceProfile(mContext)
+ ? LauncherAppState.getIDP(mWindowContext).getDeviceProfile(mWindowContext)
: null;
int configDiff = mOldConfig.diff(newConfig) & ~SKIP_RECREATE_CONFIG_CHANGES;
@@ -317,25 +334,6 @@
@Override
public void onLowMemory() { }
};
- SettingsCache.INSTANCE.get(mContext)
- .register(USER_SETUP_COMPLETE_URI, mOnSettingsChangeListener);
- SettingsCache.INSTANCE.get(mContext)
- .register(NAV_BAR_KIDS_MODE, mOnSettingsChangeListener);
- Log.d(TASKBAR_NOT_DESTROYED_TAG, "registering component callbacks from constructor.");
- mContext.registerComponentCallbacks(mDefaultComponentCallbacks);
- mShutdownReceiver.register(mContext, Intent.ACTION_SHUTDOWN);
- UI_HELPER_EXECUTOR.execute(() -> {
- mSharedState.taskbarSystemActionPendingIntent = PendingIntent.getBroadcast(
- mContext,
- SYSTEM_ACTION_ID_TASKBAR,
- new Intent(ACTION_SHOW_TASKBAR).setPackage(mContext.getPackageName()),
- PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
- mTaskbarBroadcastReceiver.register(
- mContext, RECEIVER_NOT_EXPORTED, ACTION_SHOW_TASKBAR);
- });
-
- debugWhyTaskbarNotDestroyed("TaskbarManager created");
- recreateTaskbar();
}
private void destroyAllTaskbars() {
@@ -360,7 +358,7 @@
removeTaskbarFromMap(displayId);
}
DeviceProfile dp = mUserUnlocked ?
- LauncherAppState.getIDP(mContext).getDeviceProfile(mContext) : null;
+ LauncherAppState.getIDP(mWindowContext).getDeviceProfile(mWindowContext) : null;
if (dp == null || !isTaskbarEnabled(dp)) {
removeTaskbarRootViewFromWindow(displayId);
}
@@ -407,7 +405,7 @@
*/
public void onUserUnlocked() {
mUserUnlocked = true;
- DisplayController.INSTANCE.get(mContext).addChangeListener(mRecreationListener);
+ DisplayController.INSTANCE.get(mWindowContext).addChangeListener(mRecreationListener);
recreateTaskbar();
addTaskbarRootViewToWindow(getDefaultDisplayId());
}
@@ -470,7 +468,7 @@
return ql.getUnfoldTransitionProgressProvider();
}
} else {
- return SystemUiProxy.INSTANCE.get(mContext).getUnfoldTransitionProvider();
+ return SystemUiProxy.INSTANCE.get(mWindowContext).getUnfoldTransitionProvider();
}
return null;
}
@@ -514,7 +512,7 @@
Trace.beginSection("recreateTaskbar");
try {
DeviceProfile dp = mUserUnlocked ?
- LauncherAppState.getIDP(mContext).getDeviceProfile(mContext) : null;
+ LauncherAppState.getIDP(mWindowContext).getDeviceProfile(mWindowContext) : null;
// All Apps action is unrelated to navbar unification, so we only need to check DP.
final boolean isLargeScreenTaskbar = dp != null && dp.isTaskbarPresent;
@@ -528,7 +526,7 @@
+ " FLAG_HIDE_NAVBAR_WINDOW=" + ENABLE_TASKBAR_NAVBAR_UNIFICATION
+ " dp.isTaskbarPresent=" + (dp == null ? "null" : dp.isTaskbarPresent));
if (!isTaskbarEnabled || !isLargeScreenTaskbar) {
- SystemUiProxy.INSTANCE.get(mContext)
+ SystemUiProxy.INSTANCE.get(mWindowContext)
.notifyTaskbarStatus(/* visible */ false, /* stashed */ false);
if (!isTaskbarEnabled) {
return;
@@ -537,9 +535,7 @@
TaskbarActivityContext taskbar = getTaskbarForDisplay(displayId);
if (enableTaskbarNoRecreate() || taskbar == null) {
- taskbar = new TaskbarActivityContext(mContext,
- mNavigationBarPanelContext, dp, mDefaultNavButtonController,
- mUnfoldProgressProvider, mDesktopVisibilityController);
+ taskbar = createTaskbarActivityContext(dp, displayId);
} else {
taskbar.updateDeviceProfile(dp);
}
@@ -560,7 +556,6 @@
taskbarRootLayout.addView(taskbar.getDragLayer());
taskbar.notifyUpdateLayoutParams();
}
- addTaskbarToMap(displayId, taskbar);
} finally {
Trace.endSection();
}
@@ -716,22 +711,23 @@
mRecentsViewContainer = null;
debugWhyTaskbarNotDestroyed("TaskbarManager#destroy()");
removeActivityCallbacksAndListeners();
- mTaskbarBroadcastReceiver.unregisterReceiverSafely(mContext);
+ mTaskbarBroadcastReceiver.unregisterReceiverSafely(mWindowContext);
destroyAllTaskbars();
if (mUserUnlocked) {
- DisplayController.INSTANCE.get(mContext).removeChangeListener(mRecreationListener);
+ DisplayController.INSTANCE.get(mWindowContext).removeChangeListener(
+ mRecreationListener);
}
- SettingsCache.INSTANCE.get(mContext)
+ SettingsCache.INSTANCE.get(mWindowContext)
.unregister(USER_SETUP_COMPLETE_URI, mOnSettingsChangeListener);
- SettingsCache.INSTANCE.get(mContext)
+ SettingsCache.INSTANCE.get(mWindowContext)
.unregister(NAV_BAR_KIDS_MODE, mOnSettingsChangeListener);
Log.d(TASKBAR_NOT_DESTROYED_TAG, "unregistering component callbacks from destroy().");
- mContext.unregisterComponentCallbacks(mDefaultComponentCallbacks);
- mShutdownReceiver.unregisterReceiverSafely(mContext);
+ mWindowContext.unregisterComponentCallbacks(mDefaultComponentCallbacks);
+ mShutdownReceiver.unregisterReceiverSafely(mWindowContext);
}
public @Nullable TaskbarActivityContext getCurrentActivityContext() {
- return getTaskbarForDisplay(mContext.getDisplayId());
+ return getTaskbarForDisplay(mWindowContext.getDisplayId());
}
public void dumpLogs(String prefix, PrintWriter pw) {
@@ -773,6 +769,19 @@
return mTaskbars.get(displayId);
}
+
+ /**
+ * Creates a {@link TaskbarActivityContext} for the given display and adds it to the map.
+ */
+ private TaskbarActivityContext createTaskbarActivityContext(DeviceProfile dp, int displayId) {
+ TaskbarActivityContext newTaskbar = new TaskbarActivityContext(mWindowContext,
+ mNavigationBarPanelContext, dp, mDefaultNavButtonController,
+ mUnfoldProgressProvider, mDesktopVisibilityController);
+
+ addTaskbarToMap(displayId, newTaskbar);
+ return newTaskbar;
+ }
+
/**
* Adds the {@link TaskbarActivityContext} associated with the given display ID to taskbar
* map if there is not already a taskbar mapped to that displayId.
@@ -796,6 +805,26 @@
}
/**
+ * Creates {@link FrameLayout} for the taskbar on the specified display and adds it to map.
+ * @param displayId The ID of the display for which to create the taskbar root layout.
+ */
+ private void createTaskbarRootLayout(int displayId) {
+ FrameLayout newTaskbarRootLayout = new FrameLayout(mWindowContext) {
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ // The motion events can be outside the view bounds of task bar, and hence
+ // manually dispatching them to the drag layer here.
+ TaskbarActivityContext taskbar = getTaskbarForDisplay(getDefaultDisplayId());
+ if (taskbar != null && taskbar.getDragLayer().isAttachedToWindow()) {
+ return taskbar.getDragLayer().dispatchTouchEvent(ev);
+ }
+ return super.dispatchTouchEvent(ev);
+ }
+ };
+ addTaskbarRootLayoutToMap(displayId, newTaskbarRootLayout);
+ }
+
+ /**
* Retrieves the root layout of the taskbar for the specified display.
*
* @param displayId The ID of the display for which to retrieve the taskbar root layout.
@@ -812,7 +841,7 @@
* @param rootLayout The taskbar root layout {@link FrameLayout} to add to the map.
*/
private void addTaskbarRootLayoutToMap(int displayId, FrameLayout rootLayout) {
- if (!mRootLayouts.contains(displayId)) {
+ if (!mRootLayouts.contains(displayId) && rootLayout != null) {
mRootLayouts.put(displayId, rootLayout);
}
}
@@ -829,7 +858,7 @@
}
private int getDefaultDisplayId() {
- return mContext.getDisplayId();
+ return mWindowContext.getDisplayId();
}
/** Temp logs for b/254119092. */
@@ -839,15 +868,15 @@
boolean activityTaskbarPresent = mActivity != null
&& mActivity.getDeviceProfile().isTaskbarPresent;
- boolean contextTaskbarPresent = mUserUnlocked
- && LauncherAppState.getIDP(mContext).getDeviceProfile(mContext).isTaskbarPresent;
+ boolean contextTaskbarPresent = mUserUnlocked && LauncherAppState.getIDP(mWindowContext)
+ .getDeviceProfile(mWindowContext).isTaskbarPresent;
if (activityTaskbarPresent == contextTaskbarPresent) {
- log.add("mActivity and mContext agree taskbarIsPresent=" + contextTaskbarPresent);
+ log.add("mActivity and mWindowContext agree taskbarIsPresent=" + contextTaskbarPresent);
Log.d(TASKBAR_NOT_DESTROYED_TAG, log.toString());
return;
}
- log.add("mActivity and mContext device profiles have different values, add more logs.");
+ log.add("mActivity & mWindowContext device profiles have different values, add more logs.");
log.add("\tmActivity logs:");
log.add("\t\tmActivity=" + mActivity);
@@ -857,13 +886,13 @@
log.add("\t\tmActivity.getDeviceProfile().isTaskbarPresent="
+ activityTaskbarPresent);
}
- log.add("\tmContext logs:");
- log.add("\t\tmContext=" + mContext);
- log.add("\t\tmContext.getResources().getConfiguration()="
- + mContext.getResources().getConfiguration());
+ log.add("\tmWindowContext logs:");
+ log.add("\t\tmWindowContext=" + mWindowContext);
+ log.add("\t\tmWindowContext.getResources().getConfiguration()="
+ + mWindowContext.getResources().getConfiguration());
if (mUserUnlocked) {
- log.add("\t\tLauncherAppState.getIDP().getDeviceProfile(mContext).isTaskbarPresent="
- + contextTaskbarPresent);
+ log.add("\t\tLauncherAppState.getIDP().getDeviceProfile(mWindowContext)"
+ + ".isTaskbarPresent=" + contextTaskbarPresent);
} else {
log.add("\t\tCouldn't get DeviceProfile because !mUserUnlocked");
}
@@ -876,6 +905,6 @@
@VisibleForTesting
public Context getWindowContext() {
- return mContext;
+ return mWindowContext;
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarOverflowView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarOverflowView.java
index 8775766..0ed6669 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarOverflowView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarOverflowView.java
@@ -35,6 +35,7 @@
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
import androidx.core.graphics.ColorUtils;
import com.android.app.animation.Interpolators;
@@ -315,6 +316,11 @@
invalidate();
}
+ @VisibleForTesting
+ public List<Integer> getItemIds() {
+ return mItems.stream().map(task -> task.key.id).toList();
+ }
+
/**
* Called when a task is updated. If the task is contained within the view, it's cached value
* gets updated. If the task is shown within the icon, invalidates the view, so the task icon
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index 2e0bae5..abf35a2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR;
import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition;
@@ -309,9 +310,7 @@
*/
SystemShortcut.Factory<BaseTaskbarContext> createNewWindowShortcutFactory() {
return (context, itemInfo, originalView) -> {
- ComponentKey key = itemInfo.getComponentKey();
- AppInfo app = getApp(key);
- if (app != null && app.supportsMultiInstance()) {
+ if (shouldShowMultiInstanceOptions(itemInfo)) {
return new NewWindowTaskbarShortcut<>(context, itemInfo, originalView);
}
return null;
@@ -325,9 +324,7 @@
*/
public SystemShortcut.Factory<BaseTaskbarContext> createManageWindowsShortcutFactory() {
return (context, itemInfo, originalView) -> {
- ComponentKey key = itemInfo.getComponentKey();
- AppInfo app = getApp(key);
- if (app != null && app.supportsMultiInstance()) {
+ if (shouldShowMultiInstanceOptions(itemInfo)) {
return new ManageWindowsTaskbarShortcut<>(context, itemInfo, originalView,
mControllers);
}
@@ -336,6 +333,16 @@
}
/**
+ * Determines whether to show multi-instance options for a given item.
+ */
+ private boolean shouldShowMultiInstanceOptions(ItemInfo itemInfo) {
+ ComponentKey key = itemInfo.getComponentKey();
+ AppInfo app = getApp(key);
+ return app != null && app.supportsMultiInstance()
+ && itemInfo.container != CONTAINER_ALL_APPS;
+ }
+
+ /**
* A single menu item ("Split left," "Split right," or "Split top") that executes a split
* from the taskbar, as if the user performed a drag and drop split.
* Includes an onClick method that initiates the actual split.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 130b9b7..de9eee4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -34,6 +34,7 @@
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import android.util.ArraySet;
import android.util.AttributeSet;
import android.view.DisplayCutout;
import android.view.InputDevice;
@@ -74,8 +75,10 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
import java.util.function.Predicate;
/**
@@ -134,6 +137,8 @@
private final int mNumStaticViews;
+ private Set<GroupTask> mPrevRecentTasks = Collections.emptySet();
+
public TaskbarView(@NonNull Context context) {
this(context, null);
}
@@ -458,7 +463,7 @@
// Skip static views and potential All Apps divider, if they are on the left.
mNextViewIndex = mIsRtl ? 0 : mNumStaticViews;
- if (getChildAt(mNextViewIndex) == mTaskbarDividerContainer) {
+ if (getChildAt(mNextViewIndex) == mTaskbarDividerContainer && !mAddedDividerForRecents) {
mNextViewIndex++;
}
@@ -613,7 +618,7 @@
// accounted for when comparing current icon count to max number of icons.
int nonTaskIconsToBeAdded = 1;
- boolean supportsOverflow = Flags.taskbarOverflow();
+ boolean supportsOverflow = Flags.taskbarOverflow() && recentTasks.size() > 1;
int overflowSize = 0;
if (supportsOverflow) {
mIdealNumIcons = mNextViewIndex + recentTasks.size() + nonTaskIconsToBeAdded;
@@ -636,6 +641,7 @@
}
// Add Recent/Running icons.
+ final Set<GroupTask> recentTasksSet = new ArraySet<>(recentTasks);
for (GroupTask task : recentTasks) {
if (mTaskbarOverflowView != null && overflownTasks != null
&& overflownTasks.size() < itemsToAddToOverflow) {
@@ -664,12 +670,18 @@
}
View recentIcon = null;
- while (isNextViewInSection(GroupTask.class)) {
+ // If a task is new, we should not reuse a view so that it animates in when it is added.
+ final boolean canReuseView = !taskbarRecentsLayoutTransition()
+ || mPrevRecentTasks.contains(task);
+ while (canReuseView && isNextViewInSection(GroupTask.class)) {
recentIcon = getChildAt(mNextViewIndex);
// see if the view can be reused
if ((recentIcon.getSourceLayoutResId() != expectedLayoutResId)
- || (isCollection && (recentIcon.getTag() != task))) {
+ || (isCollection && (recentIcon.getTag() != task))
+ // Remove view corresponding to removed task so that it animates out.
+ || (taskbarRecentsLayoutTransition()
+ && !recentTasksSet.contains(recentIcon.getTag()))) {
removeAndRecycle(recentIcon);
recentIcon = null;
} else {
@@ -699,6 +711,8 @@
while (isNextViewInSection(GroupTask.class)) {
removeAndRecycle(getChildAt(mNextViewIndex));
}
+
+ mPrevRecentTasks = recentTasksSet;
}
private boolean isNextViewInSection(Class<?> tagClass) {
@@ -839,6 +853,8 @@
iconEnd += mAllAppsButtonTranslationOffset;
}
+ mControllerCallbacks.onPreLayoutChildren();
+
int count = getChildCount();
for (int i = count; i > 0; i--) {
View child = getChildAt(i - 1);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
index 4d77ab2..c7841c1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
@@ -16,8 +16,11 @@
package com.android.launcher3.taskbar;
+import static com.android.launcher3.Flags.taskbarRecentsLayoutTransition;
+import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_LONG_PRESS;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP;
+import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_TASKBAR_OVERFLOW;
import android.annotation.SuppressLint;
import android.content.Context;
@@ -109,6 +112,13 @@
return new TaskbarHoverToolTipController(mActivity, mTaskbarView, icon);
}
+ /** Callback invoked before Taskbar icons are laid out. */
+ void onPreLayoutChildren() {
+ if (enableTaskbarPinning() && taskbarRecentsLayoutTransition()) {
+ mControllers.taskbarViewController.updateTaskbarIconTranslationXForPinning();
+ }
+ }
+
/**
* Notifies launcher to update icon alignment.
*/
@@ -180,6 +190,9 @@
if (mTaskbarView.getTaskbarOverflowView() != null) {
mTaskbarView.getTaskbarOverflowView().setIsActive(
!mTaskbarView.getTaskbarOverflowView().getIsActive());
+ mControllers.taskbarAutohideSuspendController
+ .updateFlag(FLAG_AUTOHIDE_SUSPEND_TASKBAR_OVERFLOW,
+ mTaskbarView.getTaskbarOverflowView().getIsActive());
}
mControllers.keyboardQuickSwitchController.toggleQuickSwitchViewForTaskbar(
mControllers.taskbarViewController.getTaskIdsForPinnedApps(),
@@ -190,6 +203,8 @@
if (mTaskbarView.getTaskbarOverflowView() != null) {
mTaskbarView.getTaskbarOverflowView().setIsActive(false);
}
+ mControllers.taskbarAutohideSuspendController.updateFlag(
+ FLAG_AUTOHIDE_SUSPEND_TASKBAR_OVERFLOW, false);
}
private float getDividerCenterX() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 4acf2fe..89f4f59 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -15,10 +15,17 @@
*/
package com.android.launcher3.taskbar;
+import static android.animation.LayoutTransition.APPEARING;
+import static android.animation.LayoutTransition.CHANGE_APPEARING;
+import static android.animation.LayoutTransition.CHANGE_DISAPPEARING;
+import static android.animation.LayoutTransition.DISAPPEARING;
+
+import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.app.animation.Interpolators.FINAL_FRAME;
import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.Flags.taskbarOverflow;
+import static com.android.launcher3.Flags.taskbarRecentsLayoutTransition;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
@@ -40,13 +47,17 @@
import android.animation.Animator;
import android.animation.AnimatorSet;
+import android.animation.LayoutTransition;
+import android.animation.LayoutTransition.TransitionListener;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.graphics.Rect;
+import android.util.FloatProperty;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewGroup;
import android.view.animation.Interpolator;
import androidx.annotation.Nullable;
@@ -74,6 +85,7 @@
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.util.MultiPropertyFactory;
+import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.util.MultiTranslateDelegate;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.quickstep.util.GroupTask;
@@ -114,6 +126,11 @@
/** Used if an unexpected edge case is hit in {@link #getPositionInHotseat}. */
private static final float ERROR_POSITION_IN_HOTSEAT_NOT_FOUND = -100;
+ private static final int TRANSITION_DELAY = 50;
+ private static final int TRANSITION_DEFAULT_DURATION = 500;
+ private static final int TRANSITION_FADE_IN_DURATION = 167;
+ private static final int TRANSITION_FADE_OUT_DURATION = 83;
+
private static boolean sEnableModelLoadingForTests = true;
private final TaskbarActivityContext mActivity;
@@ -158,7 +175,9 @@
private final View.OnLayoutChangeListener mTaskbarViewLayoutChangeListener =
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
- updateTaskbarIconTranslationXForPinning();
+ if (!taskbarRecentsLayoutTransition()) {
+ updateTaskbarIconTranslationXForPinning();
+ }
if (BubbleBarController.isBubbleBarEnabled()) {
mControllers.navbarButtonsViewController.onLayoutsUpdated();
}
@@ -432,7 +451,7 @@
}
}
- private void updateTaskbarIconTranslationXForPinning() {
+ void updateTaskbarIconTranslationXForPinning() {
View[] iconViews = mTaskbarView.getIconViews();
float scale = mTaskbarIconTranslationXForPinning.value;
float transientTaskbarAllAppsOffset = mActivity.getResources().getDimension(
@@ -1076,6 +1095,89 @@
/** Called when there's a change in running apps to update the UI. */
public void commitRunningAppsToUI() {
mModelCallbacks.commitRunningAppsToUI();
+ if (taskbarRecentsLayoutTransition() && mTaskbarView.getLayoutTransition() == null) {
+ // Set up after the first commit so that the initial recents do not animate (janky).
+ mTaskbarView.setLayoutTransition(createLayoutTransitionForRunningApps());
+ }
+ }
+
+ private LayoutTransition createLayoutTransitionForRunningApps() {
+ LayoutTransition layoutTransition = new LayoutTransition();
+ layoutTransition.setDuration(TRANSITION_DEFAULT_DURATION);
+ layoutTransition.addTransitionListener(new TransitionListener() {
+
+ @Override
+ public void startTransition(
+ LayoutTransition transition, ViewGroup container, View view, int type) {
+ if (type == APPEARING) {
+ view.setAlpha(0f);
+ view.setScaleX(0f);
+ view.setScaleY(0f);
+ }
+ }
+
+ @Override
+ public void endTransition(
+ LayoutTransition transition, ViewGroup container, View view, int type) {
+ // Do nothing.
+ }
+ });
+
+ // Appearing.
+ AnimatorSet appearingSet = new AnimatorSet();
+ Animator appearingAlphaAnimator = ObjectAnimator.ofFloat(null, "alpha", 0f, 1f);
+ appearingAlphaAnimator.setInterpolator(Interpolators.clampToProgress(LINEAR, 0f,
+ (float) TRANSITION_FADE_IN_DURATION / TRANSITION_DEFAULT_DURATION));
+ Animator appearingScaleAnimator = ObjectAnimator.ofFloat(null, SCALE_PROPERTY, 0f, 1f);
+ appearingScaleAnimator.setInterpolator(EMPHASIZED);
+ appearingSet.playTogether(appearingAlphaAnimator, appearingScaleAnimator);
+ layoutTransition.setAnimator(APPEARING, appearingSet);
+ layoutTransition.setStartDelay(APPEARING, TRANSITION_DELAY);
+
+ // Disappearing.
+ AnimatorSet disappearingSet = new AnimatorSet();
+ Animator disappearingAlphaAnimator = ObjectAnimator.ofFloat(null, "alpha", 1f, 0f);
+ disappearingAlphaAnimator.setInterpolator(Interpolators.clampToProgress(LINEAR,
+ (float) TRANSITION_DELAY / TRANSITION_DEFAULT_DURATION,
+ (float) (TRANSITION_DELAY + TRANSITION_FADE_OUT_DURATION)
+ / TRANSITION_DEFAULT_DURATION));
+ Animator disappearingScaleAnimator = ObjectAnimator.ofFloat(null, SCALE_PROPERTY, 1f, 0f);
+ disappearingScaleAnimator.setInterpolator(EMPHASIZED);
+ disappearingSet.playTogether(disappearingAlphaAnimator, disappearingScaleAnimator);
+ layoutTransition.setAnimator(DISAPPEARING, disappearingSet);
+
+ // Change transitions.
+ FloatProperty<View> translateXPinning = new FloatProperty<>("translateXPinning") {
+ @Override
+ public void setValue(View view, float value) {
+ getTranslationXForPinning(view).setValue(value);
+ }
+
+ @Override
+ public Float get(View view) {
+ return getTranslationXForPinning(view).getValue();
+ }
+
+ private MultiProperty getTranslationXForPinning(View view) {
+ return ((Reorderable) view).getTranslateDelegate()
+ .getTranslationX(INDEX_TASKBAR_PINNING_ANIM);
+ }
+ };
+ AnimatorSet changeSet = new AnimatorSet();
+ changeSet.playTogether(
+ layoutTransition.getAnimator(CHANGE_APPEARING),
+ ObjectAnimator.ofFloat(null, translateXPinning, 0f, 1f));
+
+ // Change appearing.
+ layoutTransition.setAnimator(CHANGE_APPEARING, changeSet);
+ layoutTransition.setInterpolator(CHANGE_APPEARING, EMPHASIZED);
+
+ // Change disappearing.
+ layoutTransition.setAnimator(CHANGE_DISAPPEARING, changeSet);
+ layoutTransition.setInterpolator(CHANGE_DISAPPEARING, EMPHASIZED);
+ layoutTransition.setStartDelay(CHANGE_DISAPPEARING, TRANSITION_DELAY);
+
+ return layoutTransition;
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index 987937e..5b3c233 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -405,8 +405,12 @@
mBubbleBarViewController.showOverflow(true);
}
- // Adds and removals have happened, update visibility before any other visual changes.
- mBubbleBarViewController.setHiddenForBubbles(mBubbles.isEmpty());
+ // Update the visibility if this is the initial state or if there are no bubbles.
+ // If this is the initial bubble, the bubble bar will become visible as part of the
+ // animation.
+ if (update.initialState || mBubbles.isEmpty()) {
+ mBubbleBarViewController.setHiddenForBubbles(mBubbles.isEmpty());
+ }
mBubbleStashedHandleViewController.ifPresent(
controller -> controller.setHiddenForBubbles(mBubbles.isEmpty()));
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 67d7901..dd1b0ca 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -170,7 +170,8 @@
mBubbleBarContainer, createFlyoutPositioner(), createFlyoutCallbacks());
mBubbleBarViewAnimator = new BubbleBarViewAnimator(
mBarView, mBubbleStashController, mBubbleBarFlyoutController,
- createBubbleBarParentViewController(), mBubbleBarController::showExpandedView);
+ createBubbleBarParentViewController(), mBubbleBarController::showExpandedView,
+ () -> setHiddenForBubbles(false));
mTaskbarViewPropertiesProvider = taskbarViewPropertiesProvider;
onBubbleBarConfigurationChanged(/* animate= */ false);
mActivity.addOnDeviceProfileChangeListener(
@@ -328,7 +329,7 @@
return new BubbleBarParentViewHeightUpdateNotifier() {
@Override
public void updateTopBoundary() {
- mActivity.setTaskbarWindowSize(mActivity.getDefaultTaskbarWindowSize());
+ mActivity.setTaskbarWindowForAnimatingBubble();
}
};
}
@@ -580,15 +581,23 @@
/** Returns maximum height of the bubble bar with the flyout view. */
public int getBubbleBarWithFlyoutMaximumHeight() {
- if (!isBubbleBarVisible()) return 0;
+ if (!isBubbleBarVisible() && !isAnimatingNewBubble()) return 0;
int bubbleBarTopOnHome = (int) (mBubbleStashController.getBubbleBarVerticalCenterForHome()
- + mBarView.getBubbleBarCollapsedHeight() / 2);
- int result = (int) (bubbleBarTopOnHome + mBarView.getArrowHeight());
+ + mBarView.getBubbleBarCollapsedHeight() / 2 + mBarView.getArrowHeight());
if (isAnimatingNewBubble()) {
- // when animating new bubble add the maximum height of the flyout view
- result += mBubbleBarFlyoutController.getMaximumFlyoutHeight();
+ if (mTaskbarStashController.isInApp() && mBubbleStashController.getHasHandleView()) {
+ // when animating a bubble in an app, the bubble bar will be higher than its
+ // position on home
+ float bubbleBarTopDistanceFromBottom =
+ -mBubbleStashController.getBubbleBarTranslationYForTaskbar()
+ + mBarView.getHeight();
+ return (int) bubbleBarTopDistanceFromBottom
+ + mBubbleBarFlyoutController.getMaximumFlyoutHeight();
+ }
+ return bubbleBarTopOnHome + mBubbleBarFlyoutController.getMaximumFlyoutHeight();
+ } else {
+ return bubbleBarTopOnHome;
}
- return result;
}
/**
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 6f8943f..3bff58b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
@@ -42,6 +42,7 @@
private val bubbleBarFlyoutController: BubbleBarFlyoutController,
private val bubbleBarParentViewHeightUpdateNotifier: BubbleBarParentViewHeightUpdateNotifier,
private val onExpanded: Runnable,
+ private val onBubbleBarVisible: Runnable,
private val scheduler: Scheduler = HandlerScheduler(bubbleBarView),
) {
@@ -397,9 +398,12 @@
// prepare the bubble bar for the animation
bubbleBarView.translationY = bubbleBarView.height.toFloat()
bubbleBarView.visibility = VISIBLE
+ onBubbleBarVisible.run()
bubbleBarView.alpha = 1f
bubbleBarView.scaleX = 1f
bubbleBarView.scaleY = 1f
+ bubbleBarView.setBackgroundScaleX(1f)
+ bubbleBarView.setBackgroundScaleY(1f)
val translationTracker = TranslationTracker(bubbleBarView.translationY)
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
index 63db012..7c718e5b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
@@ -63,8 +63,6 @@
return rect
}
- fun getFlyoutMaxHeight(): Int = BubbleBarFlyoutView.getMaximumViewHeight(container.context)
-
fun setUpAndShowFlyout(message: BubbleBarFlyoutMessage, onInit: () -> Unit, onEnd: () -> Unit) {
flyout?.let(container::removeView)
val flyout = BubbleBarFlyoutView(container.context, positioner, flyoutScheduler)
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
index df00696..3e3f569 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
@@ -224,12 +224,13 @@
override fun isBubbleBarVisible(): Boolean = bubbleBarViewController.hasBubbles() && !isStashed
- override fun onNewBubbleAnimationInterrupted(isStashed: Boolean, bubbleBarTranslationY: Float) =
+ override fun onNewBubbleAnimationInterrupted(isStashed: Boolean, bubbleBarTranslationY: Float) {
if (isStashed) {
stashBubbleBarImmediate()
} else {
showBubbleBarImmediate(bubbleBarTranslationY)
}
+ }
/** Check if [ev] belongs to the stash handle or the bubble bar views. */
override fun isEventOverBubbleBarViews(ev: MotionEvent): Boolean {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 5cb6e86..eeac169 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -601,7 +601,7 @@
case QUICK_SWITCH_STATE_ORDINAL: {
RecentsView rv = getOverviewPanel();
TaskView currentPageTask = rv.getCurrentPageTaskView();
- TaskView fallbackTask = rv.getTaskViewAt(0);
+ TaskView fallbackTask = rv.getFirstTaskView();
if (currentPageTask != null || fallbackTask != null) {
TaskView taskToLaunch = currentPageTask;
if (currentPageTask == null) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt b/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt
index 374db6a..2e2d7cc 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt
+++ b/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt
@@ -63,7 +63,7 @@
override fun createFadeOutAnimOptions(): ActivityOptions =
ActivityOptions.makeBasic().apply {
- remoteTransition = RemoteTransition(FadeOutRemoteTransition())
+ remoteTransition = RemoteTransition(FadeOutRemoteTransition(), "FadeOut")
}
override fun queryAllUsers(): Map<UserHandle, UserIconInfo> {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 9164405..9dec332 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -256,7 +256,7 @@
mRecentsView.setFullscreenProgress(fromState.getOverviewFullscreenProgress());
mLauncher.getActionsView().getVisibilityAlpha().updateValue(
(fromState.getVisibleElements(mLauncher) & OVERVIEW_ACTIONS) != 0 ? 1f : 0f);
- mRecentsView.setTaskIconScaledDown(true);
+ mRecentsView.setTaskIconVisible(false);
float[] scaleAndOffset = toState.getOverviewScaleAndOffset(mLauncher);
// As we drag right, animate the following properties:
@@ -340,7 +340,7 @@
public void onAnimationEnd(Animator animation) {
onAnimationToStateCompleted(OVERVIEW);
// Animate the icon after onAnimationToStateCompleted() so it doesn't clobber.
- mRecentsView.animateUpTaskIconScale();
+ mRecentsView.startIconFadeInOnGestureComplete();
}
});
overviewAnim.start();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
index 4df0f63..8c440b1 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitOverviewStateTouchHelper.java
@@ -50,7 +50,7 @@
boolean canInterceptTouch(MotionEvent ev) {
if (mRecentsView.getTaskViewCount() > 0) {
// Allow swiping up in the gap between the hotseat and overview.
- return ev.getY() >= mRecentsView.getTaskViewAt(0).getBottom();
+ return ev.getY() >= mRecentsView.getFirstTaskView().getBottom();
} else {
// If there are no tasks, we only intercept if we're below the hotseat height.
return isTouchOverHotseat(mLauncher, ev);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index 31e4e33..d673720 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -149,7 +149,7 @@
mOverviewPanel.setFullscreenProgress(progress);
if (progress > UPDATE_SYSUI_FLAGS_THRESHOLD) {
int sysuiFlags = 0;
- TaskView tv = mOverviewPanel.getTaskViewAt(0);
+ TaskView tv = mOverviewPanel.getFirstTaskView();
if (tv != null) {
sysuiFlags = tv.getTaskContainers().getFirst().getSysUiStatusNavFlags();
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 202276e..d622987 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -66,7 +66,7 @@
protected final CONTAINER mContainer;
private final SingleAxisSwipeDetector mDetector;
- private final RecentsView mRecentsView;
+ private final RecentsView<?, ?> mRecentsView;
private final Rect mTempRect = new Rect();
private final boolean mIsRtl;
@@ -157,17 +157,15 @@
} else {
mTaskBeingDragged = null;
- for (int i = 0; i < mRecentsView.getTaskViewCount(); i++) {
- TaskView view = mRecentsView.getTaskViewAt(i);
-
- if (mRecentsView.isTaskViewVisible(view) && mContainer.getDragLayer()
- .isEventOverView(view, ev)) {
+ for (TaskView taskView : mRecentsView.getTaskViews()) {
+ if (mRecentsView.isTaskViewVisible(taskView) && mContainer.getDragLayer()
+ .isEventOverView(taskView, ev)) {
// Disable swiping up and down if the task overlay is modal.
if (isRecentsModal()) {
mTaskBeingDragged = null;
break;
}
- mTaskBeingDragged = view;
+ mTaskBeingDragged = taskView;
int upDirection = mRecentsView.getPagedOrientationHandler()
.getUpDirection(mIsRtl);
@@ -179,10 +177,10 @@
// - We support gestures to enter overview
// - It's the focused task if in grid view
// - The task is snapped
- mAllowGoingDown = i == mRecentsView.getCurrentPage()
+ mAllowGoingDown = taskView == mRecentsView.getCurrentPageTaskView()
&& DisplayController.getNavigationMode(mContainer).hasGestures
&& (!mRecentsView.showAsGrid() || mTaskBeingDragged.isLargeTile())
- && mRecentsView.isTaskInExpectedScrollPosition(i);
+ && mRecentsView.isTaskInExpectedScrollPosition(taskView);
directionsToDetectScroll = mAllowGoingDown ? DIRECTION_BOTH : upDirection;
break;
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 1970014..39f9f85 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -80,6 +80,8 @@
import android.os.SystemClock;
import android.util.Log;
import android.util.Pair;
+import android.util.TimeUtils;
+import android.view.Choreographer;
import android.view.MotionEvent;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
@@ -125,7 +127,7 @@
import com.android.launcher3.util.WindowBounds;
import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
-import com.android.quickstep.fallback.window.RecentsWindowManager;
+import com.android.quickstep.fallback.window.RecentsWindowFactory;
import com.android.quickstep.util.ActiveGestureErrorDetector;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.ActiveGestureProtoLogProxy;
@@ -299,7 +301,7 @@
private static final int LOG_NO_OP_PAGE_INDEX = -1;
protected final TaskAnimationManager mTaskAnimationManager;
- protected final RecentsWindowManager mRecentsWindowManager;
+ protected final RecentsWindowFactory mRecentsWindowFactory;
// Either RectFSpringAnim (if animating home) or ObjectAnimator (from mCurrentShift) otherwise
private RunningWindowAnim[] mRunningWindowAnim;
// Possible second animation running at the same time as mRunningWindowAnim
@@ -363,7 +365,7 @@
public AbsSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState,
TaskAnimationManager taskAnimationManager, GestureState gestureState,
long touchTimeMs, boolean continuingLastGesture,
- InputConsumerController inputConsumer, RecentsWindowManager recentsWindowManager) {
+ InputConsumerController inputConsumer, RecentsWindowFactory recentsWindowFactory) {
super(context, deviceState, gestureState);
mContainerInterface = gestureState.getContainerInterface();
mContextInitListener =
@@ -379,7 +381,7 @@
endLauncherTransitionController();
}, new InputProxyHandlerFactory(mContainerInterface, mGestureState));
mTaskAnimationManager = taskAnimationManager;
- mRecentsWindowManager = recentsWindowManager;
+ mRecentsWindowFactory = recentsWindowFactory;
mTouchTimeMs = touchTimeMs;
mContinuingLastGesture = continuingLastGesture;
@@ -1734,13 +1736,30 @@
}
private void handOffAnimation(PointF velocityPxPerMs) {
- if (!TransitionAnimator.Companion.longLivedReturnAnimationsEnabled()
- || mRecentsAnimationController == null) {
+ if (!TransitionAnimator.Companion.longLivedReturnAnimationsEnabled()) {
+ return;
+ }
+
+ // This function is not guaranteed to be called inside a frame. We try to access the frame
+ // time immediately, but if we're not inside a frame we must post a callback to be run at
+ // the beginning of the next frame.
+ try {
+ handOffAnimationInternal(Choreographer.getInstance().getFrameTime(), velocityPxPerMs);
+ } catch (IllegalStateException e) {
+ Choreographer.getInstance().postFrameCallback(
+ frameTimeNanos -> handOffAnimationInternal(
+ frameTimeNanos / TimeUtils.NANOS_PER_MS, velocityPxPerMs));
+ }
+ }
+
+ private void handOffAnimationInternal(long timestamp, PointF velocityPxPerMs) {
+ if (mRecentsAnimationController == null) {
return;
}
Pair<RemoteAnimationTarget[], WindowAnimationState[]> targetsAndStates =
- extractTargetsAndStates(mRemoteTargetHandles, velocityPxPerMs);
+ extractTargetsAndStates(
+ mRemoteTargetHandles, timestamp, velocityPxPerMs);
mRecentsAnimationController.handOffAnimation(
targetsAndStates.first, targetsAndStates.second);
ActiveGestureProtoLogProxy.logHandOffAnimation();
diff --git a/quickstep/src/com/android/quickstep/FallbackWindowInterface.java b/quickstep/src/com/android/quickstep/FallbackWindowInterface.java
index 832c093..a202ebd 100644
--- a/quickstep/src/com/android/quickstep/FallbackWindowInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackWindowInterface.java
@@ -41,6 +41,8 @@
import com.android.quickstep.util.ContextInitListener;
import com.android.quickstep.views.RecentsView;
+import java.util.HashMap;
+import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -51,21 +53,23 @@
*/
public final class FallbackWindowInterface extends BaseWindowInterface{
- private static FallbackWindowInterface INSTANCE;
+ static Map<Integer, FallbackWindowInterface> sWindowInterfaceMap = new HashMap<>();
private final RecentsWindowManager mRecentsWindowManager;
-
/**
* This is only null before init() or after destroy()
*/
@Nullable
- public static FallbackWindowInterface getInstance(){
- return INSTANCE;
+ public static FallbackWindowInterface getInstance(int displayId) {
+ return sWindowInterfaceMap.get(displayId);
}
- public static void init(RecentsWindowManager recentsWindowManager) {
- if (INSTANCE == null) {
- INSTANCE = new FallbackWindowInterface(recentsWindowManager);
+ /**
+ * initializing instance and mapping it to display id
+ */
+ public static void init(int displayId, RecentsWindowManager recentsWindowManager) {
+ if (!sWindowInterfaceMap.containsKey(displayId)) {
+ sWindowInterfaceMap.put(displayId, new FallbackWindowInterface(recentsWindowManager));
}
}
@@ -75,7 +79,7 @@
}
public void destroy() {
- INSTANCE = null;
+ sWindowInterfaceMap.clear();
}
/** 2 */
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
index 461f963..c09bf3e 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
@@ -70,7 +70,7 @@
private val taskAnimationManager: TaskAnimationManager,
private val dispatcherProvider: DispatcherProvider = ProductionDispatchers,
) {
- private val coroutineScope = CoroutineScope(SupervisorJob() + dispatcherProvider.default)
+ private val coroutineScope = CoroutineScope(SupervisorJob() + dispatcherProvider.background)
private val commandQueue = ConcurrentLinkedDeque<CommandInfo>()
diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
index 1f6c671..bac5e64 100644
--- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
+++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
@@ -180,7 +180,8 @@
// The default home app is a different launcher. Use the fallback Overview instead.
if (Flags.enableLauncherOverviewInWindow() || Flags.enableFallbackOverviewInWindow()) {
- mContainerInterface = FallbackWindowInterface.getInstance();
+ mContainerInterface =
+ FallbackWindowInterface.getInstance(mDeviceState.getDisplayId());
} else {
mContainerInterface = FallbackActivityInterface.INSTANCE;
}
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 6075294..61a150b 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -19,6 +19,8 @@
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
+import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE;
+import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE_RECREATE_TO_UPDATE_THEME;
import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
import static com.android.launcher3.QuickstepTransitionManager.STATUS_BAR_TRANSITION_DURATION;
import static com.android.launcher3.QuickstepTransitionManager.STATUS_BAR_TRANSITION_PRE_DELAY;
@@ -362,6 +364,14 @@
}
@Override
+ public void onUiChangedWhileSleeping() {
+ super.onUiChangedWhileSleeping();
+ // Dismiss recents and navigate to home if the device goes to sleep
+ // while in recents.
+ startHome();
+ }
+
+ @Override
protected void onResume() {
super.onResume();
AccessibilityManagerCompat.sendStateEventToTest(getBaseContext(), OVERVIEW_STATE_ORDINAL);
@@ -382,6 +392,32 @@
// Set screen title for Talkback
setTitle(R.string.accessibility_recent_apps);
+
+ restoreState(savedInstanceState);
+ }
+
+ @Override
+ protected void onSaveInstanceState(@NonNull Bundle outState) {
+ outState.putInt(RUNTIME_STATE, mStateManager.getState().ordinal);
+ super.onSaveInstanceState(outState);
+ }
+
+ /**
+ * Restores the previous state, if it exists.
+ *
+ * @param savedState The previous state.
+ */
+ private void restoreState(Bundle savedState) {
+ if (savedState == null) {
+ return;
+ }
+
+ if (savedState.getBoolean(RUNTIME_STATE_RECREATE_TO_UPDATE_THEME)) {
+ // RecentsState is only restored after theme changes.
+ int stateOrdinal = savedState.getInt(RUNTIME_STATE, RecentsState.DEFAULT.ordinal);
+ RecentsState recentsState = RecentsState.stateFromOrdinal(stateOrdinal);
+ mStateManager.goToState(recentsState, /*animated=*/false);
+ }
}
@Override
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 055aadb..145773d 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -56,6 +56,8 @@
private boolean mFinishRequested = false;
// Only valid when mFinishRequested == true.
private boolean mFinishTargetIsLauncher;
+ // Only valid when mFinishRequested == true
+ private boolean mLauncherIsVisibleAtFinish;
private RunnableList mPendingFinishCallbacks = new RunnableList();
public RecentsAnimationController(RecentsAnimationControllerCompat controller,
@@ -130,13 +132,27 @@
}
@UiThread
+ public void finish(boolean toRecents, boolean launcherIsVisibleAtFinish,
+ Runnable onFinishComplete, boolean sendUserLeaveHint) {
+ Preconditions.assertUIThread();
+ finishController(toRecents, launcherIsVisibleAtFinish, onFinishComplete, sendUserLeaveHint,
+ false);
+ }
+
+ @UiThread
public void finishController(boolean toRecents, Runnable callback, boolean sendUserLeaveHint) {
- finishController(toRecents, callback, sendUserLeaveHint, false /* forceFinish */);
+ finishController(toRecents, false, callback, sendUserLeaveHint, false /* forceFinish */);
}
@UiThread
public void finishController(boolean toRecents, Runnable callback, boolean sendUserLeaveHint,
boolean forceFinish) {
+ finishController(toRecents, toRecents, callback, sendUserLeaveHint, forceFinish);
+ }
+
+ @UiThread
+ public void finishController(boolean toRecents, boolean launcherIsVisibleAtFinish,
+ Runnable callback, boolean sendUserLeaveHint, boolean forceFinish) {
mPendingFinishCallbacks.add(callback);
if (!forceFinish && mFinishRequested) {
// If finish has already been requested, then add the callback to the pending list.
@@ -148,6 +164,7 @@
// Finish not yet requested
mFinishRequested = true;
mFinishTargetIsLauncher = toRecents;
+ mLauncherIsVisibleAtFinish = launcherIsVisibleAtFinish;
mOnFinishedListener.accept(this);
Runnable finishCb = () -> {
mController.finish(toRecents, sendUserLeaveHint, new IResultReceiver.Stub() {
@@ -224,6 +241,14 @@
return mFinishTargetIsLauncher;
}
+ /**
+ * RecentsAnimationListeners can check this in onRecentsAnimationFinished() to determine whether
+ * the animation was finished to launcher vs an app.
+ */
+ public boolean getLauncherIsVisibleAtFinish() {
+ return mLauncherIsVisibleAtFinish;
+ }
+
public void dump(String prefix, PrintWriter pw) {
pw.println(prefix + "RecentsAnimationController:");
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 2991e64..6a25ecb 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -1478,10 +1478,11 @@
}
/** Call shell to move a task with given `taskId` to desktop */
- public void moveToDesktop(int taskId, DesktopModeTransitionSource transitionSource) {
+ public void moveToDesktop(int taskId, DesktopModeTransitionSource transitionSource,
+ @Nullable RemoteTransition transition) {
if (mDesktopMode != null) {
try {
- mDesktopMode.moveToDesktop(taskId, transitionSource);
+ mDesktopMode.moveToDesktop(taskId, transitionSource, transition);
} catch (RemoteException e) {
Log.w(TAG, "Failed call moveToDesktop", e);
}
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 0ea128a..2fcfa36 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -47,6 +47,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.util.DisplayController;
+import com.android.quickstep.fallback.window.RecentsWindowFactory;
import com.android.quickstep.fallback.window.RecentsWindowManager;
import com.android.quickstep.util.ActiveGestureProtoLogProxy;
import com.android.quickstep.util.SystemUiFlagUtils;
@@ -65,10 +66,12 @@
SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
private final Context mCtx;
- private RecentsWindowManager mRecentsWindowsManager;
+ private RecentsWindowFactory mRecentsWindowFactory;
private RecentsAnimationController mController;
private RecentsAnimationCallbacks mCallbacks;
private RecentsAnimationTargets mTargets;
+ private RecentsAnimationDeviceState mDeviceState;
+
// Temporary until we can hook into gesture state events
private GestureState mLastGestureState;
private RemoteAnimationTarget[] mLastAppearedTaskTargets;
@@ -100,9 +103,11 @@
}
};
- TaskAnimationManager(Context ctx, RecentsWindowManager manager) {
+ TaskAnimationManager(Context ctx, RecentsWindowFactory recentsWindowFactory,
+ RecentsAnimationDeviceState deviceState) {
mCtx = ctx;
- mRecentsWindowsManager = manager;
+ mDeviceState = deviceState;
+ mRecentsWindowFactory = recentsWindowFactory;
}
SystemUiProxy getSystemUiProxy() {
return SystemUiProxy.INSTANCE.get(mCtx);
@@ -298,7 +303,8 @@
|| Flags.enableLauncherOverviewInWindow())) {
mRecentsAnimationStartPending = getSystemUiProxy().startRecentsActivity(intent, options,
mCallbacks, gestureState.useSyntheticRecentsTransition());
- mRecentsWindowsManager.startRecentsWindow(mCallbacks);
+ mRecentsWindowFactory.create(mDeviceState.getDisplayId())
+ .startRecentsWindow(mCallbacks);
} else {
options.setPendingIntentBackgroundActivityStartMode(
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS);
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index 785666f..ab5e830 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -317,7 +317,7 @@
boolean hideForExistingMultiWindow = container.getDeviceProfile().isMultiWindowMode;
boolean isLargeTile = deviceProfile.isTablet && taskView.isLargeTile();
boolean isTaskInExpectedScrollPosition =
- recentsView.isTaskInExpectedScrollPosition(recentsView.indexOfChild(taskView));
+ recentsView.isTaskInExpectedScrollPosition(taskView);
if (notEnoughTasksToSplit || isTaskSplitNotSupported || hideForExistingMultiWindow
|| (isLargeTile && isTaskInExpectedScrollPosition)) {
@@ -342,7 +342,7 @@
final RecentsView recentsView = taskView.getRecentsView();
boolean isLargeTile = deviceProfile.isTablet && taskView.isLargeTile();
boolean isInExpectedScrollPosition =
- recentsView.isTaskInExpectedScrollPosition(recentsView.indexOfChild(taskView));
+ recentsView.isTaskInExpectedScrollPosition(taskView);
boolean shouldShowActionsButtonInstead =
isLargeTile && isInExpectedScrollPosition;
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 783c87c..dec36cf 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -108,7 +108,7 @@
* opening remote target (which we don't get until onAnimationStart) will resolve to a TaskView.
*/
public static TaskView findTaskViewToLaunch(
- RecentsView recentsView, View v, RemoteAnimationTarget[] targets) {
+ RecentsView<?, ?> recentsView, View v, RemoteAnimationTarget[] targets) {
if (v instanceof TaskView) {
TaskView taskView = (TaskView) v;
return recentsView.isTaskViewVisible(taskView) ? taskView : null;
@@ -121,8 +121,7 @@
ComponentName componentName = itemInfo.getTargetComponent();
int userId = itemInfo.user.getIdentifier();
if (componentName != null) {
- for (int i = 0; i < recentsView.getTaskViewCount(); i++) {
- TaskView taskView = recentsView.getTaskViewAt(i);
+ for (TaskView taskView : recentsView.getTaskViews()) {
if (recentsView.isTaskViewVisible(taskView)) {
Task.TaskKey key = taskView.getFirstTask().key;
if (componentName.equals(key.getComponent()) && userId == key.userId) {
@@ -562,7 +561,7 @@
* Start recents to desktop animation
*/
public static AnimatorSet composeRecentsDesktopLaunchAnimator(
- @NonNull DesktopTaskView launchingTaskView,
+ @NonNull TaskView launchingTaskView,
@NonNull StateManager stateManager, @Nullable DepthController depthController,
@NonNull TransitionInfo transitionInfo,
SurfaceControl.Transaction t, @NonNull Runnable finishCallback) {
@@ -795,14 +794,15 @@
* second applies to the target in the same index of the first.
*
* @param handles The handles wrapping each target.
+ * @param timestamp The start time of the current frame.
* @param velocityPxPerMs The current velocity of the target animations.
*/
@NonNull
public static Pair<RemoteAnimationTarget[], WindowAnimationState[]> extractTargetsAndStates(
- @NonNull RemoteTargetHandle[] handles, @NonNull PointF velocityPxPerMs) {
+ @NonNull RemoteTargetHandle[] handles, long timestamp,
+ @NonNull PointF velocityPxPerMs) {
RemoteAnimationTarget[] targets = new RemoteAnimationTarget[handles.length];
WindowAnimationState[] animationStates = new WindowAnimationState[handles.length];
- long timestamp = System.currentTimeMillis();
for (int i = 0; i < handles.length; i++) {
targets[i] = handles[i].getTransformParams().getTargetSet().apps[i];
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 50d4dab..564f9a2 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -89,7 +89,7 @@
import com.android.launcher3.util.ScreenOnTracker;
import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.OverviewCommandHelper.CommandType;
-import com.android.quickstep.fallback.window.RecentsWindowManager;
+import com.android.quickstep.fallback.window.RecentsWindowFactory;
import com.android.quickstep.fallback.window.RecentsWindowSwipeHandler;
import com.android.quickstep.inputconsumers.BubbleBarInputConsumer;
import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer;
@@ -631,7 +631,7 @@
private InputEventReceiver mInputEventReceiver;
private TaskbarManager mTaskbarManager;
- private RecentsWindowManager mRecentsWindowManager;
+ private RecentsWindowFactory mRecentsWindowFactory;
private Function<GestureState, AnimatedFloat> mSwipeUpProxyProvider = i -> null;
private AllAppsActionManager mAllAppsActionManager;
private InputManager mInputManager;
@@ -669,7 +669,7 @@
new DesktopAppLaunchTransitionManager(this, SystemUiProxy.INSTANCE.get(this));
mDesktopAppLaunchTransitionManager.registerTransitions();
if (Flags.enableLauncherOverviewInWindow() || Flags.enableFallbackOverviewInWindow()) {
- mRecentsWindowManager = new RecentsWindowManager(this);
+ mRecentsWindowFactory = new RecentsWindowFactory(this);
}
mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
@@ -722,7 +722,7 @@
public void onUserUnlocked() {
Log.d(TAG, "onUserUnlocked: userId=" + getUserId()
+ " instance=" + System.identityHashCode(this));
- mTaskAnimationManager = new TaskAnimationManager(this, mRecentsWindowManager);
+ mTaskAnimationManager = new TaskAnimationManager(this, mRecentsWindowFactory, mDeviceState);
mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState);
mOverviewCommandHelper = new OverviewCommandHelper(this,
mOverviewComponentObserver, mTaskAnimationManager);
@@ -830,8 +830,8 @@
mTaskbarManager.destroy();
- if (mRecentsWindowManager != null) {
- mRecentsWindowManager.destroy();
+ if (mRecentsWindowFactory != null) {
+ mRecentsWindowFactory.destroy();
}
if (mDesktopAppLaunchTransitionManager != null) {
mDesktopAppLaunchTransitionManager.unregisterTransitions();
@@ -1288,6 +1288,6 @@
GestureState gestureState, long touchTimeMs) {
return new RecentsWindowSwipeHandler(this, mDeviceState, mTaskAnimationManager,
gestureState, touchTimeMs, mTaskAnimationManager.isRecentsAnimationRunning(),
- mInputConsumer, mRecentsWindowManager);
+ mInputConsumer, mRecentsWindowFactory);
}
}
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index daad6b7..28d95e2 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -73,13 +73,14 @@
}
public FallbackRecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr, getContainerInterface());
+ super(context, attrs, defStyleAttr);
mContainer.getStateManager().addStateListener(this);
}
- private static BaseContainerInterface<RecentsState, ?> getContainerInterface() {
+ @Override
+ public BaseContainerInterface<RecentsState, ?> getContainerInterface(int displayId) {
return (Flags.enableFallbackOverviewInWindow() || Flags.enableLauncherOverviewInWindow())
- ? FallbackWindowInterface.getInstance()
+ ? FallbackWindowInterface.getInstance(displayId)
: FallbackActivityInterface.INSTANCE;
}
diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsState.java b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
index 34783c7..c2e7536 100644
--- a/quickstep/src/com/android/quickstep/fallback/RecentsState.java
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
@@ -45,6 +45,8 @@
private static final int FLAG_TASK_THUMBNAIL_SPLASH = BaseState.getFlag(8);
private static final int FLAG_DETACH_DESKTOP_CAROUSEL = BaseState.getFlag(9);
+ private static final RecentsState[] sAllStates = new RecentsState[6];
+
public static final RecentsState DEFAULT = new RecentsState(0,
FLAG_DISABLE_RESTORE | FLAG_CLEAR_ALL_BUTTON | FLAG_OVERVIEW_ACTIONS | FLAG_SHOW_AS_GRID
| FLAG_SCRIM | FLAG_LIVE_TILE | FLAG_RECENTS_VIEW_VISIBLE);
@@ -61,6 +63,11 @@
FLAG_SHOW_AS_GRID | FLAG_SCRIM | FLAG_RECENTS_VIEW_VISIBLE | FLAG_CLOSE_POPUPS
| FLAG_DISABLE_RESTORE);
+ /** Returns the corresponding RecentsState from ordinal provided */
+ public static RecentsState stateFromOrdinal(int ordinal) {
+ return sAllStates[ordinal];
+ }
+
public final int ordinal;
private final int mFlags;
@@ -70,6 +77,7 @@
public RecentsState(int id, int flags) {
this.ordinal = id;
this.mFlags = flags;
+ sAllStates[id] = this;
}
diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowFactory.kt b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowFactory.kt
new file mode 100644
index 0000000..ac0593e
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowFactory.kt
@@ -0,0 +1,93 @@
+/*
+ * 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.quickstep.fallback.window
+
+import android.content.Context
+import android.hardware.display.DisplayManager
+import android.os.Handler
+import android.util.Log
+import android.util.SparseArray
+import android.view.Display
+import androidx.core.util.valueIterator
+
+
+/**
+ * Factory for creating [RecentsWindowManager] instances based on context per display.
+ */
+class RecentsWindowFactory(private val context: Context) {
+
+ companion object {
+ private const val TAG = "RecentsWindowFactory"
+ private const val DEBUG = false
+ }
+
+ private val displayManager = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
+ private val managerArray = SparseArray<RecentsWindowManager>()
+
+ private val displayListener: DisplayManager.DisplayListener =
+ (object : DisplayManager.DisplayListener {
+ override fun onDisplayAdded(displayId: Int) {
+ if (DEBUG) Log.d(TAG, "onDisplayAdded: displayId=$displayId")
+ create(displayId)
+ }
+
+ override fun onDisplayRemoved(displayId: Int) {
+ if (DEBUG) Log.d(TAG, "onDisplayRemoved: displayId=$displayId")
+ delete(displayId)
+ }
+
+ override fun onDisplayChanged(displayId: Int) {
+ if (DEBUG) Log.d(TAG, "onDisplayChanged: displayId=$displayId")
+ }
+ })
+
+ init {
+ create(Display.DEFAULT_DISPLAY) // create manager for first display early.
+ displayManager.registerDisplayListener(displayListener, Handler.getMain())
+ }
+
+ fun destroy() {
+ managerArray.valueIterator().forEach { manager ->
+ manager.destroy()
+ }
+ managerArray.clear()
+ displayManager.unregisterDisplayListener(displayListener)
+ }
+
+ fun get(displayId: Int): RecentsWindowManager? {
+ if (DEBUG) Log.d(TAG, "get: displayId=$displayId")
+ return managerArray[displayId]
+ }
+
+ fun delete(displayId: Int) {
+ if (DEBUG) Log.d(TAG, "delete: displayId=$displayId")
+ get(displayId)?.destroy()
+ managerArray.remove(displayId)
+ }
+
+ fun create(displayId: Int): RecentsWindowManager {
+ if (DEBUG) Log.d(TAG, "create: displayId=$displayId")
+ get(displayId)?.let {
+ return it
+ }
+ val display = displayManager.getDisplay(displayId)
+ val displayContext = context.createDisplayContext(display)
+ val recentsWindowManager = RecentsWindowManager(displayId, displayContext)
+ managerArray[displayId] = recentsWindowManager
+ return recentsWindowManager
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt
index f4c8c99..b0afe90 100644
--- a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt
+++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt
@@ -88,8 +88,10 @@
* To add new protologs, see [RecentsWindowProtoLogProxy]. To enable logging to logcat, see
* [QuickstepProtoLogGroup.Constants.DEBUG_RECENTS_WINDOW]
*/
-class RecentsWindowManager(context: Context) :
- RecentsWindowContext(context), RecentsViewContainer, StatefulContainer<RecentsState> {
+class RecentsWindowManager(
+ private val displayId: Int,
+ context: Context
+) : RecentsWindowContext(context), RecentsViewContainer, StatefulContainer<RecentsState> {
companion object {
private const val HOME_APPEAR_DURATION: Long = 250
@@ -151,14 +153,14 @@
}
init {
- FallbackWindowInterface.init(this)
+ FallbackWindowInterface.init(displayId, this)
TaskStackChangeListeners.getInstance().registerTaskStackListener(taskStackChangeListener)
}
override fun destroy() {
super.destroy()
cleanupRecentsWindow()
- FallbackWindowInterface.getInstance()?.destroy()
+ FallbackWindowInterface.getInstance(displayId)?.destroy()
TaskStackChangeListeners.getInstance().unregisterTaskStackListener(taskStackChangeListener)
callbacks?.removeListener(recentsAnimationListener)
recentsWindowTracker.onContextDestroyed(this)
diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java
index be71385..ea1d21b 100644
--- a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java
@@ -110,9 +110,9 @@
public RecentsWindowSwipeHandler(Context context, RecentsAnimationDeviceState deviceState,
TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs,
boolean continuingLastGesture, InputConsumerController inputConsumer,
- RecentsWindowManager recentsWindowManager) {
+ RecentsWindowFactory recentsWindowFactory) {
super(context, deviceState, taskAnimationManager, gestureState, touchTimeMs,
- continuingLastGesture, inputConsumer, recentsWindowManager);
+ continuingLastGesture, inputConsumer, recentsWindowFactory);
mRunningOverHome = mGestureState.getRunningTask() != null
&& mGestureState.getRunningTask().isHomeTask();
@@ -159,7 +159,10 @@
boolean fromHomeToHome = mRunningOverHome
&& endTarget == GestureState.GestureEndTarget.HOME;
if (fromHomeToHome) {
- mRecentsWindowManager.startHome(/* finishRecentsAnimation= */ false);
+ RecentsWindowManager manager = mRecentsWindowFactory.get(mDeviceState.getDisplayId());
+ if (manager != null) {
+ manager.startHome(/* finishRecentsAnimation= */ false);
+ }
}
super.animateGestureEnd(
startShift,
@@ -220,7 +223,11 @@
// the PiP task appearing.
recentsCallback = () -> {
callback.run();
- mRecentsWindowManager.startHome();
+ RecentsWindowManager manager =
+ mRecentsWindowFactory.get(mDeviceState.getDisplayId());
+ if (manager != null) {
+ manager.startHome();
+ }
};
} else {
recentsCallback = callback;
diff --git a/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
index 3b59864..53969c5 100644
--- a/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
@@ -37,6 +37,12 @@
fun getThumbnailById(taskId: Int): Flow<ThumbnailData?>
/**
+ * Gets the [ThumbnailData] associated with a task that has id [taskId]. Flow will settle on
+ * null if the task was not found or is invisible.
+ */
+ fun getCurrentThumbnailById(taskId: Int): ThumbnailData?
+
+ /**
* Sets the tasks that are visible, indicating that properties relating to visuals need to be
* populated e.g. icons/thumbnails etc.
*/
diff --git a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
index 6c627ef..3aae760 100644
--- a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
@@ -72,6 +72,8 @@
override fun getThumbnailById(taskId: Int) =
getTaskDataById(taskId).map { it?.thumbnail }.distinctUntilChangedBy { it?.snapshotId }
+ override fun getCurrentThumbnailById(taskId: Int) = tasks.value[taskId]?.thumbnail
+
override fun setVisibleTasks(visibleTaskIdList: Set<Int>) {
val tasksNoLongerVisible = taskRequests.keys.subtract(visibleTaskIdList)
val newlyVisibleTasks = visibleTaskIdList.subtract(taskRequests.keys)
diff --git a/quickstep/src/com/android/quickstep/recents/usecase/GetThumbnailPositionUseCase.kt b/quickstep/src/com/android/quickstep/recents/usecase/GetThumbnailPositionUseCase.kt
index f060d7d..bea1d07 100644
--- a/quickstep/src/com/android/quickstep/recents/usecase/GetThumbnailPositionUseCase.kt
+++ b/quickstep/src/com/android/quickstep/recents/usecase/GetThumbnailPositionUseCase.kt
@@ -24,18 +24,17 @@
import com.android.quickstep.recents.usecase.ThumbnailPositionState.MatrixScaling
import com.android.quickstep.recents.usecase.ThumbnailPositionState.MissingThumbnail
import com.android.systemui.shared.recents.utilities.PreviewPositionHelper
-import kotlinx.coroutines.flow.firstOrNull
/** Use case for retrieving [Matrix] for positioning Thumbnail in a View */
class GetThumbnailPositionUseCase(
private val deviceProfileRepository: RecentsDeviceProfileRepository,
private val rotationStateRepository: RecentsRotationStateRepository,
private val tasksRepository: RecentTasksRepository,
- private val previewPositionHelper: PreviewPositionHelper = PreviewPositionHelper()
+ private val previewPositionHelper: PreviewPositionHelper = PreviewPositionHelper(),
) {
- suspend fun run(taskId: Int, width: Int, height: Int, isRtl: Boolean): ThumbnailPositionState {
+ fun run(taskId: Int, width: Int, height: Int, isRtl: Boolean): ThumbnailPositionState {
val thumbnailData =
- tasksRepository.getThumbnailById(taskId).firstOrNull() ?: return MissingThumbnail
+ tasksRepository.getCurrentThumbnailById(taskId) ?: return MissingThumbnail
val thumbnail = thumbnailData.thumbnail ?: return MissingThumbnail
previewPositionHelper.updateThumbnailMatrix(
Rect(0, 0, thumbnail.width, thumbnail.height),
@@ -44,11 +43,11 @@
height,
deviceProfileRepository.getRecentsDeviceProfile().isLargeScreen,
rotationStateRepository.getRecentsRotationState().activityRotation,
- isRtl
+ isRtl,
)
return MatrixScaling(
previewPositionHelper.matrix,
- previewPositionHelper.isOrientationChanged
+ previewPositionHelper.isOrientationChanged,
)
}
}
diff --git a/quickstep/src/com/android/quickstep/recents/usecase/GetThumbnailUseCase.kt b/quickstep/src/com/android/quickstep/recents/usecase/GetThumbnailUseCase.kt
index 3aa808e..b9e9e02 100644
--- a/quickstep/src/com/android/quickstep/recents/usecase/GetThumbnailUseCase.kt
+++ b/quickstep/src/com/android/quickstep/recents/usecase/GetThumbnailUseCase.kt
@@ -18,13 +18,9 @@
import android.graphics.Bitmap
import com.android.quickstep.recents.data.RecentTasksRepository
-import kotlinx.coroutines.flow.firstOrNull
-import kotlinx.coroutines.runBlocking
/** Use case for retrieving thumbnail. */
class GetThumbnailUseCase(private val taskRepository: RecentTasksRepository) {
/** Returns the latest thumbnail associated with [taskId] if loaded, or null otherwise */
- fun run(taskId: Int): Bitmap? = runBlocking {
- taskRepository.getThumbnailById(taskId).firstOrNull()?.thumbnail
- }
+ fun run(taskId: Int): Bitmap? = taskRepository.getCurrentThumbnailById(taskId)?.thumbnail
}
diff --git a/quickstep/src/com/android/quickstep/recents/usecase/SysUiStatusNavFlagsUseCase.kt b/quickstep/src/com/android/quickstep/recents/usecase/SysUiStatusNavFlagsUseCase.kt
index 1d19c7d..5be5f4a 100644
--- a/quickstep/src/com/android/quickstep/recents/usecase/SysUiStatusNavFlagsUseCase.kt
+++ b/quickstep/src/com/android/quickstep/recents/usecase/SysUiStatusNavFlagsUseCase.kt
@@ -22,14 +22,11 @@
import com.android.launcher3.util.SystemUiController.FLAG_LIGHT_NAV
import com.android.launcher3.util.SystemUiController.FLAG_LIGHT_STATUS
import com.android.quickstep.recents.data.RecentTasksRepository
-import kotlinx.coroutines.flow.firstOrNull
-import kotlinx.coroutines.runBlocking
/** UseCase to calculate flags for status bar and navigation bar */
class SysUiStatusNavFlagsUseCase(private val taskRepository: RecentTasksRepository) {
fun getSysUiStatusNavFlags(taskId: Int): Int {
- val thumbnailData =
- runBlocking { taskRepository.getThumbnailById(taskId).firstOrNull() } ?: return 0
+ val thumbnailData = taskRepository.getCurrentThumbnailById(taskId) ?: return 0
val thumbnailAppearance = thumbnailData.appearance
var flags = 0
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
index 0c783d3..ea4602d 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
@@ -24,8 +24,8 @@
import android.util.Log
import android.view.View
import android.view.ViewOutlineProvider
+import android.widget.FrameLayout
import androidx.annotation.ColorInt
-import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isInvisible
import com.android.launcher3.R
import com.android.launcher3.util.ViewPool
@@ -46,7 +46,7 @@
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
-class TaskThumbnailView : ConstraintLayout, ViewPool.Reusable {
+class TaskThumbnailView : FrameLayout, ViewPool.Reusable {
private lateinit var viewData: TaskThumbnailViewData
private lateinit var viewModel: TaskThumbnailViewModel
diff --git a/quickstep/src/com/android/quickstep/task/viewmodel/TaskOverlayViewModel.kt b/quickstep/src/com/android/quickstep/task/viewmodel/TaskOverlayViewModel.kt
index 4e13d1c..14359db 100644
--- a/quickstep/src/com/android/quickstep/task/viewmodel/TaskOverlayViewModel.kt
+++ b/quickstep/src/com/android/quickstep/task/viewmodel/TaskOverlayViewModel.kt
@@ -28,7 +28,6 @@
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.runBlocking
/** View model for TaskOverlay */
class TaskOverlayViewModel(
@@ -41,7 +40,7 @@
combine(
recentsViewData.overlayEnabled,
recentsViewData.settledFullyVisibleTaskIds.map { it.contains(task.key.id) },
- recentTasksRepository.getThumbnailById(task.key.id)
+ recentTasksRepository.getThumbnailById(task.key.id),
) { isOverlayEnabled, isFullyVisible, thumbnailData ->
if (isOverlayEnabled && isFullyVisible) {
Enabled(
@@ -55,24 +54,22 @@
.distinctUntilChanged()
fun getThumbnailPositionState(width: Int, height: Int, isRtl: Boolean): ThumbnailPositionState {
- return runBlocking {
- val matrix: Matrix
- val isRotated: Boolean
- when (
- val thumbnailPositionState =
- getThumbnailPositionUseCase.run(task.key.id, width, height, isRtl)
- ) {
- is MatrixScaling -> {
- matrix = thumbnailPositionState.matrix
- isRotated = thumbnailPositionState.isRotated
- }
- is MissingThumbnail -> {
- matrix = Matrix.IDENTITY_MATRIX
- isRotated = false
- }
+ val matrix: Matrix
+ val isRotated: Boolean
+ when (
+ val thumbnailPositionState =
+ getThumbnailPositionUseCase.run(task.key.id, width, height, isRtl)
+ ) {
+ is MatrixScaling -> {
+ matrix = thumbnailPositionState.matrix
+ isRotated = thumbnailPositionState.isRotated
}
- ThumbnailPositionState(matrix, isRotated)
+ is MissingThumbnail -> {
+ matrix = Matrix.IDENTITY_MATRIX
+ isRotated = false
+ }
}
+ return ThumbnailPositionState(matrix, isRotated)
}
data class ThumbnailPositionState(val matrix: Matrix, val isRotated: Boolean)
diff --git a/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModelImpl.kt b/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModelImpl.kt
index b6cb984..b5b2fc9 100644
--- a/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModelImpl.kt
+++ b/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModelImpl.kt
@@ -44,7 +44,6 @@
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.runBlocking
@OptIn(ExperimentalCoroutinesApi::class)
class TaskThumbnailViewModelImpl(
@@ -61,12 +60,14 @@
override val dimProgress: Flow<Float> =
combine(taskContainerData.taskMenuOpenProgress, recentsViewData.tintAmount) {
- taskMenuOpenProgress,
- tintAmount ->
- max(taskMenuOpenProgress * MAX_SCRIM_ALPHA, tintAmount)
- }
+ taskMenuOpenProgress,
+ tintAmount ->
+ max(taskMenuOpenProgress * MAX_SCRIM_ALPHA, tintAmount)
+ }
+ .flowOn(dispatcherProvider.background)
- override val splashAlpha = splashProgress.flatMapLatest { it }
+ override val splashAlpha =
+ splashProgress.flatMapLatest { it }.flowOn(dispatcherProvider.background)
private val isLiveTile =
combine(
@@ -77,7 +78,6 @@
runningTaskIds.contains(taskId) && !runningTaskShowScreenshot
}
.distinctUntilChanged()
- .flowOn(dispatcherProvider.default)
override val uiState: Flow<TaskThumbnailUiState> =
combine(task.flatMapLatest { it }, isLiveTile) { taskVal, isRunning ->
@@ -99,7 +99,7 @@
}
}
.distinctUntilChanged()
- .flowOn(dispatcherProvider.default)
+ .flowOn(dispatcherProvider.background)
override fun bind(taskId: Int) {
Log.d(TAG, "bind taskId: $taskId")
@@ -108,17 +108,14 @@
splashProgress.value = splashAlphaUseCase.execute(taskId)
}
- override fun getThumbnailPositionState(width: Int, height: Int, isRtl: Boolean): Matrix {
- return runBlocking {
- when (
- val thumbnailPositionState =
- getThumbnailPositionUseCase.run(taskId, width, height, isRtl)
- ) {
- is ThumbnailPositionState.MatrixScaling -> thumbnailPositionState.matrix
- is ThumbnailPositionState.MissingThumbnail -> Matrix.IDENTITY_MATRIX
- }
+ override fun getThumbnailPositionState(width: Int, height: Int, isRtl: Boolean): Matrix =
+ when (
+ val thumbnailPositionState =
+ getThumbnailPositionUseCase.run(taskId, width, height, isRtl)
+ ) {
+ is ThumbnailPositionState.MatrixScaling -> thumbnailPositionState.matrix
+ is ThumbnailPositionState.MissingThumbnail -> Matrix.IDENTITY_MATRIX
}
- }
private fun isBackgroundOnly(task: Task): Boolean = task.isLocked || task.thumbnail == null
diff --git a/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt b/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt
index c3b072d..7393de4 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt
+++ b/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt
@@ -48,16 +48,6 @@
return otherTasks + desktopTasks
}
- /** Returns the expected index of the focus task. */
- fun getFocusedTaskIndex(taskGroups: List<GroupTask>): Int {
- // The focused task index is placed after the desktop tasks views.
- return if (enableLargeDesktopWindowingTile()) {
- taskGroups.count { it.taskViewType == TaskViewType.DESKTOP }
- } else {
- 0
- }
- }
-
/** Counts [TaskView]s that are [DesktopTaskView] instances. */
fun getDesktopTaskViewCount(taskViews: Iterable<TaskView>): Int =
taskViews.count { it is DesktopTaskView }
@@ -81,6 +71,33 @@
): TaskView? =
taskViews.firstOrNull { it.isLargeTile && !(splitSelectActive && it is DesktopTaskView) }
+ /** Returns the expected focus task. */
+ fun getExpectedFocusedTask(taskViews: Iterable<TaskView>): TaskView? =
+ if (enableLargeDesktopWindowingTile()) taskViews.firstOrNull { it !is DesktopTaskView }
+ else taskViews.firstOrNull()
+
+ /**
+ * Returns the [TaskView] that should be the current page during task binding, in the following
+ * priorities:
+ * 1. Running task
+ * 2. Focused task
+ * 3. First non-desktop task
+ * 4. Last desktop task
+ * 5. null otherwise
+ */
+ fun getExpectedCurrentTask(
+ runningTaskView: TaskView?,
+ focusedTaskView: TaskView?,
+ taskViews: Iterable<TaskView>,
+ ): TaskView? =
+ runningTaskView
+ ?: focusedTaskView
+ ?: taskViews.firstOrNull { it !is DesktopTaskView }
+ ?: taskViews.lastOrNull()
+
+ /** Returns the first TaskView if it exists, or null otherwise. */
+ fun getFirstTaskView(taskViews: Iterable<TaskView>): TaskView? = taskViews.firstOrNull()
+
/**
* Returns the first TaskView that is not large
*
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index d35a36a..1eb91ae 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -106,6 +106,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Optional;
import java.util.function.Consumer;
/**
@@ -941,6 +942,10 @@
mLauncher, mLauncher.getDragLayer(),
null /* thumbnail */,
mAppIcon, new RectF());
+ floatingTaskView.setOnClickListener(view ->
+ getSplitAnimationController()
+ .playAnimPlaceholderToFullscreen(mContainer, view,
+ Optional.of(() -> resetState())));
floatingTaskView.setAlpha(1);
floatingTaskView.addStagingAnimation(anim, mTaskBounds, mTempRect,
false /* fadeWithThumbnail */, true /* isStagedTask */);
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
index 576a56e..7d04451 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
@@ -24,8 +24,10 @@
import android.util.Log
import android.view.Gravity
import android.view.View
+import android.view.ViewStub
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.updateLayoutParams
+import com.android.launcher3.Flags.enableOverviewIconMenu
import com.android.launcher3.Flags.enableRefactorTaskThumbnail
import com.android.launcher3.R
import com.android.launcher3.testing.TestLogging
@@ -85,7 +87,7 @@
override fun onFinishInflate() {
super.onFinishInflate()
iconView =
- getOrInflateIconView(R.id.icon).apply {
+ (findViewById<View>(R.id.icon) as TaskViewIcon).apply {
setIcon(
this,
ResourcesCompat.getDrawable(
@@ -109,6 +111,16 @@
}
}
+ override fun inflateViewStubs() {
+ findViewById<ViewStub>(R.id.icon)
+ ?.apply {
+ layoutResource =
+ if (enableOverviewIconMenu()) R.layout.icon_app_chip_view
+ else R.layout.icon_view
+ }
+ ?.inflate()
+ }
+
/** Updates this desktop task to the gives task list defined in `tasks` */
fun bind(
tasks: List<Task>,
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
index 0d9583d..2e94534 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
@@ -21,8 +21,10 @@
import android.util.AttributeSet
import android.util.Log
import android.view.View
+import android.view.ViewStub
import com.android.internal.jank.Cuj
import com.android.launcher3.Flags.enableOverviewIconMenu
+import com.android.launcher3.Flags.enableRefactorTaskThumbnail
import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.config.FeatureFlags
@@ -82,6 +84,24 @@
}
}
+ override fun inflateViewStubs() {
+ super.inflateViewStubs()
+ findViewById<ViewStub>(R.id.bottomright_snapshot)
+ ?.apply {
+ layoutResource =
+ if (enableRefactorTaskThumbnail()) R.layout.task_thumbnail
+ else R.layout.task_thumbnail_deprecated
+ }
+ ?.inflate()
+ findViewById<ViewStub>(R.id.bottomRight_icon)
+ ?.apply {
+ layoutResource =
+ if (enableOverviewIconMenu()) R.layout.icon_app_chip_view
+ else R.layout.icon_view
+ }
+ ?.inflate()
+ }
+
override fun onRecycle() {
super.onRecycle()
splitBoundsConfig = null
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index bbb8cc8..4f823e6 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -47,6 +47,7 @@
import com.android.launcher3.util.PendingSplitSelectInfo;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
+import com.android.quickstep.BaseContainerInterface;
import com.android.quickstep.GestureState;
import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.RotationTouchHelper;
@@ -73,7 +74,7 @@
}
public LauncherRecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr, LauncherActivityInterface.INSTANCE);
+ super(context, attrs, defStyleAttr);
getStateManager().addStateListener(this);
}
@@ -225,6 +226,11 @@
}
@Override
+ protected BaseContainerInterface<LauncherState, ?> getContainerInterface(int displayId) {
+ return LauncherActivityInterface.INSTANCE;
+ }
+
+ @Override
protected void onDismissAnimationEnds() {
super.onDismissAnimationEnds();
if (mContainer.isInState(OVERVIEW_SPLIT_SELECT)) {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 6fc33dc..3b46367 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -503,7 +503,7 @@
private static final float FOREGROUND_SCRIM_TINT = 0.32f;
protected final RecentsOrientedState mOrientationState;
- protected final BaseContainerInterface<STATE_TYPE, CONTAINER_TYPE> mSizeStrategy;
+ protected final BaseContainerInterface<STATE_TYPE, ?> mSizeStrategy;
@Nullable
protected RecentsAnimationController mRecentsAnimationController;
@Nullable
@@ -691,7 +691,7 @@
protected boolean mRunningTaskTileHidden;
protected int mFocusedTaskViewId = INVALID_TASK_ID;
- private boolean mTaskIconScaledDown = false;
+ private boolean mTaskIconVisible = true;
private boolean mRunningTaskShowScreenshot = false;
private float mRunningTaskAttachAlpha;
@@ -846,13 +846,18 @@
private final Matrix mTmpMatrix = new Matrix();
- public RecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
- BaseContainerInterface sizeStrategy) {
+ @Nullable
+ public TaskView getFirstTaskView() {
+ return mUtils.getFirstTaskView(getTaskViews());
+ }
+
+ public RecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setEnableFreeScroll(true);
- mSizeStrategy = sizeStrategy;
mContainer = RecentsViewContainer.containerFromContext(context);
+ mSizeStrategy = getContainerInterface(mContainer.getDisplayId());
+
mOrientationState = new RecentsOrientedState(
context, mSizeStrategy, this::animateRecentsRotationInPlace);
final int rotation = mContainer.getDisplay().getRotation();
@@ -1244,24 +1249,21 @@
// - It's the focused task to be moved to the front, we immediately re-add the task
if (child instanceof TaskView && child != mSplitHiddenTaskView
&& child != mMovingTaskView) {
- clearAndRecycleTaskView((TaskView) child);
+ TaskView taskView = (TaskView) child;
+ for (int i : taskView.getTaskIds()) {
+ mHasVisibleTaskData.delete(i);
+ }
+ if (child instanceof GroupedTaskView) {
+ mGroupedTaskViewPool.recycle((GroupedTaskView) taskView);
+ } else if (child instanceof DesktopTaskView) {
+ mDesktopTaskViewPool.recycle((DesktopTaskView) taskView);
+ } else {
+ mTaskViewPool.recycle(taskView);
+ }
+ mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, getTaskViewCount() == 0);
}
}
- private void clearAndRecycleTaskView(TaskView taskView) {
- for (int taskId : taskView.getTaskIds()) {
- mHasVisibleTaskData.delete(taskId);
- }
- if (taskView instanceof GroupedTaskView) {
- mGroupedTaskViewPool.recycle((GroupedTaskView) taskView);
- } else if (taskView instanceof DesktopTaskView) {
- mDesktopTaskViewPool.recycle((DesktopTaskView) taskView);
- } else {
- mTaskViewPool.recycle(taskView);
- }
- mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, getTaskViewCount() == 0);
- }
-
@Override
public void onViewAdded(View child) {
super.onViewAdded(child);
@@ -1496,17 +1498,29 @@
}
/**
- * Returns true if the task is in expected scroll position.
- *
- * @param taskIndex the index of the task
+ * Returns true if the given TaskView is in expected scroll position.
*/
- public boolean isTaskInExpectedScrollPosition(int taskIndex) {
- return getScrollForPage(taskIndex) == getPagedOrientationHandler().getPrimaryScroll(this);
+ public boolean isTaskInExpectedScrollPosition(TaskView taskView) {
+ return getScrollForPage(indexOfChild(taskView))
+ == getPagedOrientationHandler().getPrimaryScroll(this);
}
private boolean isFocusedTaskInExpectedScrollPosition() {
TaskView focusedTask = getFocusedTaskView();
- return focusedTask != null && isTaskInExpectedScrollPosition(indexOfChild(focusedTask));
+ return focusedTask != null && isTaskInExpectedScrollPosition(focusedTask);
+ }
+
+ /**
+ * Launch DesktopTaskView if found.
+ * @return provides runnable list to attach runnable at end of Desktop Mode launch
+ */
+ public RunnableList launchDesktopTaskView() {
+ for (TaskView taskView : getTaskViews()) {
+ if (taskView instanceof DesktopTaskView) {
+ return taskView.launchWithAnimation();
+ }
+ }
+ return null;
}
/**
@@ -1957,18 +1971,20 @@
}
// Keep same previous focused task
- TaskView newFocusedTaskView = getTaskViewByTaskIds(focusedTaskIds);
- if (enableLargeDesktopWindowingTile() && newFocusedTaskView instanceof DesktopTaskView) {
- newFocusedTaskView = null;
+ TaskView newFocusedTaskView = null;
+ if (!enableGridOnlyOverview()) {
+ newFocusedTaskView = getTaskViewByTaskIds(focusedTaskIds);
+ if (enableLargeDesktopWindowingTile()
+ && newFocusedTaskView instanceof DesktopTaskView) {
+ newFocusedTaskView = null;
+ }
+ // If the list changed, maybe the focused task doesn't exist anymore.
+ if (newFocusedTaskView == null) {
+ newFocusedTaskView = mUtils.getExpectedFocusedTask(getTaskViews());
+ }
}
- // If the list changed, maybe the focused task doesn't exist anymore
- int newFocusedTaskViewIndex = mUtils.getFocusedTaskIndex(taskGroups);
- if (newFocusedTaskView == null && getTaskViewCount() > newFocusedTaskViewIndex) {
- newFocusedTaskView = getTaskViewAt(newFocusedTaskViewIndex);
- }
-
- setFocusedTaskViewId(newFocusedTaskView != null && !enableGridOnlyOverview()
- ? newFocusedTaskView.getTaskViewId() : INVALID_TASK_ID);
+ setFocusedTaskViewId(
+ newFocusedTaskView != null ? newFocusedTaskView.getTaskViewId() : INVALID_TASK_ID);
updateTaskSize();
updateChildTaskOrientations();
@@ -1987,6 +2003,7 @@
// for cases where the running task isn't included in this load plan (e.g. if
// the current running task is excludedFromRecents.)
showCurrentTask(mActiveGestureRunningTasks, "applyLoadPlan");
+ newRunningTaskView = getRunningTaskView();
} else {
setRunningTaskViewId(INVALID_TASK_ID);
}
@@ -2006,12 +2023,9 @@
} else if (previousFocusedPage != INVALID_PAGE) {
targetPage = previousFocusedPage;
} else {
- // Set the current page to the running task, but not if settling on new task.
- if (hasAllValidTaskIds(runningTaskIds)) {
- targetPage = indexOfChild(newRunningTaskView);
- } else if (getTaskViewCount() > newFocusedTaskViewIndex) {
- targetPage = indexOfChild(requireTaskViewAt(newFocusedTaskViewIndex));
- }
+ targetPage = indexOfChild(
+ mUtils.getExpectedCurrentTask(newRunningTaskView, newFocusedTaskView,
+ getTaskViews()));
}
if (targetPage != -1 && mCurrentPage != targetPage) {
int finalTargetPage = targetPage;
@@ -2107,7 +2121,7 @@
if (Arrays.stream(taskView.getTaskIds()).noneMatch(
taskId -> taskId == mIgnoreResetTaskId)) {
taskView.resetViewTransforms();
- taskView.setIconScaleAndDim(mTaskIconScaledDown ? 0 : 1);
+ taskView.setIconVisibleForGesture(mTaskIconVisible);
taskView.setStableAlpha(mContentAlpha);
taskView.setFullscreenProgress(mFullscreenProgress);
taskView.setModalness(mTaskModalness);
@@ -2775,7 +2789,7 @@
setEnableFreeScroll(false);
setEnableDrawingLiveTile(false);
setRunningTaskHidden(true);
- setTaskIconScaledDown(true);
+ setTaskIconVisible(false);
}
/**
@@ -2794,7 +2808,7 @@
* {@link #onGestureAnimationStart} and {@link #onGestureAnimationEnd()}.
*/
public void onSwipeUpAnimationSuccess() {
- animateUpTaskIconScale();
+ startIconFadeInOnGestureComplete();
setSwipeDownShouldLaunchApp(true);
}
@@ -2921,7 +2935,7 @@
setEnableDrawingLiveTile(mCurrentGestureEndTarget == GestureState.GestureEndTarget.RECENTS);
Log.d(TAG, "onGestureAnimationEnd - mEnableDrawingLiveTile: " + mEnableDrawingLiveTile);
setRunningTaskHidden(false);
- animateUpTaskIconScale();
+ startIconFadeInOnGestureComplete();
animateActionsViewIn();
mCurrentGestureEndTarget = null;
@@ -3045,7 +3059,7 @@
if (mRunningTaskViewId != -1) {
// Reset the state on the old running task view
- setTaskIconScaledDown(false);
+ setTaskIconVisible(true);
setRunningTaskViewShowScreenshot(true);
setRunningTaskHidden(false);
}
@@ -3114,25 +3128,31 @@
}
}
- public void setTaskIconScaledDown(boolean isScaledDown) {
- if (mTaskIconScaledDown != isScaledDown) {
- mTaskIconScaledDown = isScaledDown;
+ /**
+ * Updates icon visibility when going in or out of overview.
+ */
+ public void setTaskIconVisible(boolean isVisible) {
+ if (mTaskIconVisible != isVisible) {
+ mTaskIconVisible = isVisible;
for (TaskView taskView : getTaskViews()) {
- taskView.setIconScaleAndDim(mTaskIconScaledDown ? 0 : 1);
+ taskView.setIconVisibleForGesture(mTaskIconVisible);
}
}
}
private void animateActionsViewIn() {
if (!showAsGrid() || isFocusedTaskInExpectedScrollPosition()) {
- animateActionsViewAlpha(1, TaskView.SCALE_ICON_DURATION);
+ animateActionsViewAlpha(1, TaskView.FADE_IN_ICON_DURATION);
}
}
- public void animateUpTaskIconScale() {
- mTaskIconScaledDown = false;
+ /**
+ * Updates icon visibility when gesture is settled.
+ */
+ public void startIconFadeInOnGestureComplete() {
+ mTaskIconVisible = true;
for (TaskView taskView : getTaskViews()) {
- taskView.animateIconScaleAndDimIntoView();
+ taskView.startIconFadeInOnGestureComplete();
}
}
@@ -3922,7 +3942,7 @@
anim.setFloat(taskView, taskView.getSecondaryDismissTranslationProperty(),
secondaryTranslation, clampToProgress(LINEAR, animationStartProgress,
dismissTranslationInterpolationEnd));
- anim.add(taskView.getFocusTransitionScaleAndDimOutAnimator(),
+ anim.add(taskView.getDismissIconFadeOutAnimator(),
clampToProgress(LINEAR, 0f, ANIMATION_DISMISS_PROGRESS_MIDPOINT));
} else if ((isFocusedTaskDismissed && nextFocusedTaskView != null && isSameGridRow(
taskView, nextFocusedTaskView))
@@ -4106,7 +4126,7 @@
? INVALID_TASK_ID
: finalNextFocusedTaskView.getTaskViewId());
mTopRowIdSet.remove(mFocusedTaskViewId);
- finalNextFocusedTaskView.animateIconScaleAndDimIntoView();
+ finalNextFocusedTaskView.getDismissIconFadeInAnimator().start();
}
updateTaskSize();
updateChildTaskOrientations();
@@ -4701,7 +4721,7 @@
/**
* Returns the current list of [TaskView] children.
*/
- private Iterable<TaskView> getTaskViews() {
+ public Iterable<TaskView> getTaskViews() {
return mUtils.getTaskViews(getTaskViewCount(), this::requireTaskViewAt);
}
@@ -5394,13 +5414,6 @@
mSplitHiddenTaskViewIndex = -1;
if (mSplitHiddenTaskView != null) {
mSplitHiddenTaskView.setThumbnailVisibility(VISIBLE, INVALID_TASK_ID);
- // mSplitHiddenTaskView is set when split select animation starts. The TaskView is only
- // removed when when the animation finishes. So in the case of overview being dismissed
- // during the animation, we should not call clearAndRecycleTaskView() because it has
- // not been removed yet.
- if (mSplitHiddenTaskView.getParent() == null) {
- clearAndRecycleTaskView(mSplitHiddenTaskView);
- }
mSplitHiddenTaskView = null;
}
}
@@ -5888,11 +5901,18 @@
}
/**
+ * Finish recents animation.
+ */
+ public void finishRecentsAnimation(boolean toRecents, boolean shouldPip,
+ @Nullable Runnable onFinishComplete) {
+ finishRecentsAnimation(toRecents, shouldPip, false, onFinishComplete);
+ }
+ /**
* NOTE: Whatever value gets passed through to the toRecents param may need to also be set on
* {@link #mRecentsAnimationController#setWillFinishToHome}.
*/
public void finishRecentsAnimation(boolean toRecents, boolean shouldPip,
- @Nullable Runnable onFinishComplete) {
+ boolean allAppTargetsAreTranslucent, @Nullable Runnable onFinishComplete) {
Log.d(TAG, "finishRecentsAnimation - mRecentsAnimationController: "
+ mRecentsAnimationController);
// TODO(b/197232424#comment#10) Move this back into onRecentsAnimationComplete(). Maybe?
@@ -5906,8 +5926,9 @@
}
final boolean sendUserLeaveHint = toRecents && shouldPip;
- if (sendUserLeaveHint) {
+ if (sendUserLeaveHint && !com.android.wm.shell.Flags.enablePip2()) {
// Notify the SysUI to use fade-in animation when entering PiP from live tile.
+ // Note: PiP2 handles entering differently, so skip if enable_pip2=true.
final SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.get(getContext());
systemUiProxy.setPipAnimationTypeToAlpha();
systemUiProxy.setShelfHeight(true, mContainer.getDeviceProfile().hotseatBarSizePx);
@@ -5924,7 +5945,7 @@
tx, null /* overlay */);
}
}
- mRecentsAnimationController.finish(toRecents, () -> {
+ mRecentsAnimationController.finish(toRecents, allAppTargetsAreTranslucent, () -> {
if (onFinishComplete != null) {
onFinishComplete.run();
}
@@ -6457,6 +6478,12 @@
return mSizeStrategy;
}
+
+ /**
+ * Returns the container interface
+ */
+ protected abstract BaseContainerInterface<STATE_TYPE, ?> getContainerInterface(int displayId);
+
/**
* Set all the task views to color tint scrim mode, dimming or tinting them all. Allows the
* tasks to be dimmed while other elements in the recents view are left alone.
@@ -6770,8 +6797,8 @@
if (mDesktopRecentsTransitionController == null) {
return;
}
- mDesktopRecentsTransitionController.moveToDesktop(taskContainer.getTask().key.id,
- transitionSource);
+
+ mDesktopRecentsTransitionController.moveToDesktop(taskContainer, transitionSource);
successCallback.run();
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 082971c..084ea4b 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -31,7 +31,6 @@
import android.util.FloatProperty
import android.util.Log
import android.view.Display
-import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.View.OnClickListener
@@ -78,7 +77,6 @@
import com.android.quickstep.TaskOverlayFactory
import com.android.quickstep.TaskViewUtils
import com.android.quickstep.orientation.RecentsPagedOrientationHandler
-import com.android.quickstep.task.thumbnail.TaskThumbnailView
import com.android.quickstep.util.ActiveGestureErrorDetector
import com.android.quickstep.util.ActiveGestureLog
import com.android.quickstep.util.BorderAnimator
@@ -434,37 +432,54 @@
// Used to cache thumbnail bounds to avoid recalculating on every hover move.
private var thumbnailBounds = Rect()
- private var focusTransitionProgress = 1f
+ // Progress variable indicating if the TaskView is in a settled state:
+ // 0 = The TaskView is in a transitioning state e.g. during gesture, in quickswitch carousel,
+ // becoming focus task etc.
+ // 1 = The TaskView is settled and no longer transitioning
+ private var settledProgress = 1f
set(value) {
field = value
- onFocusTransitionProgressUpdated(field)
+ onSettledProgressUpdated(field)
}
- private val focusTransitionPropertyFactory =
+ private val settledProgressPropertyFactory =
MultiPropertyFactory(
this,
- FOCUS_TRANSITION,
- FOCUS_TRANSITION_INDEX_COUNT,
+ SETTLED_PROGRESS,
+ SETTLED_PROGRESS_INDEX_COUNT,
{ x: Float, y: Float -> x * y },
1f,
)
- private val focusTransitionFullscreen =
- focusTransitionPropertyFactory.get(FOCUS_TRANSITION_INDEX_FULLSCREEN)
- private val focusTransitionScaleAndDim =
- focusTransitionPropertyFactory.get(FOCUS_TRANSITION_INDEX_SCALE_AND_DIM)
+ private val settledProgressFullscreen =
+ settledProgressPropertyFactory.get(SETTLED_PROGRESS_INDEX_FULLSCREEN)
+ private val settledProgressGesture =
+ settledProgressPropertyFactory.get(SETTLED_PROGRESS_INDEX_GESTURE)
+ private val settledProgressDismiss =
+ settledProgressPropertyFactory.get(SETTLED_PROGRESS_INDEX_DISMISS)
/**
- * Returns an animator of [focusTransitionScaleAndDim] that transition out with a built-in
+ * Returns an animator of [settledProgressDismiss] that transition in with a built-in
* interpolator.
*/
- fun getFocusTransitionScaleAndDimOutAnimator(): ObjectAnimator =
+ fun getDismissIconFadeInAnimator(): ObjectAnimator =
+ ObjectAnimator.ofFloat(settledProgressDismiss, MULTI_PROPERTY_VALUE, 1f).apply {
+ duration = FADE_IN_ICON_DURATION
+ interpolator = FADE_IN_ICON_INTERPOLATOR
+ }
+
+ /**
+ * Returns an animator of [settledProgressDismiss] that transition out with a built-in
+ * interpolator. [AnimatedFloat] is used to apply another level of interpolation, on top of
+ * interpolator set to the [Animator] by the caller.
+ */
+ fun getDismissIconFadeOutAnimator(): ObjectAnimator =
AnimatedFloat { v ->
- focusTransitionScaleAndDim.value =
- FOCUS_TRANSITION_FAST_OUT_INTERPOLATOR.getInterpolation(v)
+ settledProgressDismiss.value =
+ SETTLED_PROGRESS_FAST_OUT_INTERPOLATOR.getInterpolation(v)
}
.animateToValue(1f, 0f)
- private var iconAndDimAnimator: ObjectAnimator? = null
+ private var iconFadeInOnGestureCompleteAnimator: ObjectAnimator? = null
// The current background requests to load the task thumbnail and icon
private val pendingThumbnailLoadRequests = mutableListOf<CancellableTask<*>>()
private val pendingIconLoadRequests = mutableListOf<CancellableTask<*>>()
@@ -677,6 +692,28 @@
return super.performAccessibilityAction(action, arguments)
}
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+ inflateViewStubs()
+ }
+
+ protected open fun inflateViewStubs() {
+ findViewById<ViewStub>(R.id.snapshot)
+ ?.apply {
+ layoutResource =
+ if (enableRefactorTaskThumbnail()) R.layout.task_thumbnail
+ else R.layout.task_thumbnail_deprecated
+ }
+ ?.inflate()
+ findViewById<ViewStub>(R.id.icon)
+ ?.apply {
+ layoutResource =
+ if (enableOverviewIconMenu()) R.layout.icon_app_chip_view
+ else R.layout.icon_view
+ }
+ ?.inflate()
+ }
+
/** Updates this task view to the given {@param task}. */
open fun bind(
task: Task,
@@ -718,27 +755,11 @@
@StagePosition stagePosition: Int,
taskOverlayFactory: TaskOverlayFactory,
): TaskContainer {
- val existingThumbnailView: View = findViewById(thumbnailViewId)!!
- val snapshotView =
- when {
- !enableRefactorTaskThumbnail() -> existingThumbnailView
- existingThumbnailView is TaskThumbnailView -> existingThumbnailView
- else -> {
- val indexOfSnapshotView = indexOfChild(existingThumbnailView)
- LayoutInflater.from(context)
- .inflate(R.layout.task_thumbnail, this, false)
- .also {
- it.id = thumbnailViewId
- addView(it, indexOfSnapshotView, existingThumbnailView.layoutParams)
- removeView(existingThumbnailView)
- }
- }
- }
- val iconView = getOrInflateIconView(iconViewId)
+ val iconView = findViewById<View>(iconViewId) as TaskViewIcon
return TaskContainer(
this,
task,
- snapshotView,
+ findViewById(thumbnailViewId),
iconView,
TransformingTouchDelegate(iconView.asView()),
stagePosition,
@@ -748,18 +769,6 @@
)
}
- protected fun getOrInflateIconView(@IdRes iconViewId: Int): TaskViewIcon {
- val iconView = findViewById<View>(iconViewId)!!
- return iconView as? TaskViewIcon
- ?: (iconView as ViewStub)
- .apply {
- layoutResource =
- if (enableOverviewIconMenu()) R.layout.icon_app_chip_view
- else R.layout.icon_view
- }
- .inflate() as TaskViewIcon
- }
-
fun containsMultipleTasks() = taskContainers.size > 1
/**
@@ -1423,23 +1432,23 @@
* Called to animate a smooth transition when going directly from an app into Overview (and vice
* versa). Icons fade in, and DWB banners slide in with a "shift up" animation.
*/
- private fun onFocusTransitionProgressUpdated(focusTransitionProgress: Float) {
+ private fun onSettledProgressUpdated(settledProgress: Float) {
taskContainers.forEach {
- it.iconView.setContentAlpha(focusTransitionProgress)
- it.digitalWellBeingToast?.bannerOffsetPercentage = 1f - focusTransitionProgress
+ it.iconView.setContentAlpha(settledProgress)
+ it.digitalWellBeingToast?.bannerOffsetPercentage = 1f - settledProgress
}
}
- fun animateIconScaleAndDimIntoView() {
- iconAndDimAnimator?.cancel()
- iconAndDimAnimator =
- ObjectAnimator.ofFloat(focusTransitionScaleAndDim, MULTI_PROPERTY_VALUE, 0f, 1f).apply {
- duration = SCALE_ICON_DURATION
+ fun startIconFadeInOnGestureComplete() {
+ iconFadeInOnGestureCompleteAnimator?.cancel()
+ iconFadeInOnGestureCompleteAnimator =
+ ObjectAnimator.ofFloat(settledProgressGesture, MULTI_PROPERTY_VALUE, 1f).apply {
+ duration = FADE_IN_ICON_DURATION
interpolator = Interpolators.LINEAR
addListener(
object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
- iconAndDimAnimator = null
+ iconFadeInOnGestureCompleteAnimator = null
}
}
)
@@ -1447,9 +1456,9 @@
}
}
- fun setIconScaleAndDim(iconScale: Float) {
- iconAndDimAnimator?.cancel()
- focusTransitionScaleAndDim.value = iconScale
+ fun setIconVisibleForGesture(isVisible: Boolean) {
+ iconFadeInOnGestureCompleteAnimator?.cancel()
+ settledProgressGesture.value = if (isVisible) 1f else 0f
}
/** Set a color tint on the snapshot and supporting views. */
@@ -1544,8 +1553,8 @@
it.iconView.setVisibility(if (fullscreenProgress < 1) VISIBLE else INVISIBLE)
it.overlay.setFullscreenProgress(fullscreenProgress)
}
- focusTransitionFullscreen.value =
- FOCUS_TRANSITION_FAST_OUT_INTERPOLATOR.getInterpolation(1 - fullscreenProgress)
+ settledProgressFullscreen.value =
+ SETTLED_PROGRESS_FAST_OUT_INTERPOLATOR.getInterpolation(1 - fullscreenProgress)
updateFullscreenParams()
}
@@ -1602,7 +1611,8 @@
}
dismissScale = 1f
translationZ = 0f
- setIconScaleAndDim(1f)
+ setIconVisibleForGesture(true)
+ settledProgressDismiss.value = 1f
setColorTint(0f, 0)
}
@@ -1630,9 +1640,10 @@
const val FLAG_UPDATE_ALL =
(FLAG_UPDATE_ICON or FLAG_UPDATE_THUMBNAIL or FLAG_UPDATE_CORNER_RADIUS)
- const val FOCUS_TRANSITION_INDEX_FULLSCREEN = 0
- const val FOCUS_TRANSITION_INDEX_SCALE_AND_DIM = 1
- const val FOCUS_TRANSITION_INDEX_COUNT = 2
+ const val SETTLED_PROGRESS_INDEX_FULLSCREEN = 0
+ const val SETTLED_PROGRESS_INDEX_GESTURE = 1
+ const val SETTLED_PROGRESS_INDEX_DISMISS = 2
+ const val SETTLED_PROGRESS_INDEX_COUNT = 3
private const val ALPHA_INDEX_STABLE = 0
private const val ALPHA_INDEX_ATTACH = 1
@@ -1642,25 +1653,26 @@
/** The maximum amount that a task view can be scrimmed, dimmed or tinted. */
const val MAX_PAGE_SCRIM_ALPHA = 0.4f
- const val SCALE_ICON_DURATION: Long = 120
+ const val FADE_IN_ICON_DURATION: Long = 120
private const val DIM_ANIM_DURATION: Long = 700
- private const val FOCUS_TRANSITION_THRESHOLD =
- SCALE_ICON_DURATION.toFloat() / DIM_ANIM_DURATION
- val FOCUS_TRANSITION_FAST_OUT_INTERPOLATOR =
+ private const val SETTLE_TRANSITION_THRESHOLD =
+ FADE_IN_ICON_DURATION.toFloat() / DIM_ANIM_DURATION
+ val SETTLED_PROGRESS_FAST_OUT_INTERPOLATOR =
Interpolators.clampToProgress(
Interpolators.FAST_OUT_SLOW_IN,
- 1f - FOCUS_TRANSITION_THRESHOLD,
+ 1f - SETTLE_TRANSITION_THRESHOLD,
1f,
)!!
+ private val FADE_IN_ICON_INTERPOLATOR = Interpolators.LINEAR
private val SYSTEM_GESTURE_EXCLUSION_RECT = listOf(Rect())
- private val FOCUS_TRANSITION: FloatProperty<TaskView> =
- object : FloatProperty<TaskView>("focusTransition") {
+ private val SETTLED_PROGRESS: FloatProperty<TaskView> =
+ object : FloatProperty<TaskView>("settleTransition") {
override fun setValue(taskView: TaskView, v: Float) {
- taskView.focusTransitionProgress = v
+ taskView.settledProgress = v
}
- override fun get(taskView: TaskView) = taskView.focusTransitionProgress
+ override fun get(taskView: TaskView) = taskView.settledProgress
}
private val SPLIT_SELECT_TRANSLATION_X: FloatProperty<TaskView> =
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt
index 011ba7e..eb13b55 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt
@@ -22,7 +22,9 @@
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
import com.android.launcher3.Flags.FLAG_TASKBAR_OVERFLOW
+import com.android.launcher3.R
import com.android.launcher3.taskbar.TaskbarControllerTestUtil.runOnMainSync
+import com.android.launcher3.taskbar.TaskbarViewTestUtil.createHotseatItems
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
import com.android.launcher3.taskbar.rules.MockedRecentsModelTestRule
@@ -137,6 +139,54 @@
@Test
@TaskbarMode(PINNED)
+ fun testOverflownTaskbarWithNoSpaceForRecentApps_pinned() {
+ val initialIconCount = currentNumberOfTaskbarIcons.coerceAtLeast(2)
+
+ // Create two "recent" desktop tasks, and then add enough hotseat items so the taskbar
+ // reaches max number of items with hotseat item icons, all apps and divider icons only.
+ // I.e. so all desktop tasks are in taskbar overflow.
+ createDesktopTask(2)
+ runOnMainSync {
+ val taskbarView: TaskbarView =
+ taskbarUnitTestRule.activityContext.dragLayer.findViewById(R.id.taskbar_view)
+ taskbarView.updateItems(
+ createHotseatItems(maxNumberOfTaskbarIcons - initialIconCount),
+ recentAppsController.shownTasks,
+ )
+ }
+
+ // Verify that taskbar overflow view is shown (eventhough it exceeds max taskbar icons).
+ assertThat(currentNumberOfTaskbarIcons).isEqualTo(maxNumberOfTaskbarIcons + 1)
+ assertThat(taskbarOverflowIconIndex).isEqualTo(maxNumberOfTaskbarIcons)
+ assertThat(overflowItems).containsExactlyElementsIn(0..1)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testOverflownTaskbarWithNoSpaceForRecentApps_singleRecent_pinned() {
+ val initialIconCount = currentNumberOfTaskbarIcons.coerceAtLeast(2)
+
+ // Create a "recent" desktop task, and then add enough hotseat items so the taskbar
+ // reaches max number of items with hotseat item icons, all apps and divider icons only.
+ // I.e. so the single desktop tasks is in taskbar overflow.
+ createDesktopTask(1)
+ runOnMainSync {
+ val taskbarView: TaskbarView =
+ taskbarUnitTestRule.activityContext.dragLayer.findViewById(R.id.taskbar_view)
+ taskbarView.updateItems(
+ createHotseatItems(maxNumberOfTaskbarIcons - initialIconCount),
+ recentAppsController.shownTasks,
+ )
+ }
+
+ // Verify that recent task is shown (eventhough it exceeds max taskbar icons), and that
+ // the taskbar overflow view is not added for the single recent app.
+ assertThat(currentNumberOfTaskbarIcons).isEqualTo(maxNumberOfTaskbarIcons + 1)
+ assertThat(taskbarOverflowIconIndex).isEqualTo(-1)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
fun testBubbleBarReducesTaskbarMaxNumIcons_pinned() {
var initialMaxNumIconViews = maxNumberOfTaskbarIcons
assertThat(initialMaxNumIconViews).isGreaterThan(0)
@@ -296,6 +346,20 @@
}
}
+ private val overflowItems: List<Int>
+ get() {
+ return getOnUiThread {
+ val overflowIcon =
+ taskbarViewController.iconViews.firstOrNull { it is TaskbarOverflowView }
+
+ if (overflowIcon is TaskbarOverflowView) {
+ overflowIcon.itemIds
+ } else {
+ emptyList()
+ }
+ }
+ }
+
/**
* Adds enough running apps for taskbar to enter overflow of `targetOverflowSize`, and verifies
* * max number of icons in the taskbar remains unchanged
@@ -318,6 +382,9 @@
assertThat(currentNumberOfTaskbarIcons).isEqualTo(maxNumIconViews)
assertThat(taskbarOverflowIconIndex)
.isEqualTo(if (targetOverflowSize > 0) initialIconCount else -1)
+ if (targetOverflowSize > 0) {
+ assertThat(overflowItems).containsExactlyElementsIn(0..targetOverflowSize)
+ }
return maxNumIconViews
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewTest.kt
index 0bb404b..44d31c4 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewTest.kt
@@ -154,4 +154,13 @@
}
assertThat(taskbarView).hasIconTypes(ALL_APPS, HOTSEAT, DIVIDER, RECENT)
}
+
+ @Test
+ fun testUpdateItem_addHotseatItemAfterRecentsItem_hotseatItemBeforeDivider() {
+ runOnMainSync {
+ taskbarView.updateItems(emptyArray(), createRecents(1))
+ taskbarView.updateItems(createHotseatItems(1), createRecents(1))
+ }
+ assertThat(taskbarView).hasIconTypes(ALL_APPS, HOTSEAT, DIVIDER, RECENT)
+ }
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewTestUtil.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewTestUtil.kt
index a6bdbb0..f2dcf77 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewTestUtil.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewTestUtil.kt
@@ -99,7 +99,7 @@
/** Verifies that recents from [startIndex] have IDs that match [expectedIds] in order. */
fun hasRecentsOrder(startIndex: Int, expectedIds: List<Int>) {
val actualIds =
- view.iconViews.slice(startIndex..<expectedIds.size).map {
+ view.iconViews.slice(startIndex..<startIndex + expectedIds.size).map {
assertThat(it.tag).isInstanceOf(GroupTask::class.java)
(it.tag as? GroupTask)?.task1?.key?.id
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewWithLayoutTransitionTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewWithLayoutTransitionTest.kt
index 78d8e5d..4b6d5e5 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewWithLayoutTransitionTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewWithLayoutTransitionTest.kt
@@ -18,6 +18,7 @@
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
+import android.view.View
import com.android.launcher3.Flags.FLAG_TASKBAR_RECENTS_LAYOUT_TRANSITION
import com.android.launcher3.R
import com.android.launcher3.taskbar.TaskbarControllerTestUtil.runOnMainSync
@@ -33,6 +34,7 @@
import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
import com.android.launcher3.util.LauncherMultivalentJUnit
import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
+import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -49,6 +51,9 @@
private lateinit var taskbarView: TaskbarView
+ private val iconViews: Array<View>
+ get() = taskbarView.iconViews
+
@Before
fun obtainView() {
taskbarView = taskbarUnitTestRule.activityContext.dragLayer.findViewById(R.id.taskbar_view)
@@ -131,4 +136,93 @@
}
assertThat(taskbarView).hasIconTypes(RECENT, DIVIDER, HOTSEAT, ALL_APPS)
}
+
+ @Test
+ fun testUpdateItems_addRecentsItem_viewAddedOnRight() {
+ runOnMainSync {
+ taskbarView.updateItems(emptyArray(), createRecents(1))
+ val prevIconViews = iconViews
+
+ val newRecents = createRecents(2)
+ taskbarView.updateItems(emptyArray(), newRecents)
+
+ assertThat(taskbarView).hasRecentsOrder(startIndex = 2, expectedIds = listOf(0, 1))
+ assertThat(iconViews[2]).isSameInstanceAs(prevIconViews[2])
+ assertThat(iconViews.last() in prevIconViews).isFalse()
+ }
+ }
+
+ @Test
+ @ForceRtl
+ fun testUpdateItems_rtl_addRecentsItem_viewAddedOnLeft() {
+ runOnMainSync {
+ taskbarView.updateItems(emptyArray(), createRecents(1))
+ val prevIconViews = iconViews
+
+ val newRecents = createRecents(2)
+ taskbarView.updateItems(emptyArray(), newRecents)
+
+ assertThat(taskbarView).hasRecentsOrder(startIndex = 0, expectedIds = listOf(1, 0))
+ assertThat(iconViews[1]).isSameInstanceAs(prevIconViews.first())
+ assertThat(iconViews.first() in prevIconViews).isFalse()
+ }
+ }
+
+ @Test
+ fun testUpdateItems_removeFirstRecentsItem_correspondingViewRemoved() {
+ runOnMainSync {
+ val recents = createRecents(2)
+ taskbarView.updateItems(emptyArray(), recents)
+
+ val expectedViewToRemove = iconViews[2]
+ assertThat(expectedViewToRemove.tag).isEqualTo(recents.first())
+
+ taskbarView.updateItems(emptyArray(), listOf(recents.last()))
+ assertThat(expectedViewToRemove in iconViews).isFalse()
+ }
+ }
+
+ @Test
+ fun testUpdateItems_removeLastRecentsItem_correspondingViewRemoved() {
+ runOnMainSync {
+ val recents = createRecents(2)
+ taskbarView.updateItems(emptyArray(), recents)
+
+ val expectedViewToRemove = iconViews[3]
+ assertThat(expectedViewToRemove.tag).isEqualTo(recents.last())
+
+ taskbarView.updateItems(emptyArray(), listOf(recents.first()))
+ assertThat(expectedViewToRemove in iconViews).isFalse()
+ }
+ }
+
+ @Test
+ @ForceRtl
+ fun testUpdateItems_rtl_removeFirstRecentsItem_correspondingViewRemoved() {
+ runOnMainSync {
+ val recents = createRecents(2)
+ taskbarView.updateItems(emptyArray(), recents)
+
+ val expectedViewToRemove = iconViews[1]
+ assertThat(expectedViewToRemove.tag).isEqualTo(recents.first())
+
+ taskbarView.updateItems(emptyArray(), listOf(recents.last()))
+ assertThat(expectedViewToRemove in iconViews).isFalse()
+ }
+ }
+
+ @Test
+ @ForceRtl
+ fun testUpdateItems_rtl_removeLastRecentsItem_correspondingViewRemoved() {
+ runOnMainSync {
+ val recents = createRecents(2)
+ taskbarView.updateItems(emptyArray(), recents)
+
+ val expectedViewToRemove = iconViews[0]
+ assertThat(expectedViewToRemove.tag).isEqualTo(recents.last())
+
+ taskbarView.updateItems(emptyArray(), listOf(recents.first()))
+ assertThat(expectedViewToRemove in iconViews).isFalse()
+ }
+ }
}
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 06227e2..44070cf 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
@@ -23,6 +23,7 @@
import android.graphics.drawable.ColorDrawable
import android.view.LayoutInflater
import android.view.View
+import android.view.View.INVISIBLE
import android.view.View.VISIBLE
import android.widget.FrameLayout
import android.widget.TextView
@@ -78,7 +79,7 @@
private lateinit var flyoutContainer: FrameLayout
private lateinit var bubbleStashController: BubbleStashController
private lateinit var flyoutController: BubbleBarFlyoutController
- private val onExpandedNoOp = Runnable {}
+ private val emptyRunnable = Runnable {}
private val flyoutView: View?
get() = flyoutContainer.findViewById(R.id.bubble_bar_flyout_view)
@@ -106,7 +107,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpandedNoOp,
+ onExpanded = emptyRunnable,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
@@ -162,7 +164,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpandedNoOp,
+ onExpanded = emptyRunnable,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
@@ -219,7 +222,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpandedNoOp,
+ onExpanded = emptyRunnable,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
@@ -268,7 +272,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpandedNoOp,
+ onExpanded = emptyRunnable,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
@@ -320,7 +325,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpandedNoOp,
+ onExpanded = emptyRunnable,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
@@ -359,7 +365,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpanded,
+ onExpanded = onExpanded,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
@@ -405,7 +412,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpanded,
+ onExpanded = onExpanded,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
@@ -457,7 +465,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpanded,
+ onExpanded = onExpanded,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
@@ -508,17 +517,21 @@
val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+ var notifiedBubbleBarVisible = false
+ val onBubbleBarVisible = Runnable { notifiedBubbleBarVisible = true }
val animator =
BubbleBarViewAnimator(
bubbleBarView,
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpandedNoOp,
+ onExpanded = emptyRunnable,
+ onBubbleBarVisible = onBubbleBarVisible,
animatorScheduler,
)
InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ bubbleBarView.visibility = INVISIBLE
animator.animateToInitialState(bubble, isInApp = true, isExpanding = false)
}
@@ -546,6 +559,8 @@
assertThat(bubbleBarView.alpha).isEqualTo(0)
assertThat(handle.translationY).isEqualTo(0)
assertThat(handle.alpha).isEqualTo(1)
+ assertThat(bubbleBarView.visibility).isEqualTo(VISIBLE)
+ assertThat(notifiedBubbleBarVisible).isTrue()
verify(bubbleStashController).stashBubbleBarImmediate()
}
@@ -571,7 +586,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpanded,
+ onExpanded = onExpanded,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
@@ -607,7 +623,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpandedNoOp,
+ onExpanded = emptyRunnable,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
@@ -653,7 +670,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpanded,
+ onExpanded = onExpanded,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
@@ -703,7 +721,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpanded,
+ onExpanded = onExpanded,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
@@ -751,7 +770,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpandedNoOp,
+ onExpanded = emptyRunnable,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
@@ -807,7 +827,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpanded,
+ onExpanded = onExpanded,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
@@ -862,7 +883,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpanded,
+ onExpanded = onExpanded,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
@@ -927,7 +949,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpanded,
+ onExpanded = onExpanded,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
@@ -987,7 +1010,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpandedNoOp,
+ onExpanded = emptyRunnable,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
@@ -1057,7 +1081,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpandedNoOp,
+ onExpanded = emptyRunnable,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
@@ -1133,7 +1158,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpandedNoOp,
+ onExpanded = emptyRunnable,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
@@ -1220,7 +1246,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpandedNoOp,
+ onExpanded = emptyRunnable,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
@@ -1334,7 +1361,8 @@
bubbleStashController,
flyoutController,
bubbleBarParentViewController,
- onExpandedNoOp,
+ onExpanded = emptyRunnable,
+ onBubbleBarVisible = emptyRunnable,
animatorScheduler,
)
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
index 970bdec..c93507a 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
@@ -59,7 +59,7 @@
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StatefulContainer;
import com.android.launcher3.util.SystemUiController;
-import com.android.quickstep.fallback.window.RecentsWindowManager;
+import com.android.quickstep.fallback.window.RecentsWindowFactory;
import com.android.quickstep.util.ContextInitListener;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.RecentsViewContainer;
@@ -173,7 +173,8 @@
@Before
public void setUpRecentsContainer() {
- mTaskAnimationManager = new TaskAnimationManager(mContext, getRecentsWindowManager());
+ mTaskAnimationManager = new TaskAnimationManager(mContext, getRecentsWindowFactory(),
+ mRecentsAnimationDeviceState);
RecentsViewContainer recentsContainer = getRecentsContainer();
RECENTS_VIEW recentsView = getRecentsView();
@@ -365,7 +366,7 @@
}
@Nullable
- protected RecentsWindowManager getRecentsWindowManager() {
+ protected RecentsWindowFactory getRecentsWindowFactory() {
return null;
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsWindowSwipeHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsWindowSwipeHandlerTestCase.java
index 1bdf273..24b2d4e 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsWindowSwipeHandlerTestCase.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsWindowSwipeHandlerTestCase.java
@@ -16,6 +16,9 @@
package com.android.quickstep;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
+
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
@@ -23,10 +26,12 @@
import com.android.launcher3.util.LauncherMultivalentJUnit;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsState;
+import com.android.quickstep.fallback.window.RecentsWindowFactory;
import com.android.quickstep.fallback.window.RecentsWindowManager;
import com.android.quickstep.fallback.window.RecentsWindowSwipeHandler;
import com.android.quickstep.views.RecentsViewContainer;
+import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -39,8 +44,14 @@
RecentsWindowSwipeHandler,
FallbackWindowInterface> {
- @Mock private RecentsWindowManager mRecentsWindowManager;
+ @Mock private RecentsWindowFactory mRecentsWindowFactory;
@Mock private FallbackRecentsView<RecentsWindowManager> mRecentsView;
+ @Mock private RecentsWindowManager mRecentsWindowManager;
+
+ @Before
+ public void setupRecentsWindowFactory() {
+ when(mRecentsWindowFactory.get(anyInt())).thenReturn(mRecentsWindowManager);
+ }
@NonNull
@Override
@@ -54,13 +65,13 @@
touchTimeMs,
continuingLastGesture,
mInputConsumerController,
- mRecentsWindowManager);
+ mRecentsWindowFactory);
}
@Nullable
@Override
- protected RecentsWindowManager getRecentsWindowManager() {
- return mRecentsWindowManager;
+ protected RecentsWindowFactory getRecentsWindowFactory() {
+ return mRecentsWindowFactory;
}
@NonNull
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt
index d6688d6..1c9ce0b 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt
@@ -49,6 +49,9 @@
override fun getThumbnailById(taskId: Int): Flow<ThumbnailData?> =
getTaskDataById(taskId).map { it?.thumbnail }
+ override fun getCurrentThumbnailById(taskId: Int): ThumbnailData? =
+ tasks.value.firstOrNull { it.key.id == taskId }?.thumbnail
+
override fun setVisibleTasks(visibleTaskIdList: Set<Int>) {
visibleTasks.value = visibleTaskIdList
tasks.value =
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
index 357df6e..e0e7f28 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
@@ -87,6 +87,48 @@
}
@Test
+ fun getThumbnailByIdReturnsNullWithNoLoadedThumbnails() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ assertThat(systemUnderTest.getThumbnailById(1).first()).isNull()
+ }
+
+ @Test
+ fun getCurrentThumbnailByIdReturnsNullWithNoLoadedThumbnails() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ assertThat(systemUnderTest.getCurrentThumbnailById(1)).isNull()
+ }
+
+ @Test
+ fun getThumbnailByIdReturnsThumbnailWithLoadedThumbnails() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+ val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
+
+ systemUnderTest.setVisibleTasks(setOf(1))
+
+ assertThat(systemUnderTest.getThumbnailById(1).first()!!.thumbnail).isEqualTo(bitmap1)
+ }
+
+ @Test
+ fun getCurrentThumbnailByIdReturnsThumbnailWithLoadedThumbnails() =
+ testScope.runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+ val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
+
+ systemUnderTest.setVisibleTasks(setOf(1))
+
+ assertThat(systemUnderTest.getCurrentThumbnailById(1)?.thumbnail).isEqualTo(bitmap1)
+ }
+
+ @Test
fun setVisibleTasksPopulatesThumbnails() =
testScope.runTest {
recentsModel.seedTasks(defaultTaskList)
diff --git a/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java b/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java
index 5dc6932..2c6b750 100644
--- a/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/InputConsumerUtilsTest.java
@@ -56,7 +56,7 @@
import com.android.launcher3.util.LockedUserState;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.views.BaseDragLayer;
-import com.android.quickstep.fallback.window.RecentsWindowManager;
+import com.android.quickstep.fallback.window.RecentsWindowFactory;
import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
import com.android.quickstep.inputconsumers.BubbleBarInputConsumer;
import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer;
@@ -96,10 +96,9 @@
@NonNull private final MainThreadInitializedObject.SandboxContext mContext =
new MainThreadInitializedObject.SandboxContext(getApplicationContext());
- @NonNull private final TaskAnimationManager mTaskAnimationManager = new TaskAnimationManager(
- mContext, mock(RecentsWindowManager.class));
@NonNull private final InputMonitorCompat mInputMonitorCompat = new InputMonitorCompat("", 0);
+ private TaskAnimationManager mTaskAnimationManager;
private InputChannelCompat.InputEventReceiver mInputEventReceiver;
@Nullable private ResetGestureInputConsumer mResetGestureInputConsumer;
@NonNull private Function<GestureState, AnimatedFloat> mSwipeUpProxyProvider = (state) -> null;
@@ -121,6 +120,12 @@
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Before
+ public void setupTaskAnimationManager() {
+ mTaskAnimationManager = new TaskAnimationManager(
+ mContext, mock(RecentsWindowFactory.class), mDeviceState);
+ }
+
+ @Before
public void setupMainThreadInitializedObjects() {
mContext.putObject(LockedUserState.INSTANCE, mLockedUserState);
}
@@ -184,6 +189,7 @@
@Before
public void setupDeviceState() {
+ when(mDeviceState.getDisplayId()).thenReturn(0);
when(mDeviceState.canStartTrackpadGesture()).thenReturn(true);
when(mDeviceState.canStartSystemGesture()).thenReturn(true);
when(mDeviceState.isFullyGesturalNavMode()).thenReturn(true);
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index 77f4c05..c713c3d 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -16,7 +16,7 @@
package com.android.quickstep;
-import static androidx.test.InstrumentationRegistry.getInstrumentation;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.quickstep.NavigationModeSwitchRule.Mode.ALL;
import static com.android.quickstep.NavigationModeSwitchRule.Mode.THREE_BUTTON;
@@ -26,6 +26,7 @@
import android.content.Context;
import android.content.pm.PackageManager;
+import android.os.Process;
import android.util.Log;
import androidx.test.uiautomator.UiDevice;
@@ -153,7 +154,9 @@
Log.d(TAG, "setActiveOverlay: " + overlayPackage + "...");
UiDevice.getInstance(getInstrumentation()).executeShellCommand(
- "cmd overlay enable-exclusive --category " + overlayPackage);
+ String.format("cmd overlay enable-exclusive --user %d --category %s",
+ Process.myUserHandle().getIdentifier(),
+ overlayPackage));
if (currentSysUiNavigationMode() != expectedMode) {
final CountDownLatch latch = new CountDownLatch(1);
diff --git a/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java b/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
index 633a575..960a467 100644
--- a/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
@@ -28,8 +28,9 @@
import android.content.Intent;
import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.quickstep.fallback.window.RecentsWindowManager;
+import com.android.quickstep.fallback.window.RecentsWindowFactory;
import org.junit.Before;
import org.junit.Test;
@@ -40,21 +41,29 @@
@SmallTest
public class TaskAnimationManagerTest {
- @Mock
- private Context mContext;
+ protected final Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
@Mock
- private RecentsWindowManager mRecentsWindowManager;
+ private RecentsWindowFactory mRecentsWindowFactory;
@Mock
private SystemUiProxy mSystemUiProxy;
private TaskAnimationManager mTaskAnimationManager;
+ protected RecentsAnimationDeviceState mRecentsAnimationDeviceState;
+
+ @Before
+ public void setUpRecentsAnimationDeviceState() {
+ runOnMainSync(() ->
+ mRecentsAnimationDeviceState = new RecentsAnimationDeviceState(mContext, true));
+ }
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mTaskAnimationManager = new TaskAnimationManager(mContext, mRecentsWindowManager) {
+ mTaskAnimationManager = new TaskAnimationManager(mContext, mRecentsWindowFactory,
+ mRecentsAnimationDeviceState) {
@Override
SystemUiProxy getSystemUiProxy() {
return mSystemUiProxy;
@@ -69,8 +78,8 @@
final RecentsAnimationCallbacks.RecentsAnimationListener listener =
mock(RecentsAnimationCallbacks.RecentsAnimationListener.class);
doReturn(activityInterface).when(gestureState).getContainerInterface();
- mTaskAnimationManager.startRecentsAnimation(gestureState, new Intent(), listener);
-
+ runOnMainSync(() ->
+ mTaskAnimationManager.startRecentsAnimation(gestureState, new Intent(), listener));
final ArgumentCaptor<ActivityOptions> optionsCaptor =
ArgumentCaptor.forClass(ActivityOptions.class);
verify(mSystemUiProxy)
@@ -78,4 +87,8 @@
assertEquals(ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS,
optionsCaptor.getValue().getPendingIntentBackgroundActivityStartMode());
}
+
+ protected static void runOnMainSync(Runnable runnable) {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(runnable);
+ }
}
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index d28e1f5..716f5dc 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Werk"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Gesprekke"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Neem notas"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Voeg by"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Voeg <xliff:g id="WIDGET_NAME">%1$s</xliff:g>-legstuk by"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Wys almal"</string>
@@ -101,9 +105,9 @@
<string name="permlab_install_shortcut" msgid="5632423390354674437">"installeer kortpaaie"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Laat \'n app toe om kortpaaie by te voeg sonder gebruikerinmenging."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"lees tuis-instellings en -kortpaaie"</string>
- <string name="permdesc_read_settings" msgid="4208061150510996676">"Laat die program toe om die instellings en kortpaaie op tuisskerm te lees."</string>
+ <string name="permdesc_read_settings" msgid="4208061150510996676">"Laat die app toe om die instellings en kortpaaie op tuisskerm te lees."</string>
<string name="permlab_write_settings" msgid="4820028712156303762">"skryf tuis-instellings en -kortpaaie"</string>
- <string name="permdesc_write_settings" msgid="726859348127868466">"Laat die program toe om die instellings en kortpaaie op tuisskerm te verander."</string>
+ <string name="permdesc_write_settings" msgid="726859348127868466">"Laat die app toe om die instellings en kortpaaie op tuisskerm te verander."</string>
<string name="gadget_error_text" msgid="740356548025791839">"Kan nie legstuk laai nie"</string>
<string name="gadget_setup_text" msgid="8348374825537681407">"Legstukinstellings"</string>
<string name="gadget_complete_setup_text" msgid="309040266978007925">"Tik om opstelling te voltooi"</string>
@@ -151,7 +155,7 @@
<string name="app_archived_title" msgid="4548283110222420708">"<xliff:g id="NAME">%1$s</xliff:g> is geargiveer."</string>
<string name="app_unarchiving_action" msgid="5736107006413929484">"laai af en stel terug"</string>
<string name="dialog_update_title" msgid="114234265740994042">"Programopdatering word vereis"</string>
- <string name="dialog_update_message" msgid="4176784553982226114">"Die program vir hierdie ikoon is nie opgedateer nie. Jy kan dit handmatig opdateer om hierdie kortpad weer te aktiveer, of die ikoon verwyder."</string>
+ <string name="dialog_update_message" msgid="4176784553982226114">"Die app vir hierdie ikoon is nie opgedateer nie. Jy kan dit handmatig opdateer om hierdie kortpad weer te aktiveer, of die ikoon verwyder."</string>
<string name="dialog_update" msgid="2178028071796141234">"Dateer op"</string>
<string name="dialog_remove" msgid="6510806469849709407">"Verwyder"</string>
<string name="widgets_list" msgid="796804551140113767">"Legstukkelys"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 6ed533e..1f7f5f7 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ሥራ"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"ውይይቶች"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"የማስታወሻ አያያዝ"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"አክል"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"ምግብር <xliff:g id="WIDGET_NAME">%1$s</xliff:g>ን አክል"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"ሁሉንም አሳይ"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index e924f4d..bbdfebd 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"تطبيقات العمل"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"المحادثات"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"تدوين الملاحظات"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"إضافة"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"إضافة التطبيق المصغّر \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"عرض الكل"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 1e88444..44cb92f 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"কৰ্মস্থান"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"বাৰ্তালাপ"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"টোকা গ্ৰহণ কৰা"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"যোগ দিয়ক"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ৱিজেট যোগ দিয়ক"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"আটাইবোৰ দেখুৱাওক"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 516b401..f2bf5f7 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"İş"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Söhbətlər"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Qeydgötürmə"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Əlavə edin"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidcet əlavə edin"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Hamısını göstər"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index c8aaa88..53b1a02 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Posao"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Konverzacije"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Pravljenje beležaka"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodajte vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Prikaži sve"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index b2f2f32..586a44a 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Працоўныя"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Размовы"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Стварэнне нататак"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Дадаць"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Дадаць віджэт \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Паказаць усе"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index f4fb396..ea53cef 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Служебни"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Разговори"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Водене на бележки"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Добавяне"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Добавяне на приспособлението „<xliff:g id="WIDGET_NAME">%1$s</xliff:g>“"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Вижте всички"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 1d38e66..3e71dc8 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"অফিস"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"কথোপকথন"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"নোট নেওয়া"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"যোগ করুন"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> উইজেট যোগ করুন"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"সব দেখুন"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 57b475c..5173061 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Posao"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Razgovori"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Pisanje bilješki"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Dodajte"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodavanje vidžeta <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Prikaži sve"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 5c7409f..7226581 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Treball"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Converses"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Presa de notes"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Afegeix"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Afegeix el widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Mostra-ho tot"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index e5f26da..51fb179 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Práce"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Konverzace"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Psaní poznámek"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Přidat"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Přidat widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Zobrazit vše"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 1fb015f..4b4664a 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Arbejde"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Samtaler"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Notetagning"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Tilføj"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Tilføj <xliff:g id="WIDGET_NAME">%1$s</xliff:g>-widget"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Vis alle"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 6eb50a7..4fe0def 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Geschäftlich"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Unterhaltungen"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Notizen"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Hinzufügen"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Widget „<xliff:g id="WIDGET_NAME">%1$s</xliff:g>“ hinzufügen"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Alle anzeigen"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index deaf4ff..3a6d849 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Εργασίας"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Συζητήσεις"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Δημιουργία σημειώσεων"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Προσθήκη"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Προσθήκη του γραφικού στοιχείου <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Εμφάνιση όλων"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 1175601..fb5466b 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Work"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Conversations"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Note-taking"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Add"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Add <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Show all"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 1dc6d16..363bb4b 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -68,6 +68,8 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Work"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Conversations"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Note-taking"</string>
+ <string name="widget_cell_tap_to_show_add_button_label" msgid="4354194214317043581">"Show add button"</string>
+ <string name="widget_cell_tap_to_hide_add_button_label" msgid="6117805205101555997">"Hide add button"</string>
<string name="widget_add_button_label" msgid="2761267068711937179">"Add"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Add <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Show all"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 1175601..fb5466b 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Work"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Conversations"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Note-taking"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Add"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Add <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Show all"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 1175601..fb5466b 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Work"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Conversations"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Note-taking"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Add"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Add <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Show all"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 7006bfb..c522d08 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Trabajo"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Conversaciones"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Tomar notas"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Agregar"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Agregar widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Mostrar todos"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index dabba16..fd11b09 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Trabajo"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Conversaciones"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Toma de notas"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Añadir"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Añadir widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Mostrar todo"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 72f6bb8..0bc557f 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Töö"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Vestlused"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Märkmete tegemine"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Lisa"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Lisa vidin <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Kuva kõik"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 37d3e4f..4e69c3d 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Lanekoak"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Elkarrizketak"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Oharrak idazteko"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Gehitu"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Gehitu <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widgeta"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Erakutsi guztiak"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 11130e4..a772f0c 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ابزارههای کاری"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"مکالمهها"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"یادداشتبرداری"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"افزودن"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"افزودن ابزاره <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"نمایش همه"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 3a25c51..7c7045f 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Työ"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Keskustelut"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Muistiinpanojen tekeminen"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Lisää"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Lisää widget: <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Näytä kaikki"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 45a0403..8209d3a 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Professionnels"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Conversations"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Prise de note"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Ajouter"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Ajoutez le widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Tout afficher"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 0a61189..f2517ff 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Professionnels"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Conversations"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Prise de notes"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Ajouter"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Ajoutez un widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Tout afficher"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 293a6b3..8945603 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Widgets do traballo"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Conversas"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Toma de notas"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Engadir"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Engadir o widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Mostrar todo"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index c7d3a10..0f3f265 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ઑફિસ"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"વાતચીતો"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"નોંધ લેવી"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"ઉમેરો"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> વિજેટ ઉમેરો"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"બધા બતાવો"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 1bf63d6..28a29ca 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"वर्क विजेट"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"बातचीत"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"नोट बनाने से जुड़े विजेट"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"जोड़ें"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट जोड़ें"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"सभी दिखाएं"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 7bf6f33..79726e4 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Posao"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Razgovori"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Pisanje bilježaka"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodaj widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Prikaži sve"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index e82566e..154cac0 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Munka"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Beszélgetések"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Jegyzetelés"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Hozzáadás"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> modul hozzáadása"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Az összes megjelenítése"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 4879d4d..85a1f28 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Աշխատանքային"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Զրույցներ"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Նշումների ստեղծում"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Ավելացնել"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Ավելացնել <xliff:g id="WIDGET_NAME">%1$s</xliff:g> վիջեթը"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Բոլորը"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index dde261a..27079dd 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Kerja"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Percakapan"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Pembuatan catatan"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Tambahkan"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Tambahkan widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Tampilkan semua"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 0698bab..0673881 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Vinna"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Samtöl"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Glósugerð"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Bæta við"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Bæta græjunni <xliff:g id="WIDGET_NAME">%1$s</xliff:g> við"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Sýna allt"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index fdd62a4..97441a0 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Lavoro"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Conversazioni"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Aggiunta di note"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Aggiungi"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Aggiungi widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Mostra tutto"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index cfc0291..adf1ad4 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ווידג\'טים לעבודה"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"שיחות"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"כתיבת הערות"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"הוספה"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"הוספת הווידג\'ט <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"הצגת הכול"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 01626ab..7045661 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"仕事用"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"会話"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"メモ"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"追加"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>ウィジェットを追加"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"すべて表示"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 536c1ad..30aa835 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"სამსახური"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"მიმოწერები"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"ჩანიშვნა"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"დამატება"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ვიჯეტის დამატება"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"ყველას ჩვენება"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index b7f38b9..2317944 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Жұмыс виджеттері"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Әңгімелер"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Ескертпе жазу"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Қосу"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Виджет (<xliff:g id="WIDGET_NAME">%1$s</xliff:g>) қосу"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Барлығын көру"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 6a707ae..cfc2932 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ការងារ"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"ការសន្ទនា"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"ការកត់ត្រា"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"បញ្ចូល"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"បញ្ចូលធាតុក្រាហ្វិក <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"បង្ហាញទាំងអស់"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 0ce1a0f..a1daac0 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ಕೆಲಸ"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"ಸಂಭಾಷಣೆಗಳು"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"ಟಿಪ್ಪಣಿ ತೆಗೆದುಕೊಳ್ಳುವುದು"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"ಸೇರಿಸಿ"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ವಿಜೆಟ್ ಸೇರಿಸಿ"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"ಎಲ್ಲಾ ತೋರಿಸಿ"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 19e75d1..db40d20 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"직장 위젯"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"대화"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"메모"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"추가"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> 위젯 추가"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"모두 표시"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 901b2bd..eb46e16 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Жумуш"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Сүйлөшүүлөр"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Эскертме жазуу"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Кошуу"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджетин кошуу"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Баарын көрсөтүү"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index f01dc67..89bb218 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ວຽກ"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"ການສົນທະນາ"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"ການຈົດບັນທຶກ"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"ເພີ່ມ"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"ເພີ່ມວິດເຈັດ <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"ສະແດງທັງໝົດ"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index f5e21de..839c876 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Darbas"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Pokalbiai"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Užrašų kūrimas"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Pridėti"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Pridėti valdiklį: <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Rodyti viską"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 3eafd9a..8620b7b 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Darba"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Sarunas"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Piezīmju pierakstīšana"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Pievienot"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Pievienot logrīku <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Rādīt visus"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 2b85e12..2685c60 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Работни"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Разговори"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Фаќање белешки"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Додај"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Додај го виџетот <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Прикажи ги сите"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index df98b72..b9da880 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ജോലി"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"സംഭാഷണങ്ങൾ"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"കുറിപ്പ് രേഖപ്പെടുത്തൽ"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"ചേർക്കുക"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> വിജറ്റ് ചേർക്കുക"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"എല്ലാം കാണിക്കൂ"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 9fdaf13..8197832 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Ажил"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Харилцан яриа"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Тэмдэглэл хөтлөх"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Нэмэх"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджетийг нэмэх"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Бүгдийг харуул"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index e596193..5281353 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ऑफिस"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"संभाषणे"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"टिपा घेणे"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"जोडा"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट जोडा"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"सर्व दाखवा"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 91c85de..5592cd5 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Kerja"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Perbualan"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Pengambilan nota"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Tambah"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Tambahkan widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Tunjukkan semua"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 8ed7980..c7bb075 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"အလုပ်"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"စကားဝိုင်းများ"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"မှတ်စုလိုက်ခြင်း"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"ထည့်ရန်"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ဝိဂျက်ထည့်ရန်"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"အားလုံးပြပါ"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index fa7a047..c9b8de0 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Jobb"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Samtaler"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Notatskriving"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Legg til"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Legg til <xliff:g id="WIDGET_NAME">%1$s</xliff:g>-modulen"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Vis alle"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 86ebc7b..a966f9e 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"कामसम्बन्धी"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"वार्तालापहरू"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"नोट लेख्ने कार्य"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"हाल्नुहोस्"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट हाल्नुहोस्"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"सबै देखाउनुहोस्"</string>
diff --git a/res/values-night-v31/colors.xml b/res/values-night-v31/colors.xml
index d9f9769..4a6340a 100644
--- a/res/values-night-v31/colors.xml
+++ b/res/values-night-v31/colors.xml
@@ -47,7 +47,7 @@
<color name="widget_picker_unselected_tab_text_color_dark">
@android:color/system_neutral2_200</color>
<color name="widget_picker_collapse_handle_color_dark">
- @android:color/system_neutral2_700</color>
+ @android:color/system_neutral2_400</color>
<color name="widget_picker_add_button_background_color_dark">
@android:color/system_accent1_200</color>
<color name="widget_picker_add_button_text_color_dark">
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 1e3e166..1c819fc 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Werk"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Gesprekken"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Aantekeningen maken"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Toevoegen"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> toevoegen"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Alles tonen"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index f8d68ae..14c9617 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ୱାର୍କ"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"ନୋଟ-ଟେକିଂ"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"ଯୋଗ କରନ୍ତୁ"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ୱିଜେଟ ଯୋଗ କରନ୍ତୁ"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"ସବୁ ଦେଖାନ୍ତୁ"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 07aae76..2882620 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ਕੰਮ"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"ਗੱਲਾਂਬਾਤਾਂ"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"ਨੋਟ ਬਣਾਉਣਾ"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ਵਿਜੇਟ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"ਸਭ ਦਿਖਾਓ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index f76e37b..ae4ff2f 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Służbowe"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Rozmowy"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Notatki"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodaj widżet <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Pokaż wszystko"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 66dc18f..cd3f2a6 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Trabalho"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Conversas"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Tomar notas"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Adicionar"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Adicione o widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Mostrar tudo"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index b9ead80..f40c5b3 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Trabalho"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Conversas"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Anotações"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Adicionar"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Adicionar o widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Mostrar tudo"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 73a5ffb..5a98b55 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Serviciu"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Conversații"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Luare de notițe"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Adaugă"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Adaugă widgetul <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Afișează tot"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 54a1024..2437f29 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Рабочие виджеты"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Разговоры"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Создание заметок"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Добавить"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Добавить виджет \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Показать все"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 21ac9ac..2277d24 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"කාර්යාලය"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"සංවාද"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"සටහන් කර ගැනීම"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"එක් කරන්න"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> විජට්ටුව එක් කරන්න"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"සියල්ල පෙන්වන්න"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index bf96af6..37e2a7e 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Pracovné"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Konverzácie"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Zapisovanie poznámok"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Pridať"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Pridať miniaplikáciu <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Zobraziť všetko"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index b7ecd50..6072e9f 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Služba"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Pogovori"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Ustvarjanje zapiskov"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodajanje pripomočka »<xliff:g id="WIDGET_NAME">%1$s</xliff:g>«"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Pokaži vse"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 64bb03f..995db0f 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Puna"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Bisedat"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Mbajtja e shënimeve"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Shto"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Shto miniaplikacionin <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Shfaq të gjitha"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 44bc9b5..ee69f34 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Посао"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Конверзације"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Прављење бележака"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Додај"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Додајте виџет <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Прикажи све"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 217e116..0aeac3b 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Arbete"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Konversationer"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Anteckna"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Lägg till"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Lägg till widgeten <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Visa alla"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 4a2db28..674e8f9 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Kazini"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Mazungumzo"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Kuandika madokezo"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Weka"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Weka wijeti ya <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Onyesha zote"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index e724f36..6287607 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"பணி"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"உரையாடல்கள்"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"குறிப்பெடுத்தல்"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"சேர்"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> விட்ஜெட்டைச் சேர்க்கும்"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"எல்லாம் காட்டு"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 186e94d..ba7bf2c 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ఆఫీస్"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"సంభాషణలు"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"నోట్-టేకింగ్"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"జోడించండి"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> విడ్జెట్ను జోడించండి"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"అన్నీ చూడండి"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index b5373f6..0338163 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"งาน"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"การสนทนา"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"การจดบันทึก"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"เพิ่ม"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"เพิ่มวิดเจ็ต <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"แสดงทั้งหมด"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 7bc7f9d..4bd5c58 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Trabaho"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Mga Pag-uusap"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Pagtatala"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Idagdag"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Idagdag ang widget na <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Ipakita lahat"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 9990967..c11a5cd 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"İş"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Görüşmeler"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Not alma"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Ekle"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget\'ı ekle"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Tümünü göster"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 165ab49..da56b6c 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Робочі"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Розмови"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Створення нотаток"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Додати"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Додати віджет \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Показати всі"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 1bd2e4a..f978e2e 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"دفتری ویجیٹس"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"گفتگوئیں"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"نوٹ لکھنا"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"شامل کریں"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ویجیٹ شامل کریں"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"سبھی دکھائیں"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index b9286ec..371eece 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Ish"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Suhbatlar"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Qayd olish"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Chiqarish"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidjetini chiqarish"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Hammasi"</string>
diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml
index d74e308..8b43f20 100644
--- a/res/values-v31/colors.xml
+++ b/res/values-v31/colors.xml
@@ -98,7 +98,7 @@
<color name="widget_picker_unselected_tab_text_color_light">
@android:color/system_neutral2_700</color>
<color name="widget_picker_collapse_handle_color_light">
- @android:color/system_neutral2_200</color>
+ @android:color/system_neutral2_500</color>
<color name="widget_picker_add_button_background_color_light">
@android:color/system_accent1_600</color>
<color name="widget_picker_add_button_text_color_light">
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 6082ef6..94fef7e 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Công việc"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Cuộc trò chuyện"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Ghi chú"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Thêm"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Thêm tiện ích <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Hiện tất cả"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index c1917a9..6492e2b 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"工作"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"对话"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"记事"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"添加"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"添加“<xliff:g id="WIDGET_NAME">%1$s</xliff:g>”微件"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"全部显示"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index d29653c..d60bc6d 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"工作"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"對話"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"做筆記"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"新增"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"加<xliff:g id="WIDGET_NAME">%1$s</xliff:g>小工具"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"顯示全部"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index eaa5a73..618fb90 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"工作"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"對話"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"做筆記"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"新增"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"新增「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」小工具"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"全部顯示"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 60dffeb..2b102b0 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -68,6 +68,10 @@
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Umsebenzi"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Izingxoxo"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Ukuthatha amanothi"</string>
+ <!-- no translation found for widget_cell_tap_to_show_add_button_label (4354194214317043581) -->
+ <skip />
+ <!-- no translation found for widget_cell_tap_to_hide_add_button_label (6117805205101555997) -->
+ <skip />
<string name="widget_add_button_label" msgid="2761267068711937179">"Engeza"</string>
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Engeza iwijethi ye-<xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widgets_list_expand_button_label" msgid="7912016136574932622">"Bonisa konke"</string>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 967d97d..914ffd6 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -114,7 +114,7 @@
<color name="widget_picker_tab_background_unselected_light">#E3E3E3</color>
<color name="widget_picker_selected_tab_text_color_light">#FFFFFF</color>
<color name="widget_picker_unselected_tab_text_color_light">#444746</color>
- <color name="widget_picker_collapse_handle_color_light">#C4C7C5</color>
+ <color name="widget_picker_collapse_handle_color_light">#747775</color>
<color name="widget_picker_add_button_background_color_light">#0B57D0</color>
<color name="widget_picker_add_button_text_color_light">#0B57D0</color>
<color name="widget_picker_expand_button_background_color_light">
@@ -141,7 +141,7 @@
<color name="widget_picker_tab_background_unselected_dark">#343535</color>
<color name="widget_picker_selected_tab_text_color_dark">#2D312F</color>
<color name="widget_picker_unselected_tab_text_color_dark">#C4C7C5</color>
- <color name="widget_picker_collapse_handle_color_dark">#444746</color>
+ <color name="widget_picker_collapse_handle_color_dark">#8e918f</color>
<color name="widget_picker_add_button_background_color_dark">#062E6F</color>
<color name="widget_picker_add_button_text_color_dark">#FFFFFF</color>
<color name="widget_picker_expand_button_background_color_dark">
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index c0bd956..21aabfa 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -300,10 +300,6 @@
<!-- the distance an icon must be dragged before button drop targets accept it -->
<dimen name="drag_distanceThreshold">30dp</dimen>
- <!-- Elevation for the drag view. It should be larger than elevation of all other drag sources
- and drop targets like all-apps and folders -->
- <dimen name="drag_elevation">30dp</dimen>
-
<dimen name="drag_flingToDeleteMinVelocity">-1500dp</dimen>
<dimen name="spring_loaded_panel_border">2dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f7069a6..cdfbefe 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -154,6 +154,10 @@
<!-- A widget category label for grouping widgets related to note taking. [CHAR_LIMIT=30] -->
<string name="widget_category_note_taking">Note-taking</string>
+ <!-- Accessibility label on the widget preview that on click (if add button is hidden) shows the button to add widget to the home screen. [CHAR_LIMIT=none] -->
+ <string name="widget_cell_tap_to_show_add_button_label">Show add button</string>
+ <!-- Accessibility label on the widget preview that on click (if add button is showing) hides the button to add widget to the home screen. [CHAR_LIMIT=none] -->
+ <string name="widget_cell_tap_to_hide_add_button_label">Hide add button</string>
<!-- Text on the button that adds a widget to the home screen. [CHAR_LIMIT=15] -->
<string name="widget_add_button_label">Add</string>
<!-- Accessibility content description for the button that adds a widget to the home screen. The
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index df5f520..3d71ff1 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -1816,7 +1816,8 @@
+ (int) Math.ceil(getUnusedHorizontalSpace() / 2f);
final int vStartPadding = getPaddingTop();
- int x = hStartPadding + (cellX * mBorderSpace.x) + (cellX * cellWidth);
+ int x = hStartPadding + (cellX * mBorderSpace.x) + (cellX * cellWidth)
+ + getTranslationXForCell(cellX, cellY);
int y = vStartPadding + (cellY * mBorderSpace.y) + (cellY * cellHeight);
int width = cellHSpan * cellWidth + ((cellHSpan - 1) * mBorderSpace.x);
@@ -1825,6 +1826,11 @@
resultRect.set(x, y, x + width, y + height);
}
+ /** Enables successors to provide an X adjustment for the cell. */
+ protected int getTranslationXForCell(int cellX, int cellY) {
+ return 0;
+ }
+
public void markCellsAsOccupiedForView(View view) {
if (view instanceof LauncherAppWidgetHostView
&& view.getTag() instanceof LauncherAppWidgetInfo) {
diff --git a/src/com/android/launcher3/CheckLongPressHelper.java b/src/com/android/launcher3/CheckLongPressHelper.java
index 3e4e96b..e9cd16c 100644
--- a/src/com/android/launcher3/CheckLongPressHelper.java
+++ b/src/com/android/launcher3/CheckLongPressHelper.java
@@ -151,6 +151,8 @@
handled = mView.performLongClick();
}
if (handled) {
+ // Cancel any default long-press action on the view
+ mView.cancelLongPress();
mView.setPressed(false);
mHasPerformedLongPress = true;
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 16d9525..f1274dc 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -425,7 +425,9 @@
&& WindowManagerProxy.INSTANCE.get(context).isTaskbarDrawnInProcess();
// Some more constants.
- context = getContext(context, info, isVerticalBarLayout() || (isTablet && isLandscape)
+ context = getContext(context, info, inv.isFixedLandscape
+ || isVerticalBarLayout()
+ || (isTablet && isLandscape)
? Configuration.ORIENTATION_LANDSCAPE
: Configuration.ORIENTATION_PORTRAIT,
windowBounds);
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 6be8098..1c18179 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -36,6 +36,8 @@
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
+import com.android.launcher3.ShortcutAndWidgetContainer.TranslationProvider;
+import com.android.launcher3.celllayout.CellLayoutLayoutParams;
import com.android.launcher3.util.HorizontalInsettableView;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
@@ -201,13 +203,16 @@
AnimatorSet animatorSet = new AnimatorSet();
for (int i = 0; i < icons.getChildCount(); i++) {
View child = icons.getChildAt(i);
- float tx = shouldAdjustHotseat ? dp.getHotseatAdjustedTranslation(getContext(), i) : 0;
- if (child instanceof Reorderable) {
- MultiTranslateDelegate mtd = ((Reorderable) child).getTranslateDelegate();
- animatorSet.play(
- mtd.getTranslationX(INDEX_BUBBLE_ADJUSTMENT_ANIM).animateToValue(tx));
- } else {
- animatorSet.play(ObjectAnimator.ofFloat(child, VIEW_TRANSLATE_X, tx));
+ if (child.getLayoutParams() instanceof CellLayoutLayoutParams lp) {
+ float tx = shouldAdjustHotseat
+ ? dp.getHotseatAdjustedTranslation(getContext(), lp.getCellX()) : 0;
+ if (child instanceof Reorderable) {
+ MultiTranslateDelegate mtd = ((Reorderable) child).getTranslateDelegate();
+ animatorSet.play(
+ mtd.getTranslationX(INDEX_BUBBLE_ADJUSTMENT_ANIM).animateToValue(tx));
+ } else {
+ animatorSet.play(ObjectAnimator.ofFloat(child, VIEW_TRANSLATE_X, tx));
+ }
}
}
//TODO(b/381109832) refactor & simplify adjustment logic
@@ -229,6 +234,13 @@
}
@Override
+ protected int getTranslationXForCell(int cellX, int cellY) {
+ TranslationProvider translationProvider = getShortcutsAndWidgets().getTranslationProvider();
+ if (translationProvider == null) return 0;
+ return (int) translationProvider.getTranslationX(cellX);
+ }
+
+ @Override
public void setInsets(Rect insets) {
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
DeviceProfile grid = mActivity.getDeviceProfile();
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index dfbcf5c..dddc43f 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -16,6 +16,7 @@
package com.android.launcher3;
+import static com.android.launcher3.LauncherPrefs.DB_FILE;
import static com.android.launcher3.LauncherPrefs.FIXED_LANDSCAPE_MODE;
import static com.android.launcher3.LauncherPrefs.GRID_NAME;
import static com.android.launcher3.Utilities.dpiFromPx;
@@ -53,6 +54,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.DotRenderer;
+import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.DeviceGridState;
import com.android.launcher3.provider.RestoreDbTask;
import com.android.launcher3.testing.shared.ResourceUtils;
@@ -63,6 +65,7 @@
import com.android.launcher3.util.ResourceHelper;
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.WindowBounds;
+import com.android.launcher3.util.window.CachedDisplayInfo;
import com.android.launcher3.util.window.WindowManagerProxy;
import org.xmlpull.v1.XmlPullParser;
@@ -85,6 +88,8 @@
public static final MainThreadInitializedObject<InvariantDeviceProfile> INSTANCE =
new MainThreadInitializedObject<>(InvariantDeviceProfile::new);
+ public static final String GRID_NAME_PREFS_KEY = "idp_grid_name";
+
@Retention(RetentionPolicy.SOURCE)
@IntDef({TYPE_PHONE, TYPE_MULTI_DISPLAY, TYPE_TABLET})
public @interface DeviceType {
@@ -240,11 +245,11 @@
@TargetApi(23)
private InvariantDeviceProfile(Context context) {
String gridName = getCurrentGridName(context);
- String newGridName = initGrid(context, gridName);
- if (!newGridName.equals(gridName)) {
- LauncherPrefs.get(context).put(GRID_NAME, newGridName);
- }
-
+ FileLog.d(TAG, "New InvariantDeviceProfile, before initGrid(): "
+ + "gridName:" + gridName
+ + ", LauncherPrefs GRID_NAME:" + LauncherPrefs.get(context).get(GRID_NAME)
+ + ", LauncherPrefs DB_FILE:" + LauncherPrefs.get(context).get(DB_FILE));
+ initGrid(context, gridName);
DisplayController.INSTANCE.get(context).setPriorityListener(
(displayContext, info, flags) -> {
if ((flags & (CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS
@@ -367,7 +372,16 @@
? new ArrayList<>(allOptions)
: new ArrayList<>(allOptionsFilteredByColCount),
displayInfo.getDeviceType());
+
+ if (!displayOption.grid.name.equals(gridName)) {
+ LauncherPrefs.get(context).put(GRID_NAME, displayOption.grid.name);
+ }
+
initGrid(context, displayInfo, displayOption);
+ FileLog.d(TAG, "initGrid: "
+ + "gridName:" + gridName
+ + ", LauncherPrefs GRID_NAME:" + LauncherPrefs.get(context).get(GRID_NAME)
+ + ", LauncherPrefs DB_FILE:" + LauncherPrefs.get(context).get(DB_FILE));
return displayOption.grid.name;
}
@@ -679,28 +693,15 @@
}
private static int[] findMinWidthAndHeightDpForDevice(Info displayInfo) {
- int minWidthPx = Integer.MAX_VALUE;
- int minHeightPx = Integer.MAX_VALUE;
- for (WindowBounds bounds : displayInfo.supportedBounds) {
- boolean isTablet = displayInfo.isTablet(bounds);
- if (isTablet && displayInfo.getDeviceType() == TYPE_MULTI_DISPLAY) {
- // For split displays, take half width per page.
- minWidthPx = Math.min(minWidthPx, bounds.availableSize.x / 2);
- minHeightPx = Math.min(minHeightPx, bounds.availableSize.y);
- } else if (!isTablet && bounds.isLandscape()) {
- // We will use transposed layout in this case.
- minWidthPx = Math.min(minWidthPx, bounds.availableSize.y);
- minHeightPx = Math.min(minHeightPx, bounds.availableSize.x);
- } else {
- minWidthPx = Math.min(minWidthPx, bounds.availableSize.x);
- minHeightPx = Math.min(minHeightPx, bounds.availableSize.y);
- }
+ int minDisplayWidthDp = Integer.MAX_VALUE;
+ int minDisplayHeightDp = Integer.MAX_VALUE;
+ for (CachedDisplayInfo display: displayInfo.getAllDisplays()) {
+ minDisplayWidthDp = Math.min(minDisplayWidthDp,
+ (int) dpiFromPx(display.size.x, DisplayMetrics.DENSITY_DEVICE_STABLE));
+ minDisplayHeightDp = Math.min(minDisplayHeightDp,
+ (int) dpiFromPx(display.size.y, DisplayMetrics.DENSITY_DEVICE_STABLE));
}
-
- int minWidthDp = (int) dpiFromPx(minWidthPx, DisplayMetrics.DENSITY_DEVICE_STABLE);
- int minHeightDp = (int) dpiFromPx(minHeightPx, DisplayMetrics.DENSITY_DEVICE_STABLE);
-
- return new int[]{minWidthDp, minHeightDp};
+ return new int[]{minDisplayWidthDp, minDisplayHeightDp};
}
/**
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 5b8d2fc..cb021c7 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -423,8 +423,6 @@
private final SettingsCache.OnChangeListener mNaturalScrollingChangedListener =
enabled -> mIsNaturalScrollingEnabled = enabled;
- private boolean mRecreateToUpdateTheme = false;
-
public static Launcher getLauncher(Context context) {
return fromContext(context);
}
@@ -1751,12 +1749,6 @@
}
@Override
- protected void recreateToUpdateTheme() {
- mRecreateToUpdateTheme = true;
- super.recreateToUpdateTheme();
- }
-
- @Override
public void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
IntSet synchronouslyBoundPages = mModelCallbacks.getSynchronouslyBoundPages();
@@ -1801,8 +1793,6 @@
outState.putParcelable(RUNTIME_STATE_PENDING_ACTIVITY_RESULT, mPendingActivityResult);
}
- outState.putBoolean(RUNTIME_STATE_RECREATE_TO_UPDATE_THEME, mRecreateToUpdateTheme);
-
super.onSaveInstanceState(outState);
}
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 01d0a74..a53238d 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -20,8 +20,12 @@
import static android.content.Context.RECEIVER_EXPORTED;
import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
+import static com.android.launcher3.InvariantDeviceProfile.GRID_NAME_PREFS_KEY;
+import static com.android.launcher3.LauncherPrefs.DB_FILE;
+import static com.android.launcher3.LauncherPrefs.GRID_NAME;
import static com.android.launcher3.LauncherPrefs.ICON_STATE;
import static com.android.launcher3.LauncherPrefs.THEMED_ICONS;
+import static com.android.launcher3.model.DeviceGridState.KEY_DB_FILE;
import static com.android.launcher3.model.LoaderTask.SMARTSPACE_ON_HOME_SCREEN;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@@ -47,6 +51,7 @@
import com.android.launcher3.icons.IconProvider;
import com.android.launcher3.icons.LauncherIconProvider;
import com.android.launcher3.icons.LauncherIcons;
+import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.ModelLauncherCallbacks;
import com.android.launcher3.model.WidgetsFilterDataProvider;
import com.android.launcher3.notification.NotificationListener;
@@ -70,6 +75,7 @@
public class LauncherAppState implements SafeCloseable {
+ public static final String TAG = "LauncherAppState";
public static final String ACTION_FORCE_ROLOAD = "force-reload-launcher";
// We do not need any synchronization for this variable as its only written on UI thread.
@@ -293,6 +299,12 @@
if (Themes.KEY_THEMED_ICONS.equals(key)) {
mIconProvider.setIconThemeSupported(Themes.isThemedIconEnabled(mContext));
verifyIconChanged();
+ } else if (GRID_NAME_PREFS_KEY.equals(key)) {
+ FileLog.d(TAG, "onPrefChanged GRID_NAME changed: "
+ + LauncherPrefs.get(mContext).get(GRID_NAME));
+ } else if (KEY_DB_FILE.equals(key)) {
+ FileLog.d(TAG, "onPrefChanged DB_FILE changed: "
+ + LauncherPrefs.get(mContext).get(DB_FILE));
}
}
}
diff --git a/src/com/android/launcher3/LauncherConstants.java b/src/com/android/launcher3/LauncherConstants.java
index 0ed239d..5cba82f 100644
--- a/src/com/android/launcher3/LauncherConstants.java
+++ b/src/com/android/launcher3/LauncherConstants.java
@@ -68,7 +68,7 @@
// Type int[]
static final String RUNTIME_STATE_CURRENT_SCREEN_IDS = "launcher.current_screen_ids";
// Type: boolean
- static final String RUNTIME_STATE_RECREATE_TO_UPDATE_THEME =
+ public static final String RUNTIME_STATE_RECREATE_TO_UPDATE_THEME =
"launcher.recreate_to_update_theme";
}
}
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index 712c56c..5b9c2fa 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -20,6 +20,7 @@
import android.content.SharedPreferences
import androidx.annotation.VisibleForTesting
import com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN
+import com.android.launcher3.InvariantDeviceProfile.GRID_NAME_PREFS_KEY
import com.android.launcher3.LauncherFiles.DEVICE_PREFERENCES_KEY
import com.android.launcher3.LauncherFiles.SHARED_PREFERENCES_KEY
import com.android.launcher3.model.DeviceGridState
@@ -138,7 +139,7 @@
@JvmField
val GRID_NAME =
ConstantItem(
- "idp_grid_name",
+ GRID_NAME_PREFS_KEY,
isBackedUp = true,
defaultValue = null,
encryptionType = EncryptionType.ENCRYPTED,
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index a8733f2..180ed87 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -330,8 +330,13 @@
mTranslationProvider = provider;
}
+ /** Returns the current {@link TranslationProvider translation provider}. */
+ public @Nullable TranslationProvider getTranslationProvider() {
+ return mTranslationProvider;
+ }
+
/** Provides translation values to apply when laying out child views. */
- interface TranslationProvider {
+ public interface TranslationProvider {
float getTranslationX(int cellX);
}
}
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 71a2589..ebcb5da 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -16,8 +16,6 @@
package com.android.launcher3;
-import static android.graphics.drawable.AdaptiveIconDrawable.getExtraInsetFraction;
-
import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN;
import static com.android.launcher3.Flags.enableSmartspaceAsAWidget;
import static com.android.launcher3.icons.BitmapInfo.FLAG_THEMED;
@@ -36,9 +34,6 @@
import android.content.pm.ShortcutInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BlendMode;
-import android.graphics.BlendModeColorFilter;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.LightingColorFilter;
@@ -49,10 +44,8 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.os.DeadObjectException;
@@ -85,7 +78,6 @@
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.CacheableShortcutInfo;
import com.android.launcher3.icons.LauncherIcons;
-import com.android.launcher3.icons.ThemedIconDrawable;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.pm.ShortcutConfigActivityInfo;
@@ -696,29 +688,19 @@
return null;
}
- // Inject monochrome icon drawable
+ // Inject theme icon drawable
if (ATLEAST_T && useTheme) {
- result.mutate();
- int[] colors = ThemedIconDrawable.getColors(context);
- Drawable mono = result.getMonochrome();
-
- if (mono != null) {
- mono.setTint(colors[1]);
- } else if (info instanceof ItemInfoWithIcon iiwi) {
- // Inject a previously generated monochrome icon
- Bitmap monoBitmap = iiwi.bitmap.getMono();
- if (monoBitmap != null) {
- // Use BitmapDrawable instead of FastBitmapDrawable so that the colorState is
- // preserved in constantState
- mono = new BitmapDrawable(monoBitmap);
- mono.setColorFilter(new BlendModeColorFilter(colors[1], BlendMode.SRC_IN));
- // Inset the drawable according to the AdaptiveIconDrawable layers
- mono = new InsetDrawable(mono, getExtraInsetFraction() / 2);
+ try (LauncherIcons li = LauncherIcons.obtain(context)) {
+ if (li.getThemeController() != null) {
+ AdaptiveIconDrawable themed = li.getThemeController().createThemedAdaptiveIcon(
+ context,
+ result,
+ info instanceof ItemInfoWithIcon iiwi ? iiwi.bitmap : null);
+ if (themed != null) {
+ result = themed;
+ }
}
}
- if (mono != null) {
- result = new AdaptiveIconDrawable(new ColorDrawable(colors[0]), mono);
- }
}
if (badge == null) {
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 548bc35..68a6e62 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -48,6 +48,8 @@
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.ArrowPopup;
import com.android.launcher3.popup.PopupContainerWithArrow;
+import com.android.launcher3.shortcuts.DeepShortcutTextView;
+import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
@@ -104,11 +106,15 @@
R.string.action_deep_shortcut, KeyEvent.KEYCODE_S));
}
+ private static boolean isNotInShortcutMenu(@Nullable View view) {
+ return view == null || !(view.getParent() instanceof DeepShortcutView);
+ }
+
@Override
protected void getSupportedActions(View host, ItemInfo item, List<LauncherAction> out) {
// If the request came from keyboard, do not add custom shortcuts as that is already
// exposed as a direct shortcut
- if (ShortcutUtil.supportsShortcuts(item)) {
+ if (isNotInShortcutMenu(host) && ShortcutUtil.supportsShortcuts(item)) {
out.add(mActions.get(DEEP_SHORTCUTS));
}
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 8505a6d..b0001af 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -761,6 +761,22 @@
}
}
+ @Override
+ public void addChildrenForAccessibility(ArrayList<View> arrayList) {
+ super.addChildrenForAccessibility(arrayList);
+ if (!Flags.floatingSearchBar()) {
+ // Searchbox container is visually at the top of the all apps UI but it's present in
+ // end of the children list.
+ // We need to move the searchbox to the top in a11y tree for a11y services to read the
+ // all apps screen in same as visual order.
+ arrayList.stream().filter(v -> v.getId() == R.id.search_container_all_apps)
+ .findFirst().ifPresent(v -> {
+ arrayList.remove(v);
+ arrayList.add(0, v);
+ });
+ }
+ }
+
protected void updateHeaderScroll(int scrolledOffset) {
float prog1 = Utilities.boundToRange((float) scrolledOffset / mHeaderThreshold, 0f, 1f);
int headerColor = getHeaderColor(prog1);
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
index 6ebab5a..6d7d193 100644
--- a/src/com/android/launcher3/allapps/WorkProfileManager.java
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -148,7 +148,7 @@
if (getAH() != null) {
getAH().applyPadding();
}
- mWorkUtilityView.setOnClickListener(this::onWorkFabClicked);
+ mWorkUtilityView.getWorkFAB().setOnClickListener(this::onWorkFabClicked);
return true;
}
/**
diff --git a/src/com/android/launcher3/allapps/WorkUtilityView.java b/src/com/android/launcher3/allapps/WorkUtilityView.java
index 5949b78..b263639 100644
--- a/src/com/android/launcher3/allapps/WorkUtilityView.java
+++ b/src/com/android/launcher3/allapps/WorkUtilityView.java
@@ -25,6 +25,7 @@
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.widget.ImageButton;
@@ -83,6 +84,7 @@
// Threshold when user scrolls up/down to determine when should button extend/collapse
private final int mScrollThreshold;
private ValueAnimator mPauseFABAnim;
+ private View mWorkFAB;
private TextView mPauseText;
private ImageView mWorkIcon;
private ImageButton mSchedulerButton;
@@ -117,6 +119,7 @@
mPauseText = findViewById(R.id.pause_text);
mWorkIcon = findViewById(R.id.work_icon);
+ mWorkFAB = findViewById(R.id.work_mode_toggle);
mSchedulerButton = findViewById(R.id.work_scheduler);
setSelected(true);
KeyboardInsetAnimationCallback keyboardInsetAnimationCallback =
@@ -388,6 +391,10 @@
return mScrollThreshold;
}
+ public View getWorkFAB() {
+ return mWorkFAB;
+ }
+
public void updateStringFromCache(){
StringCache cache = mActivityContext.getStringCache();
if (cache != null) {
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index bcee442..67fe889 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -224,7 +224,6 @@
measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY));
mBlurSizeOutline = getResources().getDimensionPixelSize(R.dimen.blur_size_medium_outline);
- setElevation(getResources().getDimension(R.dimen.drag_elevation));
setWillNotDraw(false);
}
diff --git a/src/com/android/launcher3/dragndrop/SpringLoadedDragController.java b/src/com/android/launcher3/dragndrop/SpringLoadedDragController.java
deleted file mode 100644
index bebef70..0000000
--- a/src/com/android/launcher3/dragndrop/SpringLoadedDragController.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2010 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.dragndrop;
-
-import com.android.launcher3.Alarm;
-import com.android.launcher3.CellLayout;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.OnAlarmListener;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.Workspace;
-
-public class SpringLoadedDragController implements OnAlarmListener {
- // how long the user must hover over a mini-screen before it unshrinks
- private static final long ENTER_SPRING_LOAD_HOVER_TIME = 500;
- private static final long ENTER_SPRING_LOAD_HOVER_TIME_IN_TEST = 3000;
- private static final long ENTER_SPRING_LOAD_CANCEL_HOVER_TIME = 950;
-
- Alarm mAlarm;
-
- // the screen the user is currently hovering over, if any
- private CellLayout mScreen;
- private Launcher mLauncher;
-
- public SpringLoadedDragController(Launcher launcher) {
- mLauncher = launcher;
- mAlarm = new Alarm();
- mAlarm.setOnAlarmListener(this);
- }
-
- private long getEnterSpringLoadHoverTime() {
- // Some TAPL tests are flaky on Cuttlefish with a low waiting time
- return Utilities.isRunningInTestHarness()
- ? ENTER_SPRING_LOAD_HOVER_TIME_IN_TEST
- : ENTER_SPRING_LOAD_HOVER_TIME;
- }
-
- public void cancel() {
- mAlarm.cancelAlarm();
- }
-
- // Set a new alarm to expire for the screen that we are hovering over now
- public void setAlarm(CellLayout cl) {
- mAlarm.cancelAlarm();
- mAlarm.setAlarm((cl == null) ? ENTER_SPRING_LOAD_CANCEL_HOVER_TIME
- : getEnterSpringLoadHoverTime());
- mScreen = cl;
- }
-
- // this is called when our timer runs out
- public void onAlarm(Alarm alarm) {
- if (mScreen != null) {
- // Snap to the screen that we are hovering over now
- Workspace<?> w = mLauncher.getWorkspace();
- if (!w.isVisible(mScreen)) {
- w.snapToPage(w.indexOfChild(mScreen));
- }
- } else {
- mLauncher.getDragController().cancelDrag();
- }
- }
-}
diff --git a/src/com/android/launcher3/dragndrop/SpringLoadedDragController.kt b/src/com/android/launcher3/dragndrop/SpringLoadedDragController.kt
new file mode 100644
index 0000000..2aeab9d
--- /dev/null
+++ b/src/com/android/launcher3/dragndrop/SpringLoadedDragController.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 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.dragndrop
+
+import com.android.launcher3.Alarm
+import com.android.launcher3.CellLayout
+import com.android.launcher3.Launcher
+import com.android.launcher3.OnAlarmListener
+import com.android.launcher3.Utilities
+
+class SpringLoadedDragController(private val launcher: Launcher) : OnAlarmListener {
+ internal val alarm = Alarm().also { it.setOnAlarmListener(this) }
+
+ // the screen the user is currently hovering over, if any
+ private var screen: CellLayout? = null
+
+ fun cancel() = alarm.cancelAlarm()
+
+ // Set a new alarm to expire for the screen that we are hovering over now
+ fun setAlarm(cl: CellLayout?) {
+ cancel()
+ alarm.setAlarm(
+ when {
+ cl == null -> ENTER_SPRING_LOAD_CANCEL_HOVER_TIME
+ // Some TAPL tests are flaky on Cuttlefish with a low waiting time
+ Utilities.isRunningInTestHarness() -> ENTER_SPRING_LOAD_HOVER_TIME_IN_TEST
+ else -> ENTER_SPRING_LOAD_HOVER_TIME
+ }
+ )
+ screen = cl
+ }
+
+ // this is called when our timer runs out
+ override fun onAlarm(alarm: Alarm) {
+ if (screen != null) {
+ // Snap to the screen that we are hovering over now
+ with(launcher.workspace) { if (!isVisible(screen)) snapToPage(indexOfChild(screen)) }
+ } else {
+ launcher.dragController.cancelDrag()
+ }
+ }
+
+ companion object {
+ // how long the user must hover over a mini-screen before it unshrinks
+ private const val ENTER_SPRING_LOAD_HOVER_TIME: Long = 500
+ private const val ENTER_SPRING_LOAD_HOVER_TIME_IN_TEST: Long = 3000
+ private const val ENTER_SPRING_LOAD_CANCEL_HOVER_TIME: Long = 950
+ }
+}
diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java
index 884d448..839dfb7 100644
--- a/src/com/android/launcher3/icons/LauncherIcons.java
+++ b/src/com/android/launcher3/icons/LauncherIcons.java
@@ -17,15 +17,13 @@
package com.android.launcher3.icons;
import android.content.Context;
-import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import androidx.annotation.NonNull;
-import com.android.launcher3.Flags;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.graphics.IconShape;
+import com.android.launcher3.icons.mono.MonoIconThemeController;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.SafeCloseable;
@@ -57,13 +55,13 @@
private final ConcurrentLinkedQueue<LauncherIcons> mPool;
- private MonochromeIconFactory mMonochromeIconFactory;
-
protected LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize,
ConcurrentLinkedQueue<LauncherIcons> pool) {
super(context, fillResIconDpi, iconBitmapSize,
IconShape.INSTANCE.get(context).getShape().enableShapeDetection());
- mMonoIconEnabled = Themes.isThemedIconEnabled(context);
+ if (Themes.isThemedIconEnabled(context)) {
+ mThemeController = new MonoIconThemeController();
+ }
mPool = pool;
}
@@ -75,18 +73,6 @@
mPool.add(this);
}
- @Override
- protected Drawable getMonochromeDrawable(AdaptiveIconDrawable base) {
- Drawable mono = super.getMonochromeDrawable(base);
- if (mono != null || !Flags.forceMonochromeAppIcons()) {
- return mono;
- }
- if (mMonochromeIconFactory == null) {
- mMonochromeIconFactory = new MonochromeIconFactory(mIconBitmapSize);
- }
- return mMonochromeIconFactory.wrap(base);
- }
-
@NonNull
@Override
protected UserIconInfo getUserInfo(@NonNull UserHandle user) {
diff --git a/src/com/android/launcher3/model/DbEntry.kt b/src/com/android/launcher3/model/DbEntry.kt
index b79d312..da9779e 100644
--- a/src/com/android/launcher3/model/DbEntry.kt
+++ b/src/com/android/launcher3/model/DbEntry.kt
@@ -30,7 +30,6 @@
import com.android.launcher3.LauncherSettings.Favorites.SPANY
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.util.ContentWriter
-import java.net.URISyntaxException
import java.util.Objects
class DbEntry : ItemInfo(), Comparable<DbEntry> {
@@ -129,8 +128,8 @@
private fun cleanIntentString(intentStr: String): String {
try {
return Intent.parseUri(intentStr, 0).apply { sourceBounds = null }.toURI()
- } catch (e: URISyntaxException) {
- Log.e(TAG, "Unable to parse Intent string", e)
+ } catch (e: Exception) {
+ Log.e(TAG, "Unable to parse Intent string: $intentStr", e)
return intentStr
}
}
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 83eace8..f96e959 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -389,7 +389,7 @@
}
} catch (CancellationException e) {
// Loader stopped, ignore
- logASplit("Cancelled");
+ FileLog.w(TAG, "LoaderTask cancelled:", e);
} catch (Exception e) {
memoryLogger.printLogs();
throw e;
@@ -398,6 +398,7 @@
}
public synchronized void stopLocked() {
+ FileLog.w(TAG, "LoaderTask#stopLocked:", new Exception());
mStopped = true;
this.notify();
}
diff --git a/src/com/android/launcher3/model/WidgetItem.java b/src/com/android/launcher3/model/WidgetItem.java
index e757a68..0caeb8d 100644
--- a/src/com/android/launcher3/model/WidgetItem.java
+++ b/src/com/android/launcher3/model/WidgetItem.java
@@ -1,19 +1,8 @@
package com.android.launcher3.model;
-import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN;
-import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD;
-import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX;
-
-import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.ActivityInfo;
-import android.content.res.Resources;
-import android.util.SparseArray;
-import android.widget.RemoteViews;
-import androidx.core.os.BuildCompat;
-
-import com.android.launcher3.Flags;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.icons.BitmapInfo;
@@ -21,7 +10,6 @@
import com.android.launcher3.pm.ShortcutConfigActivityInfo;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.widget.WidgetManagerHelper;
/**
* An wrapper over various items displayed in a widget picker,
@@ -37,11 +25,9 @@
public final String label;
public final CharSequence description;
public final int spanX, spanY;
- public final SparseArray<RemoteViews> generatedPreviews;
public WidgetItem(LauncherAppWidgetProviderInfo info,
- InvariantDeviceProfile idp, IconCache iconCache, Context context,
- WidgetManagerHelper helper) {
+ InvariantDeviceProfile idp, IconCache iconCache, Context context) {
super(info.provider, info.getProfile());
label = iconCache.getTitleNoCache(info);
@@ -51,27 +37,6 @@
spanX = Math.min(info.spanX, idp.numColumns);
spanY = Math.min(info.spanY, idp.numRows);
-
- if (BuildCompat.isAtLeastV() && Flags.enableGeneratedPreviews()) {
- generatedPreviews = new SparseArray<>(3);
- for (int widgetCategory : new int[] {
- WIDGET_CATEGORY_HOME_SCREEN,
- WIDGET_CATEGORY_KEYGUARD,
- WIDGET_CATEGORY_SEARCHBOX,
- }) {
- if ((widgetCategory & widgetInfo.generatedPreviewCategories) != 0) {
- generatedPreviews.put(widgetCategory,
- helper.loadGeneratedPreview(widgetInfo, widgetCategory));
- }
- }
- } else {
- generatedPreviews = null;
- }
- }
-
- public WidgetItem(LauncherAppWidgetProviderInfo info,
- InvariantDeviceProfile idp, IconCache iconCache, Context context) {
- this(info, idp, iconCache, context, new WidgetManagerHelper(context));
}
public WidgetItem(ShortcutConfigActivityInfo info, IconCache iconCache) {
@@ -82,7 +47,6 @@
widgetInfo = null;
activityInfo = info;
spanX = spanY = 1;
- generatedPreviews = null;
}
/**
@@ -101,26 +65,8 @@
return false;
}
- /** Returns whether this {@link WidgetItem} has a preview layout that can be used. */
- @SuppressLint("NewApi") // Already added API check.
- public boolean hasPreviewLayout() {
- return widgetInfo != null && widgetInfo.previewLayout != Resources.ID_NULL;
- }
-
/** Returns whether this {@link WidgetItem} is for a shortcut rather than an app widget. */
public boolean isShortcut() {
return activityInfo != null;
}
-
- /**
- * Returns whether this {@link WidgetItem} has a generated preview for the given widget
- * category.
- */
- public boolean hasGeneratedPreview(int widgetCategory) {
- if (!Flags.enableGeneratedPreviews() || generatedPreviews == null) {
- return false;
- }
- return generatedPreviews.contains(widgetCategory)
- && generatedPreviews.get(widgetCategory) != null;
- }
}
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
index 01d4996..a27d2f1 100644
--- a/src/com/android/launcher3/model/WidgetsModel.java
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -149,8 +149,7 @@
LauncherAppWidgetProviderInfo.fromProviderInfo(context, widgetInfo);
widgetsAndShortcuts.add(new WidgetItem(
- launcherWidgetInfo, idp, app.getIconCache(), app.getContext(),
- widgetManager));
+ launcherWidgetInfo, idp, app.getIconCache(), app.getContext()));
updatedItems.add(launcherWidgetInfo);
}
@@ -213,7 +212,6 @@
if (!WIDGETS_ENABLED) {
return;
}
- WidgetManagerHelper widgetManager = new WidgetManagerHelper(app.getContext());
for (Entry<PackageItemInfo, List<WidgetItem>> entry : mWidgetsByPackageItem.entrySet()) {
if (packageNames.contains(entry.getKey().packageName)) {
List<WidgetItem> items = entry.getValue();
@@ -226,7 +224,7 @@
} else {
items.set(i, new WidgetItem(item.widgetInfo,
app.getInvariantDeviceProfile(), app.getIconCache(),
- app.getContext(), widgetManager));
+ app.getContext()));
}
}
}
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 8db981f..f56888b 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -124,11 +124,13 @@
LauncherPrefs.get(context).removeSync(RESTORE_DEVICE);
DeviceGridState deviceGridState = new DeviceGridState(context);
+ FileLog.d(TAG, "restoreIfNeeded: deviceGridState from context: " + deviceGridState);
String oldPhoneFileName = deviceGridState.getDbFile();
List<String> previousDbs = existingDbs(context);
removeOldDBs(context, oldPhoneFileName);
// The idp before this contains data about the old phone, after this it becomes the idp
// of the current phone.
+ FileLog.d(TAG, "Resetting IDP to default for restore dest device");
idp.reset(context);
trySettingPreviousGridAsCurrent(context, idp, oldPhoneFileName, previousDbs);
}
@@ -144,17 +146,24 @@
context, oldPhoneDbFileName);
// The grid option could be null if current phone doesn't support the previous db.
if (oldPhoneGridOption != null) {
+ FileLog.d(TAG, "trySettingPreviousGridAsCurrent:"
+ + ", oldPhoneDbFileName: " + oldPhoneDbFileName
+ + ", oldPhoneGridOption: " + oldPhoneGridOption
+ + ", previousDbs: " + previousDbs);
/* If the user only used the default db on the previous phone and the new default db is
* bigger than or equal to the previous one, then keep the new default db */
if (previousDbs.size() == 1 && oldPhoneGridOption.numColumns <= idp.numColumns
&& oldPhoneGridOption.numRows <= idp.numRows) {
/* Keep the user in default grid */
+ FileLog.d(TAG, "Keeping default db from restore as current grid");
return;
}
/*
* Here we are setting the previous db as the current one.
*/
+ FileLog.d(TAG, "Setting grid from old device as current grid: "
+ + "oldPhoneGridOption:" + oldPhoneGridOption.name);
idp.setCurrentGrid(context, oldPhoneGridOption.name);
}
}
diff --git a/src/com/android/launcher3/statemanager/StatefulActivity.java b/src/com/android/launcher3/statemanager/StatefulActivity.java
index 079191f..f21e5da 100644
--- a/src/com/android/launcher3/statemanager/StatefulActivity.java
+++ b/src/com/android/launcher3/statemanager/StatefulActivity.java
@@ -18,6 +18,7 @@
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
+import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE_RECREATE_TO_UPDATE_THEME;
import static com.android.launcher3.LauncherState.FLAG_NON_INTERACTIVE;
import android.content.Context;
@@ -29,6 +30,7 @@
import android.view.View;
import androidx.annotation.CallSuper;
+import androidx.annotation.NonNull;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.LauncherRootView;
@@ -54,6 +56,7 @@
protected Configuration mOldConfig;
private int mOldRotation;
+ private boolean mRecreateToUpdateTheme = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -63,6 +66,18 @@
mOldRotation = WindowManagerProxy.INSTANCE.get(this).getRotation(this);
}
+ @Override
+ protected void onSaveInstanceState(@NonNull Bundle outState) {
+ outState.putBoolean(RUNTIME_STATE_RECREATE_TO_UPDATE_THEME, mRecreateToUpdateTheme);
+ super.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void recreateToUpdateTheme() {
+ mRecreateToUpdateTheme = true;
+ super.recreateToUpdateTheme();
+ }
+
/**
* Create handlers to control the property changes for this activity
*/
diff --git a/src/com/android/launcher3/util/coroutines/DispatcherProvider.kt b/src/com/android/launcher3/util/coroutines/DispatcherProvider.kt
index e9691a8..8877535 100644
--- a/src/com/android/launcher3/util/coroutines/DispatcherProvider.kt
+++ b/src/com/android/launcher3/util/coroutines/DispatcherProvider.kt
@@ -17,18 +17,44 @@
package com.android.launcher3.util.coroutines
import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.newFixedThreadPoolContext
interface DispatcherProvider {
val default: CoroutineDispatcher
- val io: CoroutineDispatcher
+ val background: CoroutineDispatcher
val main: CoroutineDispatcher
val unconfined: CoroutineDispatcher
}
object ProductionDispatchers : DispatcherProvider {
+ private val bgDispatcher = CoroutinesHelper.bgDispatcher()
+
override val default: CoroutineDispatcher = Dispatchers.Default
- override val io: CoroutineDispatcher = Dispatchers.IO
+ override val background: CoroutineDispatcher = bgDispatcher
override val main: CoroutineDispatcher = Dispatchers.Main
override val unconfined: CoroutineDispatcher = Dispatchers.Unconfined
}
+
+private object CoroutinesHelper {
+ /**
+ * Default Coroutine dispatcher for background operations.
+ *
+ * Note that this is explicitly limiting the number of threads. In the past, we used
+ * [Dispatchers.IO]. This caused >40 threads to be spawned, and a lot of thread list lock
+ * contention between then, eventually causing jank.
+ */
+ @OptIn(DelicateCoroutinesApi::class)
+ fun bgDispatcher(): CoroutineDispatcher {
+ // Why a new ThreadPool instead of just using Dispatchers.IO with
+ // CoroutineDispatcher.limitedParallelism? Because, if we were to use Dispatchers.IO, we
+ // would share those threads with other dependencies using Dispatchers.IO.
+ // Using a dedicated thread pool we have guarantees only Launcher is able to schedule
+ // code on those.
+ return newFixedThreadPoolContext(
+ nThreads = Runtime.getRuntime().availableProcessors(),
+ name = "LauncherBg",
+ )
+ }
+}
diff --git a/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java b/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
index e100157..d4538dd 100644
--- a/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
+++ b/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
@@ -15,12 +15,15 @@
*/
package com.android.launcher3.widget;
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.widget.LauncherAppWidgetProviderInfo.fromProviderInfo;
+
+import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
@@ -30,17 +33,19 @@
import android.os.Handler;
import android.util.Log;
import android.util.Size;
+import android.widget.RemoteViews;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import androidx.core.os.BuildCompat;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.icons.BitmapRenderer;
import com.android.launcher3.icons.LauncherIcons;
-import com.android.launcher3.icons.ShadowGenerator;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.pm.ShortcutConfigActivityInfo;
import com.android.launcher3.util.CancellableTask;
@@ -52,20 +57,19 @@
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
-/** Utility class to load widget previews */
+/**
+ * Utility class to generate widget previews
+ *
+ * Note that it no longer uses database, all previews are freshly generated
+ */
public class DatabaseWidgetPreviewLoader {
private static final String TAG = "WidgetPreviewLoader";
private final Context mContext;
- private final float mPreviewBoxCornerRadius;
public DatabaseWidgetPreviewLoader(Context context) {
mContext = context;
- float previewCornerRadius = RoundedCornerEnforcement.computeEnforcedRadius(context);
- mPreviewBoxCornerRadius = previewCornerRadius > 0
- ? previewCornerRadius
- : mContext.getResources().getDimension(R.dimen.widget_preview_corner_radius);
}
/**
@@ -77,10 +81,10 @@
public CancellableTask loadPreview(
@NonNull WidgetItem item,
@NonNull Size previewSize,
- @NonNull Consumer<Bitmap> callback) {
+ @NonNull Consumer<WidgetPreviewInfo> callback) {
Handler handler = getLoaderExecutor().getHandler();
- CancellableTask<Bitmap> request = new CancellableTask<>(
- () -> generatePreview(item, previewSize.getWidth(), previewSize.getHeight()),
+ CancellableTask<WidgetPreviewInfo> request = new CancellableTask<>(
+ () -> generatePreviewInfoBg(item, previewSize.getWidth(), previewSize.getHeight()),
MAIN_EXECUTOR,
callback);
Utilities.postAsyncCallback(handler, request);
@@ -93,6 +97,39 @@
return Executors.UI_HELPER_EXECUTOR;
}
+ /** Generated the preview object. This method must be called on a background thread */
+ @VisibleForTesting
+ @NonNull
+ public WidgetPreviewInfo generatePreviewInfoBg(
+ WidgetItem item, int previewWidth, int previewHeight) {
+ WidgetPreviewInfo result = new WidgetPreviewInfo();
+
+ AppWidgetProviderInfo widgetInfo = item.widgetInfo;
+ if (BuildCompat.isAtLeastV() && Flags.enableGeneratedPreviews() && widgetInfo != null
+ && ((widgetInfo.generatedPreviewCategories & WIDGET_CATEGORY_HOME_SCREEN) != 0)) {
+ result.remoteViews = new WidgetManagerHelper(mContext)
+ .loadGeneratedPreview(widgetInfo, WIDGET_CATEGORY_HOME_SCREEN);
+ if (result.remoteViews != null) {
+ result.providerInfo = widgetInfo;
+ }
+ }
+
+ if (result.providerInfo == null && widgetInfo != null
+ && widgetInfo.previewLayout != Resources.ID_NULL) {
+ result.providerInfo = fromProviderInfo(mContext, widgetInfo.clone());
+ // A hack to force the initial layout to be the preview layout since there is no API for
+ // rendering a preview layout for work profile apps yet. For non-work profile layout, a
+ // proper solution is to use RemoteViews(PackageName, LayoutId).
+ result.providerInfo.initialLayout = item.widgetInfo.previewLayout;
+ }
+
+ if (result.providerInfo == null) {
+ // fallback to bitmap preview
+ result.previewBitmap = generatePreview(item, previewWidth, previewHeight);
+ }
+ return result;
+ }
+
/**
* Returns a generated preview for a widget and if the preview should be saved in persistent
* storage.
@@ -232,21 +269,6 @@
});
}
- private RectF drawBoxWithShadow(Canvas c, int width, int height) {
- Resources res = mContext.getResources();
-
- ShadowGenerator.Builder builder = new ShadowGenerator.Builder(Color.WHITE);
- builder.shadowBlur = res.getDimension(R.dimen.widget_preview_shadow_blur);
- builder.radius = mPreviewBoxCornerRadius;
- builder.keyShadowDistance = res.getDimension(R.dimen.widget_preview_key_shadow_distance);
-
- builder.bounds.set(builder.shadowBlur, builder.shadowBlur,
- width - builder.shadowBlur,
- height - builder.shadowBlur - builder.keyShadowDistance);
- builder.drawShadow(c);
- return builder.bounds;
- }
-
private Bitmap generateShortcutPreview(
ShortcutConfigActivityInfo info, int maxWidth, int maxHeight) {
int iconSize = ActivityContext.lookupContext(mContext).getDeviceProfile().allAppsIconSizePx;
@@ -280,4 +302,15 @@
throw new RuntimeException(e);
}
}
+
+ /**
+ * Simple class to hold preview information
+ */
+ public static class WidgetPreviewInfo {
+
+ public AppWidgetProviderInfo providerInfo;
+ public RemoteViews remoteViews;
+
+ public Bitmap previewBitmap;
+ }
}
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index 44ab966..b07d807 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -68,6 +68,8 @@
private static final String TRACE_METHOD_NAME = "appwidget load-widget ";
+ private static final Integer NO_LAYOUT_ID = Integer.valueOf(0);
+
private final CheckLongPressHelper mLongPressHelper;
protected final ActivityContext mActivityContext;
@@ -121,7 +123,7 @@
@Override
public void setAppWidget(int appWidgetId, AppWidgetProviderInfo info) {
super.setAppWidget(appWidgetId, info);
- if (!mTrackingWidgetUpdate) {
+ if (!mTrackingWidgetUpdate && appWidgetId != -1) {
mTrackingWidgetUpdate = true;
Trace.beginAsyncSection(TRACE_METHOD_NAME + info.provider, appWidgetId);
Log.i(TAG, "App widget created with id: " + appWidgetId);
@@ -164,6 +166,21 @@
return false;
}
+ private boolean isTaggedAsScrollable() {
+ // TODO: Introduce new api in AppWidgetHostView to indicate whether the widget is
+ // scrollable.
+ for (int i = 0; i < this.getChildCount(); i++) {
+ View child = this.getChildAt(i);
+ final Integer layoutId = (Integer) child.getTag(android.R.id.widget_frame);
+ if (layoutId != null) {
+ // The layout id is only set to 0 when RemoteViews is created from
+ // DrawInstructions.
+ return NO_LAYOUT_ID.equals(layoutId);
+ }
+ }
+ return false;
+ }
+
/**
* Returns true if the application of {@link RemoteViews} through {@link #updateAppWidget} are
* currently being deferred.
@@ -238,16 +255,6 @@
}
@Override
- public AppWidgetProviderInfo getAppWidgetInfo() {
- AppWidgetProviderInfo info = super.getAppWidgetInfo();
- if (info != null && !(info instanceof LauncherAppWidgetProviderInfo)) {
- throw new IllegalStateException("Launcher widget must have"
- + " LauncherAppWidgetProviderInfo");
- }
- return info;
- }
-
- @Override
public void getFocusedRect(Rect r) {
super.getFocusedRect(r);
// Outset to a larger rect for drawing a padding between focus outline and widget
@@ -266,7 +273,7 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- mIsScrollable = checkScrollableRecursively(this);
+ mIsScrollable = isTaggedAsScrollable() || checkScrollableRecursively(this);
}
/**
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index b7ad95e..4811a17 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -16,17 +16,17 @@
package com.android.launcher3.widget;
-import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
import static com.android.launcher3.Flags.enableWidgetTapToAdd;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY;
-import static com.android.launcher3.widget.LauncherAppWidgetProviderInfo.fromProviderInfo;
import static com.android.launcher3.widget.util.WidgetSizes.getWidgetItemSizePx;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
+import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Rect;
@@ -40,19 +40,17 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.RemoteViews;
import android.widget.TextView;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.app.animation.Interpolators;
import com.android.launcher3.CheckLongPressHelper;
-import com.android.launcher3.Flags;
-import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatedPropertySetter;
@@ -63,11 +61,10 @@
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.util.CancellableTask;
import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.widget.DatabaseWidgetPreviewLoader.WidgetPreviewInfo;
import com.android.launcher3.widget.picker.util.WidgetPreviewContainerSize;
import com.android.launcher3.widget.util.WidgetSizes;
-import java.util.function.Consumer;
-
/**
* Represents the individual cell of the widget inside the widget tray. The preview is drawn
* horizontally centered, and scaled down if needed.
@@ -154,7 +151,21 @@
mWidgetDescription = findViewById(R.id.widget_description);
mWidgetTextContainer = findViewById(R.id.widget_text_container);
mWidgetAddButton = findViewById(R.id.widget_add_button);
+
if (enableWidgetTapToAdd()) {
+
+ setAccessibilityDelegate(new AccessibilityDelegate() {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host,
+ AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ String accessibilityLabel = getResources().getString(mWidgetAddButton.isShown()
+ ? R.string.widget_cell_tap_to_hide_add_button_label
+ : R.string.widget_cell_tap_to_show_add_button_label);
+ info.addAction(new AccessibilityNodeInfo.AccessibilityAction(ACTION_CLICK,
+ accessibilityLabel));
+ }
+ });
mWidgetAddButton.setVisibility(INVISIBLE);
}
}
@@ -226,17 +237,6 @@
* Applies the item to this view
*/
public void applyFromCellItem(WidgetItem item) {
- applyFromCellItem(item, this::applyPreview, /*cachedPreview=*/null);
- }
-
- /**
- * Applies the item to this view
- * @param item item to apply
- * @param callback callback when preview is loaded in case the preview is being loaded or cached
- * @param cachedPreview previously cached preview bitmap is present
- */
- public void applyFromCellItem(WidgetItem item, @NonNull Consumer<Bitmap> callback,
- @Nullable Bitmap cachedPreview) {
Context context = getContext();
mItem = item;
mWidgetSize = getWidgetItemSizePx(getContext(), mActivity.getDeviceProfile(), mItem);
@@ -267,37 +267,28 @@
}
if (mRemoteViewsPreview != null) {
- mAppWidgetHostViewPreview = createAppWidgetHostView(context);
- setAppWidgetHostViewPreview(mAppWidgetHostViewPreview, item.widgetInfo,
- mRemoteViewsPreview);
- } else if (Flags.enableGeneratedPreviews()
- && item.hasGeneratedPreview(WIDGET_CATEGORY_HOME_SCREEN)) {
- mAppWidgetHostViewPreview = createAppWidgetHostView(context);
- setAppWidgetHostViewPreview(mAppWidgetHostViewPreview, item.widgetInfo,
- item.generatedPreviews.get(WIDGET_CATEGORY_HOME_SCREEN));
- } else if (item.hasPreviewLayout()) {
- // If the context is a Launcher activity, DragView will show mAppWidgetHostViewPreview
- // as a preview during drag & drop. And thus, we should use LauncherAppWidgetHostView,
- // which supports applying local color extraction during drag & drop.
- mAppWidgetHostViewPreview = isLauncherContext(context)
- ? new LauncherAppWidgetHostView(context)
- : createAppWidgetHostView(context);
- LauncherAppWidgetProviderInfo providerInfo =
- fromProviderInfo(context, item.widgetInfo.clone());
- // A hack to force the initial layout to be the preview layout since there is no API for
- // rendering a preview layout for work profile apps yet. For non-work profile layout, a
- // proper solution is to use RemoteViews(PackageName, LayoutId).
- providerInfo.initialLayout = item.widgetInfo.previewLayout;
- setAppWidgetHostViewPreview(mAppWidgetHostViewPreview, providerInfo, null);
- } else if (cachedPreview != null) {
- applyPreview(cachedPreview);
+ WidgetPreviewInfo previewInfo = new WidgetPreviewInfo();
+ previewInfo.providerInfo = item.widgetInfo;
+ previewInfo.remoteViews = mRemoteViewsPreview;
+ applyPreview(previewInfo);
} else {
if (mActiveRequest == null) {
- mActiveRequest = mWidgetPreviewLoader.loadPreview(mItem, mWidgetSize, callback);
+ mActiveRequest = mWidgetPreviewLoader.loadPreview(
+ mItem, mWidgetSize, this::applyPreview);
}
}
}
+ private void applyPreview(WidgetPreviewInfo previewInfo) {
+ if (previewInfo.providerInfo != null) {
+ mAppWidgetHostViewPreview = createAppWidgetHostView(getContext());
+ setAppWidgetHostViewPreview(mAppWidgetHostViewPreview, previewInfo.providerInfo,
+ previewInfo.remoteViews);
+ } else {
+ applyBitmapPreview(previewInfo.previewBitmap);
+ }
+ }
+
private void initPreviewContainerSizeAndScale() {
WidgetPreviewContainerSize previewSize = WidgetPreviewContainerSize.Companion.forItem(mItem,
mActivity.getDeviceProfile());
@@ -321,7 +312,7 @@
private void setAppWidgetHostViewPreview(
NavigableAppWidgetHostView appWidgetHostViewPreview,
- LauncherAppWidgetProviderInfo providerInfo,
+ AppWidgetProviderInfo providerInfo,
@Nullable RemoteViews remoteViews) {
appWidgetHostViewPreview.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
appWidgetHostViewPreview.setAppWidget(/* appWidgetId= */ -1, providerInfo);
@@ -333,7 +324,7 @@
mWidgetSize.getWidth(), mWidgetSize.getHeight(), Gravity.CENTER);
mWidgetImageContainer.addView(appWidgetHostViewPreview, /* index= */ 0, widgetHostLP);
mWidgetImage.setVisibility(View.GONE);
- applyPreview(null);
+ applyBitmapPreview(null);
appWidgetHostViewPreview.addOnLayoutChangeListener(
(v, l, t, r, b, ol, ot, or, ob) ->
@@ -391,7 +382,7 @@
mAnimatePreview = shouldAnimate;
}
- private void applyPreview(Bitmap bitmap) {
+ private void applyBitmapPreview(Bitmap bitmap) {
if (bitmap != null) {
Drawable drawable = new RoundDrawableWrapper(
new FastBitmapDrawable(bitmap), mEnforcedCornerRadius);
@@ -480,8 +471,8 @@
mLongPressHelper.cancelLongPress();
}
- private static NavigableAppWidgetHostView createAppWidgetHostView(Context context) {
- return new NavigableAppWidgetHostView(context) {
+ private static LauncherAppWidgetHostView createAppWidgetHostView(Context context) {
+ return new LauncherAppWidgetHostView(context) {
@Override
protected boolean shouldAllowDirectClick() {
return false;
@@ -489,10 +480,6 @@
};
}
- private static boolean isLauncherContext(Context context) {
- return ActivityContext.lookupContext(context) instanceof Launcher;
- }
-
@Override
public CharSequence getAccessibilityClassName() {
return WidgetCell.class.getName();
diff --git a/tests/Launcher3Tests.xml b/tests/Launcher3Tests.xml
index 270a610..a876860 100644
--- a/tests/Launcher3Tests.xml
+++ b/tests/Launcher3Tests.xml
@@ -48,6 +48,8 @@
<option name="run-command" value="settings put system pointer_location 1" />
<option name="run-command" value="settings put system show_touches 1" />
+
+ <option name="run-command" value="setprop pixel_legal_joint_permission_v2 true" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/tests/multivalentTests/src/com/android/launcher3/folder/FolderNameProviderTest.java b/tests/multivalentTests/src/com/android/launcher3/folder/FolderNameProviderTest.java
index 9c15309..b6fa81c 100644
--- a/tests/multivalentTests/src/com/android/launcher3/folder/FolderNameProviderTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/folder/FolderNameProviderTest.java
@@ -23,6 +23,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.os.Process;
import android.os.UserHandle;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -49,16 +50,17 @@
@Before
public void setUp() {
mContext = new ActivityContextWrapper(getApplicationContext());
+ int workUserId = Process.myUserHandle().hashCode() + 1;
mItem1 = new WorkspaceItemInfo(new AppInfo(
new ComponentName("a.b.c", "a.b.c/a.b.c.d"),
"title1",
- UserHandle.of(10),
+ UserHandle.of(workUserId),
new Intent().setComponent(new ComponentName("a.b.c", "a.b.c/a.b.c.d"))
));
mItem2 = new WorkspaceItemInfo(new AppInfo(
new ComponentName("a.b.c", "a.b.c/a.b.c.d"),
"title2",
- UserHandle.of(10),
+ UserHandle.of(workUserId),
new Intent().setComponent(new ComponentName("a.b.c", "a.b.c/a.b.c.d"))
));
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt b/tests/multivalentTests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
index 111ffaa..7f481b7 100644
--- a/tests/multivalentTests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
@@ -18,6 +18,7 @@
import android.R
import android.content.Context
+import android.graphics.Bitmap
import android.os.Process
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -26,9 +27,9 @@
import com.android.launcher3.LauncherPrefs.Companion.THEMED_ICONS
import com.android.launcher3.LauncherPrefs.Companion.get
import com.android.launcher3.graphics.PreloadIconDrawable
-import com.android.launcher3.icons.BaseIconFactory
import com.android.launcher3.icons.FastBitmapDrawable
import com.android.launcher3.icons.UserBadgeDrawable
+import com.android.launcher3.icons.mono.MonoThemedBitmap
import com.android.launcher3.model.data.FolderInfo
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED
@@ -88,54 +89,26 @@
// Use getAppContents() to "cast" contents to WorkspaceItemInfo so we can set bitmaps
val folderApps = modelHelper.bgDataModel.collections.valueAt(0).getAppContents()
// Set first icon to be themed.
- folderApps[0]
- .bitmap
- .setMonoIcon(
+ folderApps[0].bitmap.themedBitmap =
+ MonoThemedBitmap(
folderApps[0].bitmap.icon,
- BaseIconFactory(
- context,
- context.resources.configuration.densityDpi,
- previewItemManager.mIconSize,
- ),
+ Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888),
)
// Set second icon to be non-themed.
- folderApps[1]
- .bitmap
- .setMonoIcon(
- null,
- BaseIconFactory(
- context,
- context.resources.configuration.densityDpi,
- previewItemManager.mIconSize,
- ),
- )
+ folderApps[1].bitmap.themedBitmap = null
// Set third icon to be themed with badge.
- folderApps[2]
- .bitmap
- .setMonoIcon(
+ folderApps[2].bitmap.themedBitmap =
+ MonoThemedBitmap(
folderApps[2].bitmap.icon,
- BaseIconFactory(
- context,
- context.resources.configuration.densityDpi,
- previewItemManager.mIconSize,
- ),
+ Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888),
)
folderApps[2].bitmap = folderApps[2].bitmap.withFlags(profileFlagOp(UserIconInfo.TYPE_WORK))
// Set fourth icon to be non-themed with badge.
folderApps[3].bitmap = folderApps[3].bitmap.withFlags(profileFlagOp(UserIconInfo.TYPE_WORK))
- folderApps[3]
- .bitmap
- .setMonoIcon(
- null,
- BaseIconFactory(
- context,
- context.resources.configuration.densityDpi,
- previewItemManager.mIconSize,
- ),
- )
+ folderApps[3].bitmap.themedBitmap = null
defaultThemedIcons = get(context).get(THEMED_ICONS)
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/icons/mono/MonoIconThemeControllerTest.kt b/tests/multivalentTests/src/com/android/launcher3/icons/mono/MonoIconThemeControllerTest.kt
new file mode 100644
index 0000000..4af564e
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/icons/mono/MonoIconThemeControllerTest.kt
@@ -0,0 +1,131 @@
+/*
+ * 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.icons.mono
+
+import android.graphics.Color
+import android.graphics.drawable.AdaptiveIconDrawable
+import android.graphics.drawable.ColorDrawable
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import android.platform.uiautomatorhelpers.DeviceHelpers.context
+import android.util.DisplayMetrics
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.Flags
+import com.android.launcher3.icons.BaseIconFactory
+import com.android.launcher3.icons.BitmapInfo
+import com.android.launcher3.util.LauncherMultivalentJUnit.Companion.isRunningInRobolectric
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertNull
+import org.junit.Assume.assumeFalse
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MonoIconThemeControllerTest {
+
+ @get:Rule val mSetFlagsRule = SetFlagsRule()
+
+ private val iconFactory = BaseIconFactory(context, DisplayMetrics.DENSITY_MEDIUM, 30)
+
+ @Test
+ fun `createThemedBitmap when mono drawable is present`() {
+ val icon = AdaptiveIconDrawable(ColorDrawable(Color.BLACK), null, ColorDrawable(Color.RED))
+ assertNotNull(
+ MonoIconThemeController().createThemedBitmap(icon, BitmapInfo.LOW_RES_INFO, iconFactory)
+ )
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_FORCE_MONOCHROME_APP_ICONS)
+ fun `createThemedBitmap when mono generation is disabled`() {
+ val icon = AdaptiveIconDrawable(ColorDrawable(Color.BLACK), null, null)
+ assertNull(
+ MonoIconThemeController().createThemedBitmap(icon, BitmapInfo.LOW_RES_INFO, iconFactory)
+ )
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_FORCE_MONOCHROME_APP_ICONS)
+ fun `createThemedBitmap when mono generation is enabled`() {
+ ensureBitmapSerializationSupported()
+ val icon = AdaptiveIconDrawable(ColorDrawable(Color.BLACK), null, null)
+ assertNotNull(
+ MonoIconThemeController().createThemedBitmap(icon, BitmapInfo.LOW_RES_INFO, iconFactory)
+ )
+ }
+
+ @Test
+ fun `decode bitmap after serialization valid data`() {
+ ensureBitmapSerializationSupported()
+ val icon = AdaptiveIconDrawable(ColorDrawable(Color.BLACK), null, ColorDrawable(Color.RED))
+ val iconInfo = iconFactory.createBadgedIconBitmap(icon)
+
+ val themeBitmap =
+ MonoIconThemeController().createThemedBitmap(icon, iconInfo, iconFactory)!!
+ assertNotNull(
+ MonoIconThemeController().decode(themeBitmap.serialize(), iconInfo, iconFactory)
+ )
+ }
+
+ @Test
+ fun `decode bitmap after serialization invalid data`() {
+ ensureBitmapSerializationSupported()
+ val icon = AdaptiveIconDrawable(ColorDrawable(Color.BLACK), null, ColorDrawable(Color.RED))
+ val iconInfo = iconFactory.createBadgedIconBitmap(icon)
+ assertNull(MonoIconThemeController().decode(byteArrayOf(1, 1, 1, 1), iconInfo, iconFactory))
+ }
+
+ @Test
+ fun `createThemedAdaptiveIcon with monochrome drawable`() {
+ val icon = AdaptiveIconDrawable(ColorDrawable(Color.BLACK), null, ColorDrawable(Color.RED))
+ assertNotNull(MonoIconThemeController().createThemedAdaptiveIcon(context, icon, null))
+ }
+
+ @Test
+ fun `createThemedAdaptiveIcon with bitmap info`() {
+ val icon = AdaptiveIconDrawable(ColorDrawable(Color.BLACK), null, ColorDrawable(Color.RED))
+ val iconInfo = iconFactory.createBadgedIconBitmap(icon)
+ iconInfo.themedBitmap =
+ MonoIconThemeController().createThemedBitmap(icon, iconInfo, iconFactory)
+
+ val nonMonoIcon = AdaptiveIconDrawable(ColorDrawable(Color.BLACK), null, null)
+ assertNotNull(
+ MonoIconThemeController().createThemedAdaptiveIcon(context, nonMonoIcon, iconInfo)
+ )
+ }
+
+ @Test
+ fun `createThemedAdaptiveIcon invalid bitmap info`() {
+ val nonMonoIcon = AdaptiveIconDrawable(ColorDrawable(Color.BLACK), null, null)
+ assertNull(
+ MonoIconThemeController()
+ .createThemedAdaptiveIcon(context, nonMonoIcon, BitmapInfo.LOW_RES_INFO)
+ )
+ }
+
+ companion object {
+
+ fun ensureBitmapSerializationSupported() {
+ // Robolectric doesn't support serializing 8-bit bitmaps
+ assumeFalse(isRunningInRobolectric)
+ }
+ }
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/icons/mono/MonoThemedBitmapTest.kt b/tests/multivalentTests/src/com/android/launcher3/icons/mono/MonoThemedBitmapTest.kt
new file mode 100644
index 0000000..32de9e9
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/icons/mono/MonoThemedBitmapTest.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.icons.mono
+
+import android.graphics.Bitmap
+import android.platform.uiautomatorhelpers.DeviceHelpers.context
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.icons.BitmapInfo
+import com.android.launcher3.icons.mono.MonoIconThemeControllerTest.Companion.ensureBitmapSerializationSupported
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MonoThemedBitmapTest {
+
+ @Test
+ fun `newDrawable returns valid drawable`() {
+ val bitmap =
+ MonoThemedBitmap(
+ Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8),
+ Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888),
+ )
+ val d = bitmap.newDrawable(BitmapInfo.LOW_RES_INFO, context)
+ assertTrue(d is ThemedIconDrawable)
+ }
+
+ @Test
+ fun `serialize returns valid bytes`() {
+ ensureBitmapSerializationSupported()
+ val bitmap =
+ MonoThemedBitmap(
+ Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8),
+ Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888),
+ )
+ assertTrue(bitmap.serialize().isNotEmpty())
+ }
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt
index 9cc380e..db37247 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt
@@ -20,7 +20,7 @@
import android.content.ComponentName
import android.content.Intent
import android.content.pm.PackageInstaller.SessionInfo
-import android.os.UserHandle
+import android.os.Process.myUserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
@@ -77,16 +77,18 @@
SessionInfo().apply {
installerPackageName = expectedInstallerPackage
appPackageName = expectedAppPackage
+ userId = myUserHandle().identifier
}
val sessionInfoUnexpected =
SessionInfo().apply {
installerPackageName = expectedInstallerPackage
appPackageName = unexpectedAppPackage
+ userId = myUserHandle().identifier
}
val sessionInfoMap: HashMap<PackageUserKey, SessionInfo> =
hashMapOf(
- PackageUserKey(unexpectedAppPackage, UserHandle(0)) to sessionInfoExpected,
- PackageUserKey(expectedAppPackage, UserHandle(0)) to sessionInfoUnexpected,
+ PackageUserKey(unexpectedAppPackage, myUserHandle()) to sessionInfoExpected,
+ PackageUserKey(expectedAppPackage, myUserHandle()) to sessionInfoUnexpected,
)
// When
@@ -200,16 +202,18 @@
SessionInfo().apply {
installerPackageName = expectedInstallerPackage
appPackageName = expectedAppPackage
+ userId = myUserHandle().identifier
}
val sessionInfoUnexpected =
SessionInfo().apply {
installerPackageName = expectedInstallerPackage
appPackageName = unexpectedAppPackage
+ userId = myUserHandle().identifier
}
val sessionInfoMap: HashMap<PackageUserKey, SessionInfo> =
hashMapOf(
- PackageUserKey(unexpectedAppPackage, UserHandle(0)) to sessionInfoExpected,
- PackageUserKey(expectedAppPackage, UserHandle(0)) to sessionInfoUnexpected,
+ PackageUserKey(unexpectedAppPackage, myUserHandle()) to sessionInfoExpected,
+ PackageUserKey(expectedAppPackage, myUserHandle()) to sessionInfoUnexpected,
)
val expectedItemInfo = WorkspaceItemInfo().apply { intent = expectedIntent }
val expectedFolderInfo = FolderInfo().apply { add(expectedItemInfo) }
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/TestDispatcherProvider.kt b/tests/multivalentTests/src/com/android/launcher3/util/TestDispatcherProvider.kt
index 39e1ec5..3319c53 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/TestDispatcherProvider.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/TestDispatcherProvider.kt
@@ -21,7 +21,7 @@
class TestDispatcherProvider(testDispatcher: CoroutineDispatcher) : DispatcherProvider {
override val default: CoroutineDispatcher = testDispatcher
- override val io: CoroutineDispatcher = testDispatcher
+ override val background: CoroutineDispatcher = testDispatcher
override val main: CoroutineDispatcher = testDispatcher
override val unconfined: CoroutineDispatcher = testDispatcher
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt b/tests/multivalentTests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
index ac5fda2..b92582c 100644
--- a/tests/multivalentTests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
@@ -1,9 +1,8 @@
package com.android.launcher3.widget
+import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProviderInfo
import android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN
-import android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD
-import android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX
import android.content.ComponentName
import android.content.Context
import android.content.pm.ActivityInfo
@@ -14,23 +13,30 @@
import android.view.ContextThemeWrapper
import android.view.LayoutInflater
import android.widget.RemoteViews
-import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.android.launcher3.Flags.FLAG_ENABLE_GENERATED_PREVIEWS
import com.android.launcher3.InvariantDeviceProfile
+import com.android.launcher3.R
import com.android.launcher3.icons.IconCache
-import com.android.launcher3.icons.IconProvider
import com.android.launcher3.model.WidgetItem
import com.android.launcher3.util.ActivityContextWrapper
import com.android.launcher3.util.Executors
+import com.android.launcher3.util.Executors.MAIN_EXECUTOR
+import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext
+import com.android.launcher3.util.TestUtil
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.whenever
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -46,28 +52,25 @@
getInstrumentation().context.run {
resources.getIdentifier("test_layout_appwidget_blue", "layout", packageName)
}
- private lateinit var context: Context
+
+ private lateinit var context: SandboxModelContext
+ private lateinit var uiContext: Context
private lateinit var generatedPreview: RemoteViews
private lateinit var widgetCell: WidgetCell
- private lateinit var helper: WidgetManagerHelper
private lateinit var appWidgetProviderInfo: LauncherAppWidgetProviderInfo
private lateinit var widgetItem: WidgetItem
- private lateinit var iconCache: IconCache
+
+ @Mock lateinit var iconCache: IconCache
@Before
fun setup() {
- context = getApplicationContext()
+ MockitoAnnotations.initMocks(this)
+ context = SandboxModelContext()
generatedPreview = RemoteViews(context.packageName, generatedPreviewLayout)
+ uiContext =
+ ActivityContextWrapper(ContextThemeWrapper(context, R.style.WidgetContainerTheme))
widgetCell =
- LayoutInflater.from(
- ActivityContextWrapper(
- ContextThemeWrapper(
- context,
- com.android.launcher3.R.style.WidgetContainerTheme,
- )
- )
- )
- .inflate(com.android.launcher3.R.layout.widget_cell, null) as WidgetCell
+ LayoutInflater.from(uiContext).inflate(R.layout.widget_cell, null) as WidgetCell
appWidgetProviderInfo =
AppWidgetProviderInfo()
.apply {
@@ -76,72 +79,52 @@
providerInfo = ActivityInfo().apply { applicationInfo = ApplicationInfo() }
}
.let { LauncherAppWidgetProviderInfo.fromProviderInfo(context, it) }
- helper =
- object : WidgetManagerHelper(context) {
- override fun loadGeneratedPreview(
- info: AppWidgetProviderInfo,
- widgetCategory: Int,
- ) =
- generatedPreview.takeIf {
- info === appWidgetProviderInfo &&
- widgetCategory == WIDGET_CATEGORY_HOME_SCREEN
- }
+
+ val widgetManager = context.spyService(AppWidgetManager::class.java)
+ doAnswer { i ->
+ generatedPreview.takeIf {
+ i.arguments[0] == appWidgetProviderInfo.provider &&
+ i.arguments[1] == appWidgetProviderInfo.user &&
+ i.arguments[2] == WIDGET_CATEGORY_HOME_SCREEN
+ }
}
+ .whenever(widgetManager)
+ .getWidgetPreview(any(), any(), any())
createWidgetItem()
}
@After
fun tearDown() {
- iconCache.close()
+ context.destroy()
}
private fun createWidgetItem() {
Executors.MODEL_EXECUTOR.submit {
val idp = InvariantDeviceProfile()
- if (::iconCache.isInitialized) iconCache.close()
- iconCache = IconCache(context, idp, null, IconProvider(context))
- widgetItem = WidgetItem(appWidgetProviderInfo, idp, iconCache, context, helper)
+ widgetItem = WidgetItem(appWidgetProviderInfo, idp, iconCache, context)
}
.get()
}
@Test
- fun widgetItem_hasGeneratedPreview() {
- assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_HOME_SCREEN)).isTrue()
- assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_KEYGUARD)).isFalse()
- assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_SEARCHBOX)).isFalse()
- }
-
- @Test
fun widgetItem_hasGeneratedPreview_noPreview() {
appWidgetProviderInfo.generatedPreviewCategories = 0
createWidgetItem()
- assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_HOME_SCREEN)).isFalse()
- assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_KEYGUARD)).isFalse()
- assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_SEARCHBOX)).isFalse()
- }
-
- @Test
- fun widgetItem_hasGeneratedPreview_nullPreview() {
- appWidgetProviderInfo.generatedPreviewCategories =
- WIDGET_CATEGORY_HOME_SCREEN or WIDGET_CATEGORY_KEYGUARD
- createWidgetItem()
- assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_HOME_SCREEN)).isTrue()
- // loadGeneratedPreview returns null for KEYGUARD, so this should still be false.
- assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_KEYGUARD)).isFalse()
- assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_SEARCHBOX)).isFalse()
+ val preview = DatabaseWidgetPreviewLoader(uiContext).generatePreviewInfoBg(widgetItem, 1, 1)
+ assertThat(preview.remoteViews).isNull()
}
@Test
fun widgetItem_getGeneratedPreview() {
- val preview = widgetItem.generatedPreviews.get(WIDGET_CATEGORY_HOME_SCREEN)
- assertThat(preview).isEqualTo(generatedPreview)
+ val preview = DatabaseWidgetPreviewLoader(uiContext).generatePreviewInfoBg(widgetItem, 1, 1)
+ assertThat(preview.remoteViews).isEqualTo(generatedPreview)
}
@Test
fun widgetCell_showGeneratedPreview() {
widgetCell.applyFromCellItem(widgetItem)
- DatabaseWidgetPreviewLoader.getLoaderExecutor().submit {}.get()
+ TestUtil.runOnExecutorSync(DatabaseWidgetPreviewLoader.getLoaderExecutor()) {}
+ TestUtil.runOnExecutorSync(MAIN_EXECUTOR) {}
assertThat(widgetCell.appWidgetHostViewPreview).isNotNull()
assertThat(widgetCell.appWidgetHostViewPreview?.appWidgetInfo)
.isEqualTo(appWidgetProviderInfo)
diff --git a/tests/multivalentTests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java b/tests/multivalentTests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
index 0d9464a..86bbcc1 100644
--- a/tests/multivalentTests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
@@ -54,7 +54,6 @@
import com.android.launcher3.widget.DatabaseWidgetPreviewLoader;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.WidgetCell;
-import com.android.launcher3.widget.WidgetManagerHelper;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import org.junit.Before;
@@ -143,7 +142,6 @@
}
private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
- WidgetManagerHelper widgetManager = new WidgetManagerHelper(mContext);
ArrayList<WidgetItem> widgetItems = new ArrayList<>();
for (int i = 0; i < numOfWidgets; i++) {
ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
@@ -151,7 +149,7 @@
widgetItems.add(new WidgetItem(
LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
- mTestProfile, mIconCache, mContext, widgetManager));
+ mTestProfile, mIconCache, mContext));
}
return widgetItems;
}
diff --git a/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java b/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java
index 34b292c..f494f38 100644
--- a/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java
+++ b/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java
@@ -16,6 +16,8 @@
package com.android.launcher3.compat;
+import static android.os.Process.myUserHandle;
+
import static com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING;
import static com.google.common.truth.Truth.assertThat;
@@ -136,7 +138,8 @@
public void testPromiseIcon_addedArchivedApp() throws Throwable {
installDummyAppAndWaitForUIUpdate();
assertThat(executeShellCommand(
- String.format("pm archive %s", DUMMY_PACKAGE)))
+ String.format("pm archive --user %d %s",
+ myUserHandle().getIdentifier(), DUMMY_PACKAGE)))
.isEqualTo("Success\n");
// Create and add test session
diff --git a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
index 882061f..34cbdee 100644
--- a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
@@ -2,6 +2,7 @@
import android.appwidget.AppWidgetManager
import android.content.Intent
+import android.os.Process
import android.os.UserHandle
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
@@ -136,7 +137,7 @@
@Test
fun loadsDataProperly() =
with(BgDataModel()) {
- val MAIN_HANDLE = UserHandle.of(0)
+ val MAIN_HANDLE = Process.myUserHandle()
val mockUserHandles = arrayListOf<UserHandle>(MAIN_HANDLE)
`when`(userCache.userProfiles).thenReturn(mockUserHandles)
`when`(userCache.getUserInfo(MAIN_HANDLE)).thenReturn(UserIconInfo(MAIN_HANDLE, 1))
@@ -186,7 +187,7 @@
fun setsQuietModeFlagCorrectlyForWorkProfile() =
with(BgDataModel()) {
setFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE)
- val MAIN_HANDLE = UserHandle.of(0)
+ val MAIN_HANDLE = Process.myUserHandle()
val mockUserHandles = arrayListOf<UserHandle>(MAIN_HANDLE)
`when`(userCache.userProfiles).thenReturn(mockUserHandles)
`when`(userManagerState?.isUserQuiet(MAIN_HANDLE)).thenReturn(true)
@@ -215,7 +216,7 @@
fun setsQuietModeFlagCorrectlyForPrivateProfile() =
with(BgDataModel()) {
setFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE)
- val MAIN_HANDLE = UserHandle.of(0)
+ val MAIN_HANDLE = Process.myUserHandle()
val mockUserHandles = arrayListOf<UserHandle>(MAIN_HANDLE)
`when`(userCache.userProfiles).thenReturn(mockUserHandles)
`when`(userManagerState?.isUserQuiet(MAIN_HANDLE)).thenReturn(true)
diff --git a/tests/src/com/android/launcher3/ui/BaseLauncherTaplTest.java b/tests/src/com/android/launcher3/ui/BaseLauncherTaplTest.java
index 8449853..9fa1500 100644
--- a/tests/src/com/android/launcher3/ui/BaseLauncherTaplTest.java
+++ b/tests/src/com/android/launcher3/ui/BaseLauncherTaplTest.java
@@ -16,6 +16,7 @@
package com.android.launcher3.ui;
+import static android.os.Process.myUserHandle;
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -219,7 +220,8 @@
protected void clearPackageData(String pkg) throws IOException, InterruptedException {
assertTrue("pm clear command failed",
- mDevice.executeShellCommand("pm clear " + pkg)
+ mDevice.executeShellCommand(
+ String.format("pm clear --user %d %s", myUserHandle().getIdentifier(), pkg))
.contains("Success"));
assertTrue("pm wait-for-handler command failed",
mDevice.executeShellCommand("pm wait-for-handler")
diff --git a/tests/src/com/android/launcher3/ui/WorkProfileTest.java b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
index d866a9f..b6c1135 100644
--- a/tests/src/com/android/launcher3/ui/WorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
@@ -26,6 +26,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
+import android.os.Process;
import android.util.Log;
import android.view.View;
@@ -73,7 +74,9 @@
@Before
public void setUp() throws Exception {
- String output = executeShellCommand("pm create-user --profileOf 0 --managed TestProfile");
+ String output = executeShellCommand(String.format(
+ "pm create-user --profileOf %d --managed TestProfile",
+ Process.myUserHandle().getIdentifier()));
updateWorkProfileSetupSuccessful("pm create-user", output);
String[] tokens = output.split("\\s+");
@@ -146,7 +149,7 @@
executeOnLauncher(l -> {
// Ensure updates are not deferred so notification happens when apps pause.
l.getAppsView().getAppsStore().disableDeferUpdates(DEFER_UPDATES_TEST);
- l.getAppsView().getWorkManager().getWorkUtilityView().performClick();
+ l.getAppsView().getWorkManager().getWorkUtilityView().getWorkFAB().performClick();
});
waitForLauncherCondition("Work profile toggle OFF failed", launcher -> {
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
index bb645d7..64ad305 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
@@ -123,7 +123,7 @@
v instanceof WidgetCell
&& v.getTag() instanceof PendingAddWidgetInfo pawi
&& mWidgetInfo.provider.equals(pawi.componentName)));
- addToWorkspace(widgetView);
+ addWidgetToWorkspace(widgetView);
// Widget id for which the config activity was opened
mWidgetId = monitor.getWidgetId();
diff --git a/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java b/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
index c623513..c852729 100644
--- a/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
@@ -37,7 +37,7 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.allapps.AllAppsRecyclerView;
import com.android.launcher3.celllayout.FavoriteItemsTransaction;
-import com.android.launcher3.icons.ThemedIconDrawable;
+import com.android.launcher3.icons.mono.ThemedIconDrawable;
import com.android.launcher3.popup.ArrowPopup;
import com.android.launcher3.util.BaseLauncherActivityTest;
import com.android.launcher3.util.Executors;
diff --git a/tests/src/com/android/launcher3/util/BaseLauncherActivityTest.kt b/tests/src/com/android/launcher3/util/BaseLauncherActivityTest.kt
index 61fa7d5..b5702c9 100644
--- a/tests/src/com/android/launcher3/util/BaseLauncherActivityTest.kt
+++ b/tests/src/com/android/launcher3/util/BaseLauncherActivityTest.kt
@@ -170,6 +170,18 @@
UiDevice.getInstance(getInstrumentation()).waitForIdle()
}
+ /**
+ * Match the behavior with how widget is added in reality with "tap to add" (even with screen
+ * readers).
+ */
+ fun addWidgetToWorkspace(view: View) {
+ executeOnLauncher {
+ view.performClick()
+ UiDevice.getInstance(getInstrumentation()).waitForIdle()
+ view.findViewById<View>(R.id.widget_add_button).performClick()
+ }
+ }
+
fun ViewGroup.searchView(filter: Predicate<View>): View? {
if (filter.test(this)) return this
for (child in children) {
diff --git a/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java b/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java
index 2219003..a0f227e 100644
--- a/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java
+++ b/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java
@@ -21,6 +21,7 @@
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
+import android.os.Process;
import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
@@ -109,8 +110,9 @@
}
public static String getLauncherCommand(ActivityInfo launcher) {
- return "cmd package set-home-activity " +
- new ComponentName(launcher.packageName, launcher.name).flattenToString();
+ return String.format("cmd package set-home-activity --user %d %s",
+ Process.myUserHandle().getIdentifier(),
+ new ComponentName(launcher.packageName, launcher.name).flattenToString());
}
/**
diff --git a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java
index 7f6062f..b43bfcf 100644
--- a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java
+++ b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java
@@ -33,10 +33,9 @@
import androidx.test.uiautomator.SearchCondition;
import androidx.test.uiautomator.UiDevice;
-import org.junit.Assert;
-
import java.util.Date;
import java.util.List;
+import java.util.Objects;
public class TestHelpers {
@@ -113,8 +112,8 @@
}
private static String checkCrash(Context context, String label, long startTime) {
- DropBoxManager dropbox = (DropBoxManager) context.getSystemService(Context.DROPBOX_SERVICE);
- Assert.assertNotNull("Unable access the DropBoxManager service", dropbox);
+ DropBoxManager dropbox = Objects.requireNonNull(
+ context.getSystemService(DropBoxManager.class));
long timestamp = startTime;
DropBoxManager.Entry entry;