Merge "Replace verifyZeroInteractions with verifyNoMoreInteractions" into main
diff --git a/OWNERS b/OWNERS
index 32c82c5..a66bf54 100644
--- a/OWNERS
+++ b/OWNERS
@@ -50,3 +50,6 @@
per-file DeviceConfigWrapper.java, globs = set noparent
per-file DeviceConfigWrapper.java = sunnygoyal@google.com, winsonc@google.com, adamcohen@google.com, hyunyoungs@google.com
+
+# Predictive Back
+per-file LauncherBackAnimationController.java = shanh@google.com, gallmann@google.com
\ No newline at end of file
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 3d15e77..ff97b22 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,6 +1,13 @@
+[Builtin Hooks]
+ktfmt = true
+
+[Builtin Hooks Options]
+ktfmt = --kotlinlang-style
+
+[Tool Paths]
+ktfmt = ${REPO_ROOT}/prebuilts/build-tools/common/framework/ktfmt.jar
+
[Hook Scripts]
checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --config_xml tools/checkstyle.xml --sha ${PREUPLOAD_COMMIT}
-ktfmt_hook = ${REPO_ROOT}/external/ktfmt/ktfmt.py --check ${PREUPLOAD_FILES}
-
flag_hook = ${REPO_ROOT}/frameworks/base/packages/SystemUI/flag_check.py --msg=${PREUPLOAD_COMMIT_MESSAGE} --files=${PREUPLOAD_FILES} --project=${REPO_PATH}
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 8682e5d..9147e4c 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -284,10 +284,3 @@
description: "Enables folders in all apps"
bug: "341582436"
}
-
-flag {
- name: "enable_tiny_taskbar"
- namespace: "launcher"
- description: "Enables Taskbar on phones"
- bug: "341784466"
-}
diff --git a/go/quickstep/res/layout/overview_actions_container.xml b/go/quickstep/res/layout/overview_actions_container.xml
index b1a6202..e31f462 100644
--- a/go/quickstep/res/layout/overview_actions_container.xml
+++ b/go/quickstep/res/layout/overview_actions_container.xml
@@ -124,23 +124,15 @@
</LinearLayout>
<!-- Unused. Included only for compatibility with parent class. -->
- <LinearLayout
- android:id="@+id/group_action_buttons"
- android:layout_width="match_parent"
- android:layout_height="@dimen/overview_actions_height"
+ <Button
+ android:id="@+id/action_save_app_pair"
+ style="@style/GoOverviewActionButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_gravity="top|center_horizontal"
- android:orientation="horizontal"
- android:visibility="gone">
-
- <Button
- android:id="@+id/action_save_app_pair"
- style="@style/GoOverviewActionButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:drawableStart="@drawable/ic_save_app_pair_up_down"
- android:text="@string/action_save_app_pair"
- android:theme="@style/ThemeControlHighlightWorkspaceColor" />
-
- </LinearLayout>
+ android:drawableStart="@drawable/ic_save_app_pair_up_down"
+ android:text="@string/action_save_app_pair"
+ android:theme="@style/ThemeControlHighlightWorkspaceColor"
+ android:visibility="gone" />
</com.android.quickstep.views.GoOverviewActionsView>
\ No newline at end of file
diff --git a/quickstep/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml
index 7aaf744..fcd2e54 100644
--- a/quickstep/res/layout/overview_actions_container.xml
+++ b/quickstep/res/layout/overview_actions_container.xml
@@ -47,22 +47,16 @@
</LinearLayout>
- <LinearLayout
- android:id="@+id/group_action_buttons"
+ <!-- Currently, the only "group action button" is this save app pair button. If more are added,
+ a new LinearLayout may be needed to contain them, but beware of increased memory usage. -->
+ <Button
+ android:id="@+id/action_save_app_pair"
+ style="@style/OverviewActionButton"
android:layout_width="wrap_content"
- android:layout_height="@dimen/overview_actions_height"
+ android:layout_height="wrap_content"
+ android:text="@string/action_save_app_pair"
+ android:theme="@style/ThemeControlHighlightWorkspaceColor"
android:layout_gravity="bottom|center_horizontal"
- android:orientation="horizontal"
- android:visibility="gone">
-
- <Button
- android:id="@+id/action_save_app_pair"
- style="@style/OverviewActionButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/action_save_app_pair"
- android:theme="@style/ThemeControlHighlightWorkspaceColor" />
-
- </LinearLayout>
+ android:visibility="gone" />
</com.android.quickstep.views.OverviewActionsView>
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 2021a0b..08d36d8 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -358,6 +358,9 @@
<dimen name="taskbar_running_app_indicator_height">4dp</dimen>
<dimen name="taskbar_running_app_indicator_width">14dp</dimen>
<dimen name="taskbar_running_app_indicator_top_margin">2dp</dimen>
+ <dimen name="taskbar_minimized_app_indicator_height">2dp</dimen>
+ <dimen name="taskbar_minimized_app_indicator_width">12dp</dimen>
+ <dimen name="taskbar_minimized_app_indicator_top_margin">2dp</dimen>
<!-- Transient taskbar -->
<dimen name="transient_taskbar_padding">12dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt
index 3649c4e..d4bef28 100644
--- a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt
@@ -47,6 +47,7 @@
private var apps: Array<AppInfo>? = null
private var allRunningDesktopAppInfos: List<AppInfo>? = null
+ private var allMinimizedDesktopAppInfos: List<AppInfo>? = null
private val desktopVisibilityController: DesktopVisibilityController?
get() = desktopVisibilityControllerProvider()
@@ -95,6 +96,13 @@
return allRunningDesktopAppInfos?.mapNotNull { it.targetPackage }?.toSet() ?: emptySet()
}
+ override fun getMinimizedApps(): Set<String> {
+ if (!isInDesktopMode) {
+ return emptySet()
+ }
+ return allMinimizedDesktopAppInfos?.mapNotNull { it.targetPackage }?.toSet() ?: emptySet()
+ }
+
@VisibleForTesting
public override fun updateRunningApps() {
if (!isInDesktopMode) {
@@ -102,10 +110,34 @@
mControllers.taskbarViewController.commitRunningAppsToUI()
return
}
- allRunningDesktopAppInfos = getRunningDesktopAppInfos()
+ val runningTasks = getDesktopRunningTasks()
+ val runningAppInfo = getAppInfosFromRunningTasks(runningTasks)
+ allRunningDesktopAppInfos = runningAppInfo
+ updateMinimizedApps(runningTasks, runningAppInfo)
mControllers.taskbarViewController.commitRunningAppsToUI()
}
+ private fun updateMinimizedApps(
+ runningTasks: List<RunningTaskInfo>,
+ runningAppInfo: List<AppInfo>,
+ ) {
+ val allRunningAppTasks =
+ runningAppInfo
+ .mapNotNull { appInfo -> appInfo.targetPackage?.let { appInfo to it } }
+ .associate { (appInfo, targetPackage) ->
+ appInfo to
+ runningTasks
+ .filter { it.realActivity?.packageName == targetPackage }
+ .map { it.taskId }
+ }
+ val minimizedTaskIds = runningTasks.associate { it.taskId to !it.isVisible }
+ allMinimizedDesktopAppInfos =
+ allRunningAppTasks
+ .filterValues { taskIds -> taskIds.all { minimizedTaskIds[it] ?: false } }
+ .keys
+ .toList()
+ }
+
private fun getRunningDesktopAppInfosExceptHotseatApps(
allRunningDesktopAppInfos: List<AppInfo>,
hotseatItems: List<ItemInfo>
@@ -116,15 +148,10 @@
.map { WorkspaceItemInfo(it) }
}
- private fun getRunningDesktopAppInfos(): List<AppInfo> {
- return getAppInfosFromRunningTasks(
- recentsModel.runningTasks
- .filter { taskInfo: RunningTaskInfo ->
- taskInfo.windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM
- }
- .toList()
- )
- }
+ private fun getDesktopRunningTasks(): List<RunningTaskInfo> =
+ recentsModel.runningTasks.filter { taskInfo: RunningTaskInfo ->
+ taskInfo.windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM
+ }
// TODO(b/335398876) fetch app icons from Tasks instead of AppInfos
private fun getAppInfosFromRunningTasks(tasks: List<RunningTaskInfo>): List<AppInfo> {
@@ -138,9 +165,10 @@
.filterNotNull()
}
- private fun <E> SparseArray<E>.toList(): List<E> {
- return valueIterator().asSequence().toList()
- }
+ private fun getAppInfosFromRunningTask(task: RunningTaskInfo): AppInfo? =
+ apps?.firstOrNull { it.targetPackage == task.realActivity?.packageName }
+
+ private fun <E> SparseArray<E>.toList(): List<E> = valueIterator().asSequence().toList()
companion object {
private const val TAG = "TabletDesktopTaskbarRunningAppsController"
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
index b213203..358d703 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
@@ -148,7 +148,7 @@
});
}
- private void processLoadedTasks(ArrayList<GroupTask> tasks) {
+ private void processLoadedTasks(List<GroupTask> tasks) {
// Only store MAX_TASK tasks, from most to least recent
Collections.reverse(tasks);
mTasks = tasks.stream()
@@ -157,7 +157,7 @@
mNumHiddenTasks = Math.max(0, tasks.size() - MAX_TASKS);
}
- private void processLoadedTasksOnDesktop(ArrayList<GroupTask> tasks) {
+ private void processLoadedTasksOnDesktop(List<GroupTask> tasks) {
// Find the single desktop task that contains a grouping of desktop tasks
DesktopTask desktopTask = findDesktopTask(tasks);
@@ -173,7 +173,7 @@
}
@Nullable
- private DesktopTask findDesktopTask(ArrayList<GroupTask> tasks) {
+ private DesktopTask findDesktopTask(List<GroupTask> tasks) {
return (DesktopTask) tasks.stream()
.filter(t -> t instanceof DesktopTask)
.findFirst()
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index 8d4c34d..252f2a8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -118,7 +118,7 @@
mControllers = controllers;
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
Resources resources = mActivity.getResources();
- if (mActivity.isPhoneGestureNavMode()) {
+ if (mActivity.isPhoneGestureNavMode() || mActivity.isTinyTaskbar()) {
mTaskbarSize = resources.getDimensionPixelSize(R.dimen.taskbar_phone_size);
mStashedHandleWidth =
resources.getDimensionPixelSize(R.dimen.taskbar_stashed_small_screen);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 1571ac0..0de0550 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -43,6 +43,7 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
import static com.android.window.flags.Flags.enableDesktopWindowingMode;
import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
+import static com.android.wm.shell.Flags.enableTinyTaskbar;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
@@ -416,7 +417,9 @@
* single window for taskbar and navbar.
*/
public boolean isPhoneMode() {
- return ENABLE_TASKBAR_NAVBAR_UNIFICATION && mDeviceProfile.isPhone;
+ return ENABLE_TASKBAR_NAVBAR_UNIFICATION
+ && mDeviceProfile.isPhone
+ && !mDeviceProfile.isTaskbarPresent;
}
/**
@@ -433,6 +436,11 @@
return isPhoneMode() && !isThreeButtonNav();
}
+ /** Returns {@code true} iff a tiny version of taskbar is shown on phone. */
+ public boolean isTinyTaskbar() {
+ return enableTinyTaskbar() && mDeviceProfile.isPhone && mDeviceProfile.isTaskbarPresent;
+ }
+
/**
* Returns if software keyboard is docked or input toolbar is placed at the taskbar area
*/
@@ -981,7 +989,7 @@
public int getDefaultTaskbarWindowSize() {
Resources resources = getResources();
- if (ENABLE_TASKBAR_NAVBAR_UNIFICATION && mDeviceProfile.isPhone) {
+ if (isPhoneMode()) {
return isThreeButtonNav() ?
resources.getDimensionPixelSize(R.dimen.taskbar_phone_size) :
resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index e290c3f..bafd059 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -97,8 +97,11 @@
fun updateStashedHandleWidth(context: TaskbarActivityContext, res: Resources) {
stashedHandleWidth =
res.getDimensionPixelSize(
- if (context.isPhoneMode) R.dimen.taskbar_stashed_small_screen
- else R.dimen.taskbar_stashed_handle_width
+ if (context.isPhoneMode || context.isTinyTaskbar) {
+ R.dimen.taskbar_stashed_small_screen
+ } else {
+ R.dimen.taskbar_stashed_handle_width
+ }
)
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
index d43055d..5cbd5c9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
@@ -81,7 +81,11 @@
protected val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context)
open val shouldShowSearchEdu = false
private val isTooltipEnabled: Boolean
- get() = !Utilities.isRunningInTestHarness() && !activityContext.isPhoneMode
+ get() {
+ return !Utilities.isRunningInTestHarness() &&
+ !activityContext.isPhoneMode &&
+ !activityContext.isTinyTaskbar
+ }
private val isOpen: Boolean
get() = tooltip?.isOpen ?: false
val isBeforeTooltipFeaturesStep: Boolean
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 4a8ed87..96f4a5f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -51,6 +51,7 @@
import com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION
import com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate
import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
+import com.android.launcher3.testing.shared.ResourceUtils
import com.android.launcher3.util.DisplayController
import java.io.PrintWriter
import kotlin.jvm.optionals.getOrNull
@@ -231,8 +232,24 @@
val contentHeight = controllers.taskbarStashController.contentHeightToReportToApps
val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps
val res = context.resources
- if (provider.type == navigationBars() || provider.type == mandatorySystemGestures()) {
+ if (provider.type == navigationBars()) {
provider.insetsSize = getInsetsForGravityWithCutout(contentHeight, gravity, endRotation)
+ } else if (provider.type == mandatorySystemGestures()) {
+ if (context.isThreeButtonNav) {
+ // Leave null to inset by the window frame
+ } else {
+ val gestureHeight =
+ ResourceUtils.getNavbarSize(
+ ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE,
+ context.resources)
+ val isPinnedTaskbar = context.deviceProfile.isTaskbarPresent
+ && !context.deviceProfile.isTransientTaskbar
+ val mandatoryGestureHeight =
+ if (isPinnedTaskbar) contentHeight
+ else gestureHeight
+ provider.insetsSize = getInsetsForGravityWithCutout(mandatoryGestureHeight, gravity,
+ endRotation)
+ }
} else if (provider.type == tappableElement()) {
provider.insetsSize = getInsetsForGravity(tappableHeight, gravity)
} else if (provider.type == systemGestures() && provider.index == INDEX_LEFT) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index e8dc177..ec2cee2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -519,7 +519,7 @@
}
}
- private static boolean isTaskbarEnabled(DeviceProfile deviceProfile) {
+ private boolean isTaskbarEnabled(DeviceProfile deviceProfile) {
return ENABLE_TASKBAR_NAVBAR_UNIFICATION || deviceProfile.isTaskbarPresent;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 9f24d38..35e1c7b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -68,7 +68,7 @@
// Used to defer any UI updates during the SUW unstash animation.
private boolean mDeferUpdatesForSUW;
private Runnable mDeferredUpdates;
- private DesktopVisibilityController.DesktopVisibilityListener mDesktopVisibilityListener =
+ private final DesktopVisibilityController.DesktopVisibilityListener mDesktopVisibilityListener =
visible -> updateRunningApps();
public TaskbarModelCallbacks(
@@ -235,20 +235,23 @@
hotseatItemInfos = mControllers.taskbarRecentAppsController
.updateHotseatItemInfos(hotseatItemInfos);
Set<String> runningPackages = mControllers.taskbarRecentAppsController.getRunningApps();
+ Set<String> minimizedPackages = mControllers.taskbarRecentAppsController.getMinimizedApps();
if (mDeferUpdatesForSUW) {
ItemInfo[] finalHotseatItemInfos = hotseatItemInfos;
mDeferredUpdates = () ->
- commitHotseatItemUpdates(finalHotseatItemInfos, runningPackages);
+ commitHotseatItemUpdates(finalHotseatItemInfos, runningPackages,
+ minimizedPackages);
} else {
- commitHotseatItemUpdates(hotseatItemInfos, runningPackages);
+ commitHotseatItemUpdates(hotseatItemInfos, runningPackages, minimizedPackages);
}
}
- private void commitHotseatItemUpdates(
- ItemInfo[] hotseatItemInfos, Set<String> runningPackages) {
+ private void commitHotseatItemUpdates(ItemInfo[] hotseatItemInfos, Set<String> runningPackages,
+ Set<String> minimizedPackages) {
mContainer.updateHotseatItems(hotseatItemInfos);
- mControllers.taskbarViewController.updateIconViewsRunningStates(runningPackages);
+ mControllers.taskbarViewController.updateIconViewsRunningStates(runningPackages,
+ minimizedPackages);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java
index a29c74b..606ba5b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java
@@ -69,4 +69,9 @@
public Set<String> getRunningApps() {
return emptySet();
}
+
+ /** Returns the set of apps whose tasks are all minimized. */
+ public Set<String> getMinimizedApps() {
+ return emptySet();
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index e4ccc58..570221c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -25,7 +25,6 @@
import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.quickstep.RecentsAnimationDeviceState.QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON;
import android.content.Context;
import android.content.res.Resources;
@@ -33,7 +32,6 @@
import android.graphics.Rect;
import android.os.Bundle;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.DisplayCutout;
import android.view.InputDevice;
import android.view.LayoutInflater;
@@ -68,7 +66,6 @@
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.IconButtonView;
import com.android.quickstep.DeviceConfigWrapper;
-import com.android.quickstep.RecentsAnimationDeviceState;
import com.android.quickstep.util.AssistStateManager;
import java.util.function.Predicate;
@@ -78,8 +75,6 @@
*/
public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconParent, Insettable,
DeviceProfile.OnDeviceProfileChangeListener {
- private static final String TAG = "TaskbarView";
-
private static final Rect sTmpRect = new Rect();
private final int[] mTempOutLocation = new int[2];
@@ -89,10 +84,8 @@
private final int mItemPadding;
private final int mFolderLeaveBehindColor;
private final boolean mIsRtl;
- private final boolean mIsTransientTaskbar;
private final TaskbarActivityContext mActivityContext;
- private final RecentsAnimationDeviceState mDeviceState;
// Initialized in init.
private TaskbarViewCallbacks mControllerCallbacks;
@@ -107,8 +100,6 @@
private Runnable mAllAppsTouchRunnable;
private long mAllAppsButtonTouchDelayMs;
private boolean mAllAppsTouchTriggered;
- private MotionEvent mCurrentDownEvent;
- private float mTouchSlopSquared;
// Only non-null when device supports having an All Apps button.
private @Nullable IconButtonView mTaskbarDivider;
@@ -138,7 +129,7 @@
mActivityContext = ActivityContext.lookupContext(context);
mIconLayoutBounds = mActivityContext.getTransientTaskbarBounds();
Resources resources = getResources();
- mIsTransientTaskbar = DisplayController.isTransientTaskbar(mActivityContext)
+ boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivityContext)
&& !mActivityContext.isPhoneMode();
mIsRtl = Utilities.isRtl(resources);
mTransientTaskbarMinWidth = resources.getDimension(R.dimen.transient_taskbar_min_width);
@@ -172,7 +163,7 @@
mAllAppsButton = (IconButtonView) LayoutInflater.from(context)
.inflate(R.layout.taskbar_all_apps_button, this, false);
mAllAppsButton.setIconDrawable(resources.getDrawable(
- getAllAppsButton(mIsTransientTaskbar)));
+ getAllAppsButton(isTransientTaskbar)));
mAllAppsButton.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
mAllAppsButton.setForegroundTint(
mActivityContext.getColor(R.color.all_apps_button_color));
@@ -191,10 +182,6 @@
// Default long press (touch) delay = 400ms
mAllAppsButtonTouchDelayMs = ViewConfiguration.getLongPressTimeout();
- // Default touch slop
- mDeviceState = new RecentsAnimationDeviceState(mContext);
- mTouchSlopSquared = mDeviceState.getSquaredTouchSlop(
- QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON, 1);
}
@DrawableRes
@@ -299,12 +286,6 @@
&& assistStateManager.getLPNHDurationMillis().isPresent()) {
mAllAppsButtonTouchDelayMs = assistStateManager.getLPNHDurationMillis().get();
}
- if (DeviceConfigWrapper.get().getCustomLpaaThresholds()
- && assistStateManager.getLPNHCustomSlopMultiplier().isPresent()) {
- mTouchSlopSquared = mDeviceState.getSquaredTouchSlop(
- QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON,
- assistStateManager.getLPNHCustomSlopMultiplier().get());
- }
}
if (mTaskbarDivider != null && !mActivityContext.isThreeButtonNav()) {
mTaskbarDivider.setOnLongClickListener(
@@ -727,27 +708,10 @@
private boolean onAllAppsButtonTouch(View view, MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
- if (mCurrentDownEvent != null) {
- mCurrentDownEvent.recycle();
- }
- mCurrentDownEvent = MotionEvent.obtain(ev);
mAllAppsTouchTriggered = false;
MAIN_EXECUTOR.getHandler().postDelayed(
mAllAppsTouchRunnable, mAllAppsButtonTouchDelayMs);
break;
- case MotionEvent.ACTION_MOVE:
- if (!MAIN_EXECUTOR.getHandler().hasCallbacks(mAllAppsTouchRunnable)
- || mIsTransientTaskbar) {
- break;
- }
- float dx = ev.getX() - mCurrentDownEvent.getX();
- float dy = ev.getY() - mCurrentDownEvent.getY();
- double distanceSquared = (dx * dx) + (dy * dy);
- if (distanceSquared > mTouchSlopSquared) {
- Log.d(TAG, "Touch slop out");
- cancelAllAppsButtonTouch();
- }
- break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
cancelAllAppsButtonTouch();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 93814b7..23495ad 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -510,14 +510,30 @@
}
/** Updates which icons are marked as running given the Set of currently running packages. */
- public void updateIconViewsRunningStates(Set<String> runningPackages) {
+ public void updateIconViewsRunningStates(Set<String> runningPackages,
+ Set<String> minimizedPackages) {
for (View iconView : getIconViews()) {
if (iconView instanceof BubbleTextView btv) {
- btv.updateRunningState(runningPackages.contains(btv.getTargetPackageName()));
+ btv.updateRunningState(
+ getRunningAppState(btv.getTargetPackageName(), runningPackages,
+ minimizedPackages));
}
}
}
+ private BubbleTextView.RunningAppState getRunningAppState(
+ String packageName,
+ Set<String> runningPackages,
+ Set<String> minimizedPackages) {
+ if (minimizedPackages.contains(packageName)) {
+ return BubbleTextView.RunningAppState.MINIMIZED;
+ }
+ if (runningPackages.contains(packageName)) {
+ return BubbleTextView.RunningAppState.RUNNING;
+ }
+ return BubbleTextView.RunningAppState.NOT_RUNNING;
+ }
+
/**
* Defers any updates to the UI for the setup wizard animation.
*/
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index 8e05686..90ac872 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -17,6 +17,8 @@
import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.launcher3.Flags.enablePredictiveBackGesture;
+import static com.android.launcher3.touch.AllAppsSwipeController.ALL_APPS_FADE_MANUAL;
+import static com.android.launcher3.touch.AllAppsSwipeController.SCRIM_FADE_MANUAL;
import android.animation.Animator;
import android.content.Context;
@@ -32,6 +34,7 @@
import androidx.annotation.Nullable;
+import com.android.app.animation.Interpolators;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
@@ -40,6 +43,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.taskbar.allapps.TaskbarAllAppsViewController.TaskbarAllAppsCallbacks;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
+import com.android.launcher3.util.Themes;
import com.android.launcher3.views.AbstractSlideInView;
/** Wrapper for taskbar all apps with slide-in behavior. */
@@ -113,8 +117,25 @@
@Override
protected void onOpenCloseAnimationPending(PendingAnimation animation) {
- mAllAppsCallbacks.onAllAppsAnimationPending(
- animation, mToTranslationShift == TRANSLATION_SHIFT_OPENED);
+ final boolean isOpening = mToTranslationShift == TRANSLATION_SHIFT_OPENED;
+
+ if (mActivityContext.getDeviceProfile().isPhone) {
+ final Interpolator allAppsFadeInterpolator =
+ isOpening ? ALL_APPS_FADE_MANUAL : Interpolators.reverse(ALL_APPS_FADE_MANUAL);
+ animation.setViewAlpha(mAppsView, 1 - mToTranslationShift, allAppsFadeInterpolator);
+ }
+
+ mAllAppsCallbacks.onAllAppsAnimationPending(animation, isOpening);
+ }
+
+ @Override
+ protected Interpolator getScrimInterpolator() {
+ if (mActivityContext.getDeviceProfile().isTablet) {
+ return super.getScrimInterpolator();
+ }
+ return mToTranslationShift == TRANSLATION_SHIFT_OPENED
+ ? SCRIM_FADE_MANUAL
+ : Interpolators.reverse(SCRIM_FADE_MANUAL);
}
/** The apps container inside this view. */
@@ -154,6 +175,9 @@
protected void onFinishInflate() {
super.onFinishInflate();
mAppsView = findViewById(R.id.apps_view);
+ if (mActivityContext.getDeviceProfile().isPhone) {
+ mAppsView.setAlpha(0);
+ }
mContent = mAppsView;
// Setup header protection for search bar, if enabled.
@@ -214,7 +238,9 @@
@Override
protected int getScrimColor(Context context) {
- return context.getColor(R.color.widgets_picker_scrim);
+ return mActivityContext.getDeviceProfile().isPhone
+ ? Themes.getAttrColor(context, R.attr.allAppsScrimColor)
+ : context.getColor(R.color.widgets_picker_scrim);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index c33e4cc..e3a2bab 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -542,18 +542,16 @@
if (mDesktopVisibilityController != null) {
mDesktopVisibilityController.unregisterSystemUiListener();
}
- mDesktopVisibilityController = null;
if (mSplitSelectStateController != null) {
- removeBackAnimationCallback(mSplitSelectStateController.getSplitBackHandler());
mSplitSelectStateController.onDestroy();
}
- mSplitSelectStateController = null;
super.onDestroy();
mHotseatPredictionController.destroy();
mSplitWithKeyboardShortcutController.onDestroy();
if (mViewCapture != null) mViewCapture.close();
+ removeBackAnimationCallback(mSplitSelectStateController.getSplitBackHandler());
}
@Override
@@ -758,6 +756,9 @@
@Override
public boolean isSplitSelectionActive() {
+ if (mSplitSelectStateController == null) {
+ return false;
+ }
return mSplitSelectStateController.isSplitSelectActive();
}
@@ -1275,7 +1276,7 @@
if ((flags & CHANGE_NAVIGATION_MODE) != 0) {
getDragLayer().recreateControllers();
if (mActionsView != null) {
- mActionsView.updateVerticalMargin(info.navigationMode);
+ mActionsView.updateVerticalMargin(info.getNavigationMode());
}
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 711882c..37b4dca 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -31,6 +31,7 @@
import android.os.RemoteException;
import android.util.SparseBooleanArray;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.util.LooperExecutor;
@@ -44,6 +45,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -137,7 +139,7 @@
* @return The change id of the current task list
*/
public synchronized int getTasks(boolean loadKeysOnly,
- Consumer<ArrayList<GroupTask>> callback, Predicate<GroupTask> filter) {
+ @Nullable Consumer<List<GroupTask>> callback, Predicate<GroupTask> filter) {
final int requestLoadId = mChangeId;
if (mResultsUi.isValidForRequest(requestLoadId, loadKeysOnly)) {
// The list is up to date, send the callback on the next frame,
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 34b50ca..8bcdaa3 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -91,7 +91,7 @@
static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode";
// TODO: Move to quickstep contract
- public static final float QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON = 3f;
+ private static final float QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON = 3f;
private static final float QUICKSTEP_TOUCH_SLOP_RATIO_GESTURAL = 1.414f;
private final Context mContext;
@@ -610,16 +610,6 @@
return touchSlop * touchSlop;
}
- /**
- * Returns the squared touch slop using the given base slop multiplier {@code slopMultiplier}
- * and custom slop multiplier {@code customSlopMultiplier}.
- */
- public float getSquaredTouchSlop(float slopMultiplier, float customSlopMultiplier) {
- float systemTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
- float touchSlop = customSlopMultiplier * slopMultiplier * systemTouchSlop;
- return touchSlop * touchSlop;
- }
-
public String getSystemUiStateString() {
return QuickStepContract.getSystemUiStateString(mSystemUiStateFlags);
}
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 89351aa..98c1eb4 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -33,6 +33,7 @@
import android.os.Process;
import android.os.UserHandle;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.icons.IconProvider;
@@ -40,6 +41,7 @@
import com.android.launcher3.util.Executors.SimpleThreadFactory;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.SafeCloseable;
+import com.android.quickstep.recents.data.RecentTasksDataSource;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.TaskVisualsChangeListener;
import com.android.systemui.shared.recents.model.Task;
@@ -60,8 +62,8 @@
* Singleton class to load and manage recents model.
*/
@TargetApi(Build.VERSION_CODES.O)
-public class RecentsModel implements IconChangeListener, TaskStackChangeListener,
- TaskVisualsChangeListener, SafeCloseable {
+public class RecentsModel implements RecentTasksDataSource, IconChangeListener,
+ TaskStackChangeListener, TaskVisualsChangeListener, SafeCloseable {
// We do not need any synchronization for this variable as its only written on UI thread.
public static final MainThreadInitializedObject<RecentsModel> INSTANCE =
@@ -141,7 +143,8 @@
* always called on the UI thread.
* @return the request id associated with this call.
*/
- public int getTasks(Consumer<ArrayList<GroupTask>> callback) {
+ @Override
+ public int getTasks(@Nullable Consumer<List<GroupTask>> callback) {
return mTaskList.getTasks(false /* loadKeysOnly */, callback,
RecentsFilterState.DEFAULT_FILTER);
}
@@ -155,7 +158,7 @@
* callback.
* @return the request id associated with this call.
*/
- public int getTasks(Consumer<ArrayList<GroupTask>> callback, Predicate<GroupTask> filter) {
+ public int getTasks(@Nullable Consumer<List<GroupTask>> callback, Predicate<GroupTask> filter) {
return mTaskList.getTasks(false /* loadKeysOnly */, callback, filter);
}
diff --git a/quickstep/src/com/android/quickstep/RotationTouchHelper.java b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
index 3380291..6f1ab7d 100644
--- a/quickstep/src/com/android/quickstep/RotationTouchHelper.java
+++ b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
@@ -157,7 +157,7 @@
// Register for navigation mode changes
mDisplayController.addChangeListener(this);
DisplayController.Info info = mDisplayController.getInfo();
- onDisplayInfoChangedInternal(info, CHANGE_ALL, info.navigationMode.hasGestures);
+ onDisplayInfoChangedInternal(info, CHANGE_ALL, info.getNavigationMode().hasGestures);
runOnDestroy(() -> mDisplayController.removeChangeListener(this));
mOrientationListener = new OrientationEventListener(mContext) {
@@ -291,7 +291,7 @@
}
if ((flags & CHANGE_NAVIGATION_MODE) != 0) {
- NavigationMode newMode = info.navigationMode;
+ NavigationMode newMode = info.getNavigationMode();
mOrientationTouchTransformer.setNavigationMode(newMode, mDisplayController.getInfo(),
mContext.getResources());
diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
index 7ebb767..38e927f 100644
--- a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
+++ b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
@@ -21,11 +21,13 @@
import android.content.Context;
import android.content.res.Resources;
+import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.R;
import com.android.launcher3.util.CancellableTask;
import com.android.launcher3.util.Preconditions;
+import com.android.quickstep.task.thumbnail.data.TaskThumbnailDataSource;
import com.android.quickstep.util.TaskKeyByLastActiveTimeCache;
import com.android.quickstep.util.TaskKeyCache;
import com.android.quickstep.util.TaskKeyLruCache;
@@ -38,7 +40,7 @@
import java.util.concurrent.Executor;
import java.util.function.Consumer;
-public class TaskThumbnailCache {
+public class TaskThumbnailCache implements TaskThumbnailDataSource {
private final Executor mBgExecutor;
private final TaskKeyCache<ThumbnailData> mCache;
@@ -148,8 +150,9 @@
* @param callback The callback to receive the task after its data has been populated.
* @return A cancelable handle to the request
*/
+ @Override
public CancellableTask<ThumbnailData> updateThumbnailInBackground(
- Task task, Consumer<ThumbnailData> callback) {
+ Task task, @NonNull Consumer<ThumbnailData> callback) {
Preconditions.assertUIThread();
boolean lowResolution = !mHighResLoadingState.isEnabled();
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 4599f18..b153396 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -68,11 +68,13 @@
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Region;
+import android.hardware.input.InputManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.os.SystemClock;
import android.os.Trace;
+import android.util.ArraySet;
import android.util.Log;
import android.view.Choreographer;
import android.view.InputDevice;
@@ -146,6 +148,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
+import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -453,6 +456,47 @@
}
}
+ private final InputManager.InputDeviceListener mInputDeviceListener =
+ new InputManager.InputDeviceListener() {
+ @Override
+ public void onInputDeviceAdded(int deviceId) {
+ if (isTrackpadDevice(deviceId)) {
+ boolean wasEmpty = mTrackpadsConnected.isEmpty();
+ mTrackpadsConnected.add(deviceId);
+ if (wasEmpty) {
+ update();
+ }
+ }
+ }
+
+ @Override
+ public void onInputDeviceChanged(int deviceId) {
+ }
+
+ @Override
+ public void onInputDeviceRemoved(int deviceId) {
+ mTrackpadsConnected.remove(deviceId);
+ if (mTrackpadsConnected.isEmpty()) {
+ update();
+ }
+ }
+
+ private void update() {
+ if (mInputMonitorCompat != null && !mTrackpadsConnected.isEmpty()) {
+ // Don't destroy and reinitialize input monitor due to trackpad
+ // connecting when it's already set up.
+ return;
+ }
+ initInputMonitor("onTrackpadConnected()");
+ }
+
+ private boolean isTrackpadDevice(int deviceId) {
+ InputDevice inputDevice = mInputManager.getInputDevice(deviceId);
+ return inputDevice.getSources() == (InputDevice.SOURCE_MOUSE
+ | InputDevice.SOURCE_TOUCHPAD);
+ }
+ };
+
private static boolean sConnected = false;
private static boolean sIsInitialized = false;
private RotationTouchHelper mRotationTouchHelper;
@@ -503,6 +547,8 @@
private TaskbarManager mTaskbarManager;
private Function<GestureState, AnimatedFloat> mSwipeUpProxyProvider = i -> null;
private AllAppsActionManager mAllAppsActionManager;
+ private InputManager mInputManager;
+ private final Set<Integer> mTrackpadsConnected = new ArraySet<>();
@Override
public void onCreate() {
@@ -514,6 +560,15 @@
mDeviceState = new RecentsAnimationDeviceState(this, true);
mAllAppsActionManager = new AllAppsActionManager(
this, UI_HELPER_EXECUTOR, this::createAllAppsPendingIntent);
+ mInputManager = getSystemService(InputManager.class);
+ if (ENABLE_TRACKPAD_GESTURE.get()) {
+ mInputManager.registerInputDeviceListener(mInputDeviceListener,
+ UI_HELPER_EXECUTOR.getHandler());
+ int [] inputDevices = mInputManager.getInputDeviceIds();
+ for (int inputDeviceId : inputDevices) {
+ mInputDeviceListener.onInputDeviceAdded(inputDeviceId);
+ }
+ }
mTaskbarManager = new TaskbarManager(this, mAllAppsActionManager, mNavCallbacks);
mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
@@ -542,7 +597,8 @@
private void initInputMonitor(String reason) {
disposeEventHandlers("Initializing input monitor due to: " + reason);
- if (mDeviceState.isButtonNavMode() && !ENABLE_TRACKPAD_GESTURE.get()) {
+ if (mDeviceState.isButtonNavMode() && (!ENABLE_TRACKPAD_GESTURE.get()
+ || mTrackpadsConnected.isEmpty())) {
return;
}
@@ -678,6 +734,9 @@
mAllAppsActionManager.onDestroy();
+ mInputManager.unregisterInputDeviceListener(mInputDeviceListener);
+ mTrackpadsConnected.clear();
+
mTaskbarManager.destroy();
sConnected = false;
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 096ed2c..485d6c4 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -54,6 +54,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsState>
implements StateListener<RecentsState> {
@@ -179,7 +180,7 @@
}
@Override
- protected void applyLoadPlan(ArrayList<GroupTask> taskGroups) {
+ protected void applyLoadPlan(List<GroupTask> taskGroups) {
// When quick-switching on 3p-launcher, we add a "stub" tile corresponding to Launcher
// as well. This tile is never shown as we have setCurrentTaskHidden, but allows use to
// track the index of the next task appropriately, as if we are switching on any other app.
diff --git a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
index f8d695c..5ac04da 100644
--- a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
+++ b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
@@ -148,7 +148,7 @@
@Override
public void onDisplayInfoChanged(Context context, Info info, int flags) {
if ((flags & CHANGE_NAVIGATION_MODE) != 0) {
- mNavMode = info.navigationMode;
+ mNavMode = info.getNavigationMode();
mStatsLogManager.logger().log(mNavMode.launcherEvent);
}
}
diff --git a/quickstep/src/com/android/quickstep/recents/data/RecentTasksDataSource.kt b/quickstep/src/com/android/quickstep/recents/data/RecentTasksDataSource.kt
new file mode 100644
index 0000000..6719099
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/recents/data/RecentTasksDataSource.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.recents.data
+
+import com.android.quickstep.util.GroupTask
+import java.util.function.Consumer
+
+interface RecentTasksDataSource {
+ fun getTasks(callback: Consumer<List<GroupTask>>?): Int
+}
diff --git a/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
new file mode 100644
index 0000000..c1eef0b
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.recents.data
+
+import com.android.systemui.shared.recents.model.Task
+import kotlinx.coroutines.flow.Flow
+
+interface RecentTasksRepository {
+ /** Gets all the recent tasks, refreshing from data sources if [forceRefresh] is true. */
+ fun getAllTaskData(forceRefresh: Boolean = false): Flow<List<Task>>
+
+ /**
+ * Gets the data associated with a task that has id [taskId]. Flow will settle on null if the
+ * task was not found.
+ */
+ fun getTaskDataById(taskId: Int): Flow<Task?>
+
+ /**
+ * Sets the tasks that are visible, indicating that properties relating to visuals need to be
+ * populated e.g. icons/thumbnails etc.
+ */
+ fun setVisibleTasks(visibleTaskIdList: List<Int>)
+}
diff --git a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
new file mode 100644
index 0000000..b21a1b4
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
@@ -0,0 +1,114 @@
+/*
+ * 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.recents.data
+
+import com.android.quickstep.TaskIconCache
+import com.android.quickstep.task.thumbnail.data.TaskThumbnailDataSource
+import com.android.quickstep.util.GroupTask
+import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.ThumbnailData
+import kotlin.coroutines.resume
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.suspendCancellableCoroutine
+
+@OptIn(ExperimentalCoroutinesApi::class)
+class TasksRepository(
+ private val recentsModel: RecentTasksDataSource,
+ private val taskThumbnailDataSource: TaskThumbnailDataSource,
+ private val taskIconCache: TaskIconCache,
+) : RecentTasksRepository {
+ private val groupedTaskData = MutableStateFlow(emptyList<GroupTask>())
+ private val _taskData =
+ groupedTaskData.map { groupTaskList -> groupTaskList.flatMap { it.tasks } }
+ private val visibleTaskIds = MutableStateFlow(emptySet<Int>())
+
+ private val taskData: Flow<List<Task>> =
+ combine(_taskData, getThumbnailQueryResults()) { tasks, results ->
+ tasks.forEach { task ->
+ // Add retrieved thumbnails + remove unnecessary thumbnails
+ task.thumbnail = results[task.key.id]
+ }
+ tasks
+ }
+
+ override fun getAllTaskData(forceRefresh: Boolean): Flow<List<Task>> {
+ if (forceRefresh) {
+ recentsModel.getTasks { groupedTaskData.value = it }
+ }
+ return taskData
+ }
+
+ override fun getTaskDataById(taskId: Int): Flow<Task?> =
+ taskData.map { taskList -> taskList.firstOrNull { it.key.id == taskId } }
+
+ override fun setVisibleTasks(visibleTaskIdList: List<Int>) {
+ this.visibleTaskIds.value = visibleTaskIdList.toSet()
+ }
+
+ /** Flow wrapper for [TaskThumbnailDataSource.updateThumbnailInBackground] api */
+ private fun getThumbnailDataRequest(task: Task): ThumbnailDataRequest =
+ flow {
+ emit(task.key.id to task.thumbnail)
+ val thumbnailDataResult: ThumbnailData? =
+ suspendCancellableCoroutine { continuation ->
+ val cancellableTask =
+ taskThumbnailDataSource.updateThumbnailInBackground(task) {
+ continuation.resume(it)
+ }
+ continuation.invokeOnCancellation { cancellableTask?.cancel() }
+ }
+ emit(task.key.id to thumbnailDataResult)
+ }
+ .distinctUntilChanged()
+
+ /**
+ * This is a Flow that makes a query for thumbnail data to the [taskThumbnailDataSource] for
+ * each visible task. It then collects the responses and returns them in a Map as soon as they
+ * are available.
+ */
+ private fun getThumbnailQueryResults(): Flow<Map<Int, ThumbnailData?>> {
+ val visibleTasks =
+ combine(_taskData, visibleTaskIds) { tasks, visibleIds ->
+ tasks.filter { it.key.id in visibleIds }
+ }
+ val visibleThumbnailDataRequests: Flow<List<ThumbnailDataRequest>> =
+ visibleTasks.map {
+ it.map { visibleTask ->
+ val taskCopy = Task(visibleTask).apply { thumbnail = visibleTask.thumbnail }
+ getThumbnailDataRequest(taskCopy)
+ }
+ }
+ return visibleThumbnailDataRequests.flatMapLatest {
+ thumbnailRequestFlows: List<ThumbnailDataRequest> ->
+ if (thumbnailRequestFlows.isEmpty()) {
+ flowOf(emptyMap())
+ } else {
+ combine(thumbnailRequestFlows) { it.toMap() }
+ }
+ }
+ }
+}
+
+typealias ThumbnailDataRequest = Flow<Pair<Int, ThumbnailData?>>
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
index 0843ae3..40f9b28 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
@@ -16,11 +16,19 @@
package com.android.quickstep.task.thumbnail
-import com.android.systemui.shared.recents.model.Task
+import android.graphics.Bitmap
+import android.graphics.Rect
+import androidx.annotation.ColorInt
sealed class TaskThumbnailUiState {
data object Uninitialized : TaskThumbnailUiState()
data object LiveTile : TaskThumbnailUiState()
+ data class BackgroundOnly(@ColorInt val backgroundColor: Int) : TaskThumbnailUiState()
+ data class Snapshot(
+ val bitmap: Bitmap,
+ val drawnRect: Rect,
+ @ColorInt val backgroundColor: Int
+ ) : TaskThumbnailUiState()
}
-data class TaskThumbnail(val task: Task, val isRunning: Boolean)
+data class TaskThumbnail(val taskId: Int, val isRunning: Boolean)
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
index 8762976..2836c89 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
@@ -19,15 +19,20 @@
import android.content.Context
import android.content.res.Configuration
import android.graphics.Canvas
+import android.graphics.Color
import android.graphics.Outline
import android.graphics.Paint
import android.graphics.PorterDuff
import android.graphics.PorterDuffXfermode
+import android.graphics.Rect
import android.util.AttributeSet
import android.view.View
import android.view.ViewOutlineProvider
+import androidx.annotation.ColorInt
import com.android.launcher3.Utilities
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.BackgroundOnly
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Snapshot
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
import com.android.quickstep.util.TaskCornerRadius
import com.android.quickstep.views.RecentsView
@@ -42,17 +47,26 @@
// to [TaskView], and also shared between [TaskView] and [TaskThumbnailView]
// This is using a lazy for now because the dependencies cannot be obtained without DI.
val viewModel by lazy {
- TaskThumbnailViewModel(
+ val recentsView =
RecentsViewContainer.containerFromContext<RecentsViewContainer>(context)
.getOverviewPanel<RecentsView<*, *>>()
- .mRecentsViewData,
- (parent as TaskView).taskViewData
+ TaskThumbnailViewModel(
+ recentsView.mRecentsViewData,
+ (parent as TaskView).taskViewData,
+ recentsView.mTasksRepository,
)
}
private var uiState: TaskThumbnailUiState = Uninitialized
private var inheritedScale: Float = 1f
+ private val backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG)
+ private val _measuredBounds = Rect()
+ private val measuredBounds: Rect
+ get() {
+ _measuredBounds.set(0, 0, measuredWidth, measuredHeight)
+ return _measuredBounds
+ }
private var cornerRadius: Float = TaskCornerRadius.get(context)
private var fullscreenCornerRadius: Float = QuickStepContract.getWindowCornerRadius(context)
@@ -85,24 +99,25 @@
outlineProvider =
object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
- outline.setRoundRect(
- 0,
- 0,
- view.measuredWidth,
- view.measuredHeight,
- getCurrentCornerRadius()
- )
+ outline.setRoundRect(measuredBounds, getCurrentCornerRadius())
}
}
}
override fun onDraw(canvas: Canvas) {
- when (uiState) {
- is Uninitialized -> {}
+ when (val uiStateVal = uiState) {
+ is Uninitialized -> drawBackgroundOnly(canvas, Color.BLACK)
is LiveTile -> drawTransparentUiState(canvas)
+ is Snapshot -> drawSnapshotState(canvas, uiStateVal)
+ is BackgroundOnly -> drawBackgroundOnly(canvas, uiStateVal.backgroundColor)
}
}
+ private fun drawBackgroundOnly(canvas: Canvas, @ColorInt backgroundColor: Int) {
+ backgroundPaint.color = backgroundColor
+ canvas.drawRect(measuredBounds, backgroundPaint)
+ }
+
override fun onConfigurationChanged(newConfig: Configuration?) {
super.onConfigurationChanged(newConfig)
@@ -112,7 +127,12 @@
}
private fun drawTransparentUiState(canvas: Canvas) {
- canvas.drawRect(0f, 0f, measuredWidth.toFloat(), measuredHeight.toFloat(), CLEAR_PAINT)
+ canvas.drawRect(measuredBounds, CLEAR_PAINT)
+ }
+
+ private fun drawSnapshotState(canvas: Canvas, snapshot: Snapshot) {
+ drawBackgroundOnly(canvas, snapshot.backgroundColor)
+ canvas.drawBitmap(snapshot.bitmap, snapshot.drawnRect, measuredBounds, null)
}
private fun getCurrentCornerRadius() =
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModel.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModel.kt
index 71bc865..4511ea7 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModel.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModel.kt
@@ -16,32 +16,76 @@
package com.android.quickstep.task.thumbnail
+import android.annotation.ColorInt
+import android.graphics.Rect
+import androidx.core.graphics.ColorUtils
+import com.android.quickstep.recents.data.RecentTasksRepository
import com.android.quickstep.recents.viewmodel.RecentsViewData
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.BackgroundOnly
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Snapshot
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
import com.android.quickstep.task.viewmodel.TaskViewData
+import com.android.systemui.shared.recents.model.Task
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
-class TaskThumbnailViewModel(recentsViewData: RecentsViewData, taskViewData: TaskViewData) {
- private val task = MutableStateFlow<TaskThumbnail?>(null)
+@OptIn(ExperimentalCoroutinesApi::class)
+class TaskThumbnailViewModel(
+ recentsViewData: RecentsViewData,
+ taskViewData: TaskViewData,
+ private val tasksRepository: RecentTasksRepository,
+) {
+ private val task = MutableStateFlow<Flow<Task?>>(flowOf(null))
+ private var boundTaskIsRunning = false
val recentsFullscreenProgress = recentsViewData.fullscreenProgress
val inheritedScale =
combine(recentsViewData.scale, taskViewData.scale) { recentsScale, taskScale ->
recentsScale * taskScale
}
- val uiState =
- task.map { taskVal ->
- when {
- taskVal == null -> Uninitialized
- taskVal.isRunning -> LiveTile
- else -> Uninitialized
+ val uiState: Flow<TaskThumbnailUiState> =
+ task
+ .flatMapLatest { taskFlow ->
+ taskFlow.map { taskVal ->
+ when {
+ taskVal == null -> Uninitialized
+ boundTaskIsRunning -> LiveTile
+ isBackgroundOnly(taskVal) ->
+ BackgroundOnly(taskVal.colorBackground.removeAlpha())
+ isSnapshotState(taskVal) -> {
+ val bitmap = taskVal.thumbnail?.thumbnail!!
+ Snapshot(
+ bitmap,
+ Rect(0, 0, bitmap.width, bitmap.height),
+ taskVal.colorBackground.removeAlpha()
+ )
+ }
+ else -> Uninitialized
+ }
+ }
}
- }
+ .distinctUntilChanged()
- fun bind(task: TaskThumbnail) {
- this.task.value = task
+ fun bind(taskThumbnail: TaskThumbnail) {
+ boundTaskIsRunning = taskThumbnail.isRunning
+ task.value = tasksRepository.getTaskDataById(taskThumbnail.taskId)
}
+
+ private fun isBackgroundOnly(task: Task): Boolean = task.isLocked || task.thumbnail == null
+
+ private fun isSnapshotState(task: Task): Boolean {
+ val thumbnailPresent = task.thumbnail?.thumbnail != null
+ val taskLocked = task.isLocked
+
+ return thumbnailPresent && !taskLocked
+ }
+
+ @ColorInt private fun Int.removeAlpha(): Int = ColorUtils.setAlphaComponent(this, 0xff)
}
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/data/TaskThumbnailDataSource.kt b/quickstep/src/com/android/quickstep/task/thumbnail/data/TaskThumbnailDataSource.kt
new file mode 100644
index 0000000..55598f0
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/data/TaskThumbnailDataSource.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.task.thumbnail.data
+
+import com.android.launcher3.util.CancellableTask
+import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.ThumbnailData
+import java.util.function.Consumer
+
+interface TaskThumbnailDataSource {
+ fun updateThumbnailInBackground(
+ task: Task,
+ callback: Consumer<ThumbnailData>
+ ): CancellableTask<ThumbnailData>?
+}
diff --git a/quickstep/src/com/android/quickstep/util/DesktopTask.java b/quickstep/src/com/android/quickstep/util/DesktopTask.java
index 07f2d68..8d99069 100644
--- a/quickstep/src/com/android/quickstep/util/DesktopTask.java
+++ b/quickstep/src/com/android/quickstep/util/DesktopTask.java
@@ -21,7 +21,7 @@
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
-import java.util.ArrayList;
+import java.util.List;
/**
* A {@link Task} container that can contain N number of tasks that are part of the desktop in
@@ -30,9 +30,9 @@
public class DesktopTask extends GroupTask {
@NonNull
- public final ArrayList<Task> tasks;
+ public final List<Task> tasks;
- public DesktopTask(@NonNull ArrayList<Task> tasks) {
+ public DesktopTask(@NonNull List<Task> tasks) {
super(tasks.get(0), null, null, TaskView.Type.DESKTOP);
this.tasks = tasks;
}
@@ -53,6 +53,12 @@
}
@Override
+ @NonNull
+ public List<Task> getTasks() {
+ return tasks;
+ }
+
+ @Override
public DesktopTask copy() {
return new DesktopTask(tasks);
}
diff --git a/quickstep/src/com/android/quickstep/util/GroupTask.java b/quickstep/src/com/android/quickstep/util/GroupTask.java
index 7dd6afc..945ffe3 100644
--- a/quickstep/src/com/android/quickstep/util/GroupTask.java
+++ b/quickstep/src/com/android/quickstep/util/GroupTask.java
@@ -23,6 +23,10 @@
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
/**
* A {@link Task} container that can contain one or two tasks, depending on if the two tasks
* are represented as an app-pair in the recents task list.
@@ -62,6 +66,17 @@
}
/**
+ * Returns a List of all the Tasks in this GroupTask
+ */
+ public List<Task> getTasks() {
+ if (task2 == null) {
+ return Collections.singletonList(task1);
+ } else {
+ return Arrays.asList(task1, task2);
+ }
+ }
+
+ /**
* Create a copy of this instance
*/
public GroupTask copy() {
diff --git a/quickstep/src/com/android/quickstep/util/NavBarPosition.java b/quickstep/src/com/android/quickstep/util/NavBarPosition.java
deleted file mode 100644
index 9418512..0000000
--- a/quickstep/src/com/android/quickstep/util/NavBarPosition.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep.util;
-
-import static com.android.launcher3.util.NavigationMode.NO_BUTTON;
-
-import android.view.Surface;
-
-import com.android.launcher3.util.DisplayController.Info;
-import com.android.launcher3.util.NavigationMode;
-
-/**
- * Utility class to check nav bar position.
- */
-public class NavBarPosition {
-
- private final boolean mIsTablet;
- private final NavigationMode mMode;
- private final int mDisplayRotation;
-
- public NavBarPosition(NavigationMode mode, Info info) {
- mIsTablet = info.isTablet(info.realBounds);
- mMode = mode;
- mDisplayRotation = info.rotation;
- }
-
- public boolean isRightEdge() {
- return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_90 && !mIsTablet;
- }
-
- public boolean isLeftEdge() {
- return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_270 && !mIsTablet;
- }
-
- public float getRotation() {
- return isLeftEdge() ? 90 : (isRightEdge() ? -90 : 0);
- }
-}
diff --git a/quickstep/src/com/android/quickstep/util/NavBarPosition.kt b/quickstep/src/com/android/quickstep/util/NavBarPosition.kt
new file mode 100644
index 0000000..43cf540
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/NavBarPosition.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.util
+
+import android.view.Surface
+import com.android.launcher3.util.DisplayController.Info
+import com.android.launcher3.util.NavigationMode
+import com.android.launcher3.util.NavigationMode.NO_BUTTON
+
+/** Utility class to check nav bar position. */
+data class NavBarPosition(
+ val isTablet: Boolean,
+ val displayRotation: Int,
+ val mode: NavigationMode
+) {
+ constructor(
+ mode: NavigationMode,
+ info: Info
+ ) : this(info.isTablet(info.realBounds), info.rotation, mode)
+
+ val isRightEdge: Boolean
+ get() = mode != NO_BUTTON && displayRotation == Surface.ROTATION_90 && !isTablet
+ val isLeftEdge: Boolean
+ get() = mode != NO_BUTTON && displayRotation == Surface.ROTATION_270 && !isTablet
+
+ val rotation: Float
+ get() = if (isLeftEdge) 90f else if (isRightEdge) -90f else 0f
+}
diff --git a/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java b/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
index c63a58e..671b2ea 100644
--- a/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
+++ b/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
@@ -99,6 +99,7 @@
if (mDisableHorizontalSwipe
&& Math.abs(displacementX) > Math.abs(displacementY)) {
// Horizontal gesture is not allowed in this region
+ mOnSwipeUp.onSwipeUpCancelled();
endTouchTracking();
break;
}
@@ -111,6 +112,7 @@
}
case ACTION_CANCEL:
+ mOnSwipeUp.onSwipeUpCancelled();
endTouchTracking();
break;
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 83a2ceb..d729bdc 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -110,9 +110,11 @@
/** Container for the action buttons below a focused, non-split Overview tile. */
protected LinearLayout mActionButtons;
- /** Container for the action buttons below a focused, split Overview tile. */
- protected LinearLayout mGroupActionButtons;
private Button mSplitButton;
+ /**
+ * The "save app pair" button. Currently this is the only button that is not contained in
+ * mActionButtons, since it is the sole button that appears for a grouped task.
+ */
private Button mSaveAppPairButton;
@ActionsHiddenFlags
@@ -150,15 +152,16 @@
super.onFinishInflate();
// Initialize 2 view containers: one for single tasks, one for grouped tasks.
// These will take up the same space on the screen and alternate visibility as needed.
+ // Currently, the only grouped task action is "save app pairs".
mActionButtons = findViewById(R.id.action_buttons);
- mGroupActionButtons = findViewById(R.id.group_action_buttons);
- // Initialize a list to hold alphas for mActionButtons and mGroupActionButtons.
+ mSaveAppPairButton = findViewById(R.id.action_save_app_pair);
+ // Initialize a list to hold alphas for mActionButtons and any group action buttons.
mMultiValueAlphas[ACTIONS_ALPHAS] = new MultiValueAlpha(mActionButtons, NUM_ALPHAS);
mMultiValueAlphas[GROUP_ACTIONS_ALPHAS] =
- new MultiValueAlpha(mGroupActionButtons, NUM_ALPHAS);
+ new MultiValueAlpha(mSaveAppPairButton, NUM_ALPHAS);
Arrays.stream(mMultiValueAlphas).forEach(a -> a.setUpdateVisibility(true));
- // To control alpha simultaneously on mActionButtons and mGroupActionButtons, we set up an
- // AnimatedFloat for each alpha property.
+ // To control alpha simultaneously on mActionButtons and any group action buttons, we set up
+ // an AnimatedFloat for each alpha property.
for (int i = 0; i < NUM_ALPHAS; i++) {
final int index = i;
mAlphaProperties[index] = new AnimatedFloat(() -> {
@@ -175,7 +178,6 @@
screenshotButton.setOnClickListener(this);
mSplitButton = findViewById(R.id.action_split);
mSplitButton.setOnClickListener(this);
- mSaveAppPairButton = findViewById(R.id.action_save_app_pair);
mSaveAppPairButton.setOnClickListener(this);
}
@@ -336,7 +338,7 @@
*/
public boolean areActionsButtonsVisible() {
return mActionButtons.getVisibility() == View.VISIBLE
- || mGroupActionButtons.getVisibility() == View.VISIBLE;
+ || mSaveAppPairButton.getVisibility() == View.VISIBLE;
}
/**
@@ -350,11 +352,11 @@
/** Updates vertical margins for different navigation mode or configuration changes. */
public void updateVerticalMargin(NavigationMode mode) {
updateActionBarPosition(mActionButtons);
- updateActionBarPosition(mGroupActionButtons);
+ updateActionBarPosition(mSaveAppPairButton);
}
/** Positions actions buttons according to device settings and insets. */
- private void updateActionBarPosition(LinearLayout actionBar) {
+ private void updateActionBarPosition(View actionBar) {
if (mDp == null) {
return;
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 4e5d646..4804e56 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -188,6 +188,7 @@
import com.android.quickstep.TopTaskTracker;
import com.android.quickstep.ViewUtils;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
+import com.android.quickstep.recents.data.TasksRepository;
import com.android.quickstep.recents.viewmodel.RecentsViewData;
import com.android.quickstep.util.ActiveGestureErrorDetector;
import com.android.quickstep.util.ActiveGestureLog;
@@ -305,6 +306,7 @@
public static final float SCROLL_VIBRATION_PRIMITIVE_SCALE = 0.6f;
public static final VibrationEffect SCROLL_VIBRATION_FALLBACK =
VibrationConstants.EFFECT_TEXTURE_TICK;
+ public static final int UNBOUND_TASK_VIEW_ID = -1;
/**
* Can be used to tint the color of the RecentsView to simulate a scrim that can views
@@ -456,6 +458,7 @@
private static final float FOREGROUND_SCRIM_TINT = 0.32f;
public final RecentsViewData mRecentsViewData = new RecentsViewData();
+ public final TasksRepository mTasksRepository;
protected final RecentsOrientedState mOrientationState;
protected final BaseContainerInterface<STATE_TYPE, CONTAINER_TYPE> mSizeStrategy;
@@ -800,6 +803,12 @@
.getDimensionPixelSize(R.dimen.recents_fast_fling_velocity);
mModel = RecentsModel.INSTANCE.get(context);
mIdp = InvariantDeviceProfile.INSTANCE.get(context);
+ if (enableRefactorTaskThumbnail()) {
+ mTasksRepository = new TasksRepository(
+ mModel, mModel.getThumbnailCache(), mModel.getIconCache());
+ } else {
+ mTasksRepository = null;
+ }
mClearAllButton = (ClearAllButton) LayoutInflater.from(context)
.inflate(R.layout.overview_clear_all_button, this, false);
@@ -1141,6 +1150,7 @@
if (FeatureFlags.enableSplitContextually()) {
mSplitSelectStateController.unregisterSplitListener(mSplitSelectionListener);
}
+ reset();
}
@Override
@@ -1164,7 +1174,6 @@
} else {
mTaskViewPool.recycle(taskView);
}
- taskView.setTaskViewId(-1);
mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, getTaskViewCount() == 0);
}
}
@@ -1715,7 +1724,7 @@
return super.isPageScrollsInitialized() && mLoadPlanEverApplied;
}
- protected void applyLoadPlan(ArrayList<GroupTask> taskGroups) {
+ protected void applyLoadPlan(List<GroupTask> taskGroups) {
if (mPendingAnimation != null) {
mPendingAnimation.addEndListener(success -> applyLoadPlan(taskGroups));
return;
@@ -2361,6 +2370,8 @@
upper = Math.min(centerPageIndex + 2, numChildren - 1);
}
+ List<Integer> visibleTaskIds = new ArrayList<>();
+
// Update the task data for the in/visible children
for (int i = 0; i < getTaskViewCount(); i++) {
TaskView taskView = requireTaskViewAt(i);
@@ -2380,6 +2391,10 @@
List<Task> tasksToUpdate = containers.stream()
.map(TaskContainer::getTask)
.collect(Collectors.toCollection(ArrayList::new));
+ if (enableRefactorTaskThumbnail()) {
+ visibleTaskIds.addAll(
+ tasksToUpdate.stream().map((task) -> task.key.id).toList());
+ }
if (mTmpRunningTasks != null) {
for (Task t : mTmpRunningTasks) {
// Skip loading if this is the task that we are animating into
@@ -2415,6 +2430,9 @@
}
}
}
+ if (enableRefactorTaskThumbnail()) {
+ mTasksRepository.setVisibleTasks(visibleTaskIds);
+ }
}
/**
@@ -2601,6 +2619,9 @@
if (!mModel.isTaskListValid(mTaskListChangeId)) {
mTaskListChangeId = mModel.getTasks(this::applyLoadPlan, RecentsFilterState
.getFilter(mFilterState.getPackageNameToFilter()));
+ if (enableRefactorTaskThumbnail()) {
+ mTasksRepository.getAllTaskData(/* forceRefresh = */ true);
+ }
}
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 1490fd0..4045ad7 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -93,6 +93,7 @@
import com.android.quickstep.util.RecentsOrientedState
import com.android.quickstep.util.TaskCornerRadius
import com.android.quickstep.util.TaskRemovedDuringLaunchListener
+import com.android.quickstep.views.RecentsView.UNBOUND_TASK_VIEW_ID
import com.android.systemui.shared.recents.model.Task
import com.android.systemui.shared.recents.model.ThumbnailData
import com.android.systemui.shared.system.ActivityManagerWrapper
@@ -235,7 +236,7 @@
protected set
lateinit var orientedState: RecentsOrientedState
- var taskViewId = -1
+ var taskViewId = UNBOUND_TASK_VIEW_ID
var isEndQuickSwitchCuj = false
// Various animation progress variables.
@@ -257,6 +258,9 @@
*/
protected var modalness = 0f
set(value) {
+ if (field == value) {
+ return
+ }
field = value
onModalnessUpdated(field)
}
@@ -499,7 +503,6 @@
resetPersistentViewTransforms()
// Clear any references to the thumbnail (it will be re-read either from the cache or the
// system on next bind)
- // TODO(b/334825222): Implement thumbnail/snapshot for the new [TaskThumbnailView].
if (enableRefactorTaskThumbnail()) {
notifyIsRunningTaskUpdated()
} else {
@@ -508,6 +511,7 @@
setOverlayEnabled(false)
onTaskListVisibilityChanged(false)
borderEnabled = false
+ taskViewId = UNBOUND_TASK_VIEW_ID
}
// TODO: Clip-out the icon region from the thumbnail, since they are overlapping.
@@ -777,22 +781,19 @@
val recentsModel = RecentsModel.INSTANCE.get(context)
// These calls are no-ops if the data is already loaded, try and load the high
// resolution thumbnail if the state permits
- if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
- if (!enableRefactorTaskThumbnail()) {
- // TODO(b/334825222) add thumbnail state
- taskContainers.forEach {
- if (visible) {
- recentsModel.thumbnailCache
- .updateThumbnailInBackground(it.task) { thumbnailData ->
- it.thumbnailViewDeprecated.setThumbnail(it.task, thumbnailData)
- }
- ?.also { request -> pendingThumbnailLoadRequests.add(request) }
- } else {
- it.thumbnailViewDeprecated.setThumbnail(null, null)
- // Reset the task thumbnail reference as well (it will be fetched from the
- // cache or reloaded next time we need it)
- it.task.thumbnail = null
- }
+ if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL) && !enableRefactorTaskThumbnail()) {
+ taskContainers.forEach {
+ if (visible) {
+ recentsModel.thumbnailCache
+ .updateThumbnailInBackground(it.task) { thumbnailData ->
+ it.thumbnailViewDeprecated.setThumbnail(it.task, thumbnailData)
+ }
+ ?.also { request -> pendingThumbnailLoadRequests.add(request) }
+ } else {
+ it.thumbnailViewDeprecated.setThumbnail(null, null)
+ // Reset the task thumbnail reference as well (it will be fetched from the
+ // cache or reloaded next time we need it)
+ it.task.thumbnail = null
}
}
}
@@ -858,7 +859,7 @@
open fun refreshThumbnails(thumbnailDatas: HashMap<Int, ThumbnailData?>?) {
if (enableRefactorTaskThumbnail()) {
- // TODO(b/334825222) add thumbnail logic
+ // TODO(b/342560598) add thumbnail logic
return
}
@@ -1588,7 +1589,9 @@
// TODO(b/335649589): TaskView's VM will already have access to TaskThumbnailView's VM
// so there will be no need to access TaskThumbnailView's VM through the TaskThumbnailView
fun bindThumbnailView() {
- thumbnailView?.viewModel?.bind(TaskThumbnail(task, isRunningTask))
+ // TODO(b/343364498): Existing view has shouldShowScreenshot as an override as well but
+ // this should be decided inside TaskThumbnailViewModel.
+ thumbnailView?.viewModel?.bind(TaskThumbnail(task.key.id, isRunningTask))
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentTasksDataSource.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentTasksDataSource.kt
new file mode 100644
index 0000000..eaeb513
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentTasksDataSource.kt
@@ -0,0 +1,33 @@
+/*
+ * 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.recents.data
+
+import com.android.quickstep.util.GroupTask
+import java.util.function.Consumer
+
+class FakeRecentTasksDataSource : RecentTasksDataSource {
+ var taskList: List<GroupTask> = listOf()
+
+ override fun getTasks(callback: Consumer<List<GroupTask>>?): Int {
+ callback?.accept(taskList)
+ return 0
+ }
+
+ fun seedTasks(tasks: List<GroupTask>) {
+ taskList = tasks
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt
new file mode 100644
index 0000000..b66b735
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt
@@ -0,0 +1,52 @@
+/*
+ * 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.recents.data
+
+import android.graphics.Bitmap
+import com.android.launcher3.util.CancellableTask
+import com.android.quickstep.task.thumbnail.data.TaskThumbnailDataSource
+import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.ThumbnailData
+import java.util.function.Consumer
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+class FakeTaskThumbnailDataSource : TaskThumbnailDataSource {
+
+ val taskIdToBitmap: Map<Int, Bitmap> = (0..10).associateWith { mock() }
+ val taskIdToUpdatingTask: MutableMap<Int, () -> Unit> = mutableMapOf()
+ var shouldLoadSynchronously: Boolean = true
+
+ /** Retrieves and sets a thumbnail on [task] from [taskIdToBitmap]. */
+ override fun updateThumbnailInBackground(
+ task: Task,
+ callback: Consumer<ThumbnailData>
+ ): CancellableTask<ThumbnailData>? {
+ val thumbnailData = mock<ThumbnailData>()
+ whenever(thumbnailData.thumbnail).thenReturn(taskIdToBitmap[task.key.id])
+ val wrappedCallback = {
+ task.thumbnail = thumbnailData
+ callback.accept(thumbnailData)
+ }
+ if (shouldLoadSynchronously) {
+ wrappedCallback()
+ } else {
+ taskIdToUpdatingTask[task.key.id] = wrappedCallback
+ }
+ return null
+ }
+}
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
new file mode 100644
index 0000000..e160627
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.recents.data
+
+import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.ThumbnailData
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.map
+
+class FakeTasksRepository : RecentTasksRepository {
+ private var thumbnailDataMap: Map<Int, ThumbnailData> = emptyMap()
+ private var tasks: MutableStateFlow<List<Task>> = MutableStateFlow(emptyList())
+ private var visibleTasks: MutableStateFlow<List<Int>> = MutableStateFlow(emptyList())
+
+ override fun getAllTaskData(forceRefresh: Boolean): Flow<List<Task>> = tasks
+
+ override fun getTaskDataById(taskId: Int): Flow<Task?> =
+ getAllTaskData().map { taskList -> taskList.firstOrNull { it.key.id == taskId } }
+
+ override fun setVisibleTasks(visibleTaskIdList: List<Int>) {
+ visibleTasks.value = visibleTaskIdList
+ tasks.value = tasks.value.map { it.apply { thumbnail = thumbnailDataMap[it.key.id] } }
+ }
+
+ fun seedTasks(tasks: List<Task>) {
+ this.tasks.value = tasks
+ }
+
+ fun seedThumbnailData(thumbnailDataMap: Map<Int, ThumbnailData>) {
+ this.thumbnailDataMap = thumbnailDataMap
+ }
+}
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
new file mode 100644
index 0000000..c28a85a
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
@@ -0,0 +1,150 @@
+/*
+ * 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.recents.data
+
+import android.content.ComponentName
+import android.content.Intent
+import com.android.quickstep.TaskIconCache
+import com.android.quickstep.util.DesktopTask
+import com.android.quickstep.util.GroupTask
+import com.android.systemui.shared.recents.model.Task
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.drop
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.toList
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.mockito.kotlin.mock
+
+@OptIn(ExperimentalCoroutinesApi::class)
+class TasksRepositoryTest {
+ private val tasks = (0..5).map(::createTaskWithId)
+ private val defaultTaskList =
+ listOf(
+ GroupTask(tasks[0]),
+ GroupTask(tasks[1], tasks[2], null),
+ DesktopTask(tasks.subList(3, 6))
+ )
+ private val recentsModel = FakeRecentTasksDataSource()
+ private val taskThumbnailDataSource = FakeTaskThumbnailDataSource()
+ private val taskIconCache = mock<TaskIconCache>()
+
+ private val systemUnderTest =
+ TasksRepository(recentsModel, taskThumbnailDataSource, taskIconCache)
+
+ @Test
+ fun getAllTaskDataReturnsFlattenedListOfTasks() = runTest {
+ recentsModel.seedTasks(defaultTaskList)
+
+ assertThat(systemUnderTest.getAllTaskData(forceRefresh = true).first()).isEqualTo(tasks)
+ }
+
+ @Test
+ fun getTaskDataByIdReturnsSpecificTask() = runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ assertThat(systemUnderTest.getTaskDataById(2).first()).isEqualTo(tasks[2])
+ }
+
+ @Test
+ fun setVisibleTasksPopulatesThumbnails() = runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
+ val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
+
+ // .drop(1) to ignore initial null content before from thumbnail was loaded.
+ assertThat(systemUnderTest.getTaskDataById(1).drop(1).first()!!.thumbnail!!.thumbnail)
+ .isEqualTo(bitmap1)
+ assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail!!.thumbnail)
+ .isEqualTo(bitmap2)
+ }
+
+ @Test
+ fun changingVisibleTasksContainsAlreadyPopulatedThumbnails() = runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
+
+ // .drop(1) to ignore initial null content before from thumbnail was loaded.
+ assertThat(systemUnderTest.getTaskDataById(2).drop(1).first()!!.thumbnail!!.thumbnail)
+ .isEqualTo(bitmap2)
+
+ // Prevent new loading of Bitmaps
+ taskThumbnailDataSource.shouldLoadSynchronously = false
+ systemUnderTest.setVisibleTasks(listOf(2, 3))
+
+ assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail!!.thumbnail)
+ .isEqualTo(bitmap2)
+ }
+
+ @Test
+ fun retrievedThumbnailsAreDiscardedWhenTaskBecomesInvisible() = runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
+
+ // .drop(1) to ignore initial null content before from thumbnail was loaded.
+ assertThat(systemUnderTest.getTaskDataById(2).drop(1).first()!!.thumbnail!!.thumbnail)
+ .isEqualTo(bitmap2)
+
+ // Prevent new loading of Bitmaps
+ taskThumbnailDataSource.shouldLoadSynchronously = false
+ systemUnderTest.setVisibleTasks(listOf(0, 1))
+
+ assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail).isNull()
+ }
+
+ @Test
+ fun retrievedThumbnailsCauseEmissionOnTaskDataFlow() = runTest {
+ // Setup fakes
+ recentsModel.seedTasks(defaultTaskList)
+ val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
+ taskThumbnailDataSource.shouldLoadSynchronously = false
+
+ // Setup TasksRepository
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
+
+ // Assert there is no bitmap in first emission
+ val taskFlow = systemUnderTest.getTaskDataById(2)
+ val taskFlowValuesList = mutableListOf<Task?>()
+ backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
+ taskFlow.toList(taskFlowValuesList)
+ }
+ assertThat(taskFlowValuesList[0]!!.thumbnail).isNull()
+
+ // Simulate bitmap loading after first emission
+ taskThumbnailDataSource.taskIdToUpdatingTask.getValue(2).invoke()
+
+ // Check for second emission
+ assertThat(taskFlowValuesList[1]!!.thumbnail!!.thumbnail).isEqualTo(bitmap2)
+ }
+
+ private fun createTaskWithId(taskId: Int) =
+ Task(Task.TaskKey(taskId, 0, Intent(), ComponentName("", ""), 0, 2000))
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt
index efd7bec..3b8754c 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt
@@ -16,33 +16,51 @@
package com.android.quickstep.task.thumbnail
+import android.content.ComponentName
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.Color
+import android.graphics.Rect
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.quickstep.recents.data.FakeTasksRepository
import com.android.quickstep.recents.viewmodel.RecentsViewData
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.BackgroundOnly
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Snapshot
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
import com.android.quickstep.task.viewmodel.TaskViewData
import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.ThumbnailData
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
@RunWith(AndroidJUnit4::class)
class TaskThumbnailViewModelTest {
private val recentsViewData = RecentsViewData()
private val taskViewData = TaskViewData()
- private val systemUnderTest = TaskThumbnailViewModel(recentsViewData, taskViewData)
+ private val tasksRepository = FakeTasksRepository()
+ private val systemUnderTest =
+ TaskThumbnailViewModel(recentsViewData, taskViewData, tasksRepository)
+
+ private val tasks = (0..5).map(::createTaskWithId)
@Test
fun initialStateIsUninitialized() = runTest {
- assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.Uninitialized)
+ assertThat(systemUnderTest.uiState.first()).isEqualTo(Uninitialized)
}
@Test
fun bindRunningTask_thenStateIs_LiveTile() = runTest {
- val taskThumbnail = TaskThumbnail(Task(), isRunning = true)
+ tasksRepository.seedTasks(tasks)
+ val taskThumbnail = TaskThumbnail(taskId = 1, isRunning = true)
systemUnderTest.bind(taskThumbnail)
- assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.LiveTile)
+ assertThat(systemUnderTest.uiState.first()).isEqualTo(LiveTile)
}
@Test
@@ -65,15 +83,96 @@
}
@Test
- fun bindRunningTaskThenStoppedTask_thenStateIs_Uninitialized() = runTest {
- // TODO(b/334825222): Change the expectation here when snapshot state is implemented
- val task = Task()
- val runningTask = TaskThumbnail(task, isRunning = true)
- val stoppedTask = TaskThumbnail(task, isRunning = false)
- systemUnderTest.bind(runningTask)
- assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.LiveTile)
+ fun bindRunningTaskThenStoppedTaskWithoutThumbnail_thenStateChangesToBackgroundOnly() =
+ runTest {
+ tasksRepository.seedTasks(tasks)
+ val runningTask = TaskThumbnail(taskId = 1, isRunning = true)
+ val stoppedTask = TaskThumbnail(taskId = 2, isRunning = false)
+ systemUnderTest.bind(runningTask)
+ assertThat(systemUnderTest.uiState.first()).isEqualTo(LiveTile)
+
+ systemUnderTest.bind(stoppedTask)
+ assertThat(systemUnderTest.uiState.first())
+ .isEqualTo(BackgroundOnly(backgroundColor = Color.rgb(2, 2, 2)))
+ }
+
+ @Test
+ fun bindStoppedTaskWithoutThumbnail_thenStateIs_BackgroundOnly_withAlphaRemoved() = runTest {
+ tasksRepository.seedTasks(tasks)
+ val stoppedTask = TaskThumbnail(taskId = 2, isRunning = false)
systemUnderTest.bind(stoppedTask)
- assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.Uninitialized)
+ assertThat(systemUnderTest.uiState.first())
+ .isEqualTo(BackgroundOnly(backgroundColor = Color.rgb(2, 2, 2)))
+ }
+
+ @Test
+ fun bindLockedTaskWithThumbnail_thenStateIs_BackgroundOnly() = runTest {
+ tasksRepository.seedThumbnailData(mapOf(2 to createThumbnailData()))
+ tasks[2].isLocked = true
+ tasksRepository.seedTasks(tasks)
+ val recentTask = TaskThumbnail(taskId = 2, isRunning = false)
+
+ systemUnderTest.bind(recentTask)
+ assertThat(systemUnderTest.uiState.first())
+ .isEqualTo(BackgroundOnly(backgroundColor = Color.rgb(2, 2, 2)))
+ }
+
+ @Test
+ fun bindStoppedTaskWithThumbnail_thenStateIs_Snapshot_withAlphaRemoved() = runTest {
+ val expectedThumbnailData = createThumbnailData()
+ tasksRepository.seedThumbnailData(mapOf(2 to expectedThumbnailData))
+ tasksRepository.seedTasks(tasks)
+ tasksRepository.setVisibleTasks(listOf(2))
+ val recentTask = TaskThumbnail(taskId = 2, isRunning = false)
+
+ systemUnderTest.bind(recentTask)
+ assertThat(systemUnderTest.uiState.first())
+ .isEqualTo(
+ Snapshot(
+ backgroundColor = Color.rgb(2, 2, 2),
+ bitmap = expectedThumbnailData.thumbnail!!,
+ drawnRect = Rect(0, 0, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT)
+ )
+ )
+ }
+
+ @Test
+ fun bindNonVisibleStoppedTask_whenMadeVisible_thenStateIsSnapshot() = runTest {
+ val expectedThumbnailData = createThumbnailData()
+ tasksRepository.seedThumbnailData(mapOf(2 to expectedThumbnailData))
+ tasksRepository.seedTasks(tasks)
+ val recentTask = TaskThumbnail(taskId = 2, isRunning = false)
+
+ systemUnderTest.bind(recentTask)
+ assertThat(systemUnderTest.uiState.first())
+ .isEqualTo(BackgroundOnly(backgroundColor = Color.rgb(2, 2, 2)))
+ tasksRepository.setVisibleTasks(listOf(2))
+ assertThat(systemUnderTest.uiState.first())
+ .isEqualTo(
+ Snapshot(
+ backgroundColor = Color.rgb(2, 2, 2),
+ bitmap = expectedThumbnailData.thumbnail!!,
+ drawnRect = Rect(0, 0, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT)
+ )
+ )
+ }
+
+ private fun createTaskWithId(taskId: Int) =
+ Task(Task.TaskKey(taskId, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
+ colorBackground = Color.argb(taskId, taskId, taskId, taskId)
+ }
+
+ private fun createThumbnailData(): ThumbnailData {
+ val bitmap = mock<Bitmap>()
+ whenever(bitmap.width).thenReturn(THUMBNAIL_WIDTH)
+ whenever(bitmap.height).thenReturn(THUMBNAIL_HEIGHT)
+
+ return ThumbnailData(thumbnail = bitmap)
+ }
+
+ companion object {
+ const val THUMBNAIL_WIDTH = 100
+ const val THUMBNAIL_HEIGHT = 200
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
index 0de5f19..aa08ca4 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
@@ -31,7 +31,6 @@
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.statehandlers.DepthController
import com.android.launcher3.statemanager.StateManager
-import com.android.launcher3.statemanager.StatefulActivity
import com.android.launcher3.util.ComponentKey
import com.android.launcher3.util.SplitConfigurationOptions
import com.android.quickstep.RecentsModel
@@ -121,7 +120,7 @@
// Capture callback from recentsModel#getTasks()
val consumer =
- argumentCaptor<Consumer<ArrayList<GroupTask>>> {
+ argumentCaptor<Consumer<List<GroupTask>>> {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(nonMatchingComponent),
false /* findExactPairMatch */,
@@ -174,7 +173,7 @@
// Capture callback from recentsModel#getTasks()
val consumer =
- argumentCaptor<Consumer<ArrayList<GroupTask>>> {
+ argumentCaptor<Consumer<List<GroupTask>>> {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(matchingComponent),
false /* findExactPairMatch */,
@@ -215,7 +214,7 @@
// Capture callback from recentsModel#getTasks()
val consumer =
- argumentCaptor<Consumer<ArrayList<GroupTask>>> {
+ argumentCaptor<Consumer<List<GroupTask>>> {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(nonPrimaryUserComponent),
false /* findExactPairMatch */,
@@ -271,7 +270,7 @@
// Capture callback from recentsModel#getTasks()
val consumer =
- argumentCaptor<Consumer<ArrayList<GroupTask>>> {
+ argumentCaptor<Consumer<List<GroupTask>>> {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(nonPrimaryUserComponent),
false /* findExactPairMatch */,
@@ -324,7 +323,7 @@
// Capture callback from recentsModel#getTasks()
val consumer =
- argumentCaptor<Consumer<ArrayList<GroupTask>>> {
+ argumentCaptor<Consumer<List<GroupTask>>> {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(matchingComponent),
false /* findExactPairMatch */,
@@ -378,7 +377,7 @@
// Capture callback from recentsModel#getTasks()
val consumer =
- argumentCaptor<Consumer<ArrayList<GroupTask>>> {
+ argumentCaptor<Consumer<List<GroupTask>>> {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(nonMatchingComponent, matchingComponent),
false /* findExactPairMatch */,
@@ -431,7 +430,7 @@
// Capture callback from recentsModel#getTasks()
val consumer =
- argumentCaptor<Consumer<ArrayList<GroupTask>>> {
+ argumentCaptor<Consumer<List<GroupTask>>> {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(matchingComponent, matchingComponent),
false /* findExactPairMatch */,
@@ -497,7 +496,7 @@
// Capture callback from recentsModel#getTasks()
val consumer =
- argumentCaptor<Consumer<ArrayList<GroupTask>>> {
+ argumentCaptor<Consumer<List<GroupTask>>> {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(matchingComponent, matchingComponent),
false /* findExactPairMatch */,
@@ -549,7 +548,7 @@
// Capture callback from recentsModel#getTasks()
val consumer =
- argumentCaptor<Consumer<ArrayList<GroupTask>>> {
+ argumentCaptor<Consumer<List<GroupTask>>> {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(matchingComponent2, matchingComponent),
true /* findExactPairMatch */,
diff --git a/quickstep/tests/multivalentTestsForDeviceless b/quickstep/tests/multivalentTestsForDeviceless
deleted file mode 120000
index fa0fabf..0000000
--- a/quickstep/tests/multivalentTestsForDeviceless
+++ /dev/null
@@ -1 +0,0 @@
-./multivalentTests
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt
index 4fafde8..5b56710 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt
@@ -86,7 +86,8 @@
val newHotseatItems =
taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
- assertThat(newHotseatItems.map { it?.targetPackage }).isEqualTo(hotseatPackages)
+ assertThat(newHotseatItems.map { it?.targetPackage })
+ .containsExactlyElementsIn(hotseatPackages)
}
@Test
@@ -119,7 +120,8 @@
RUNNING_APP_PACKAGE_1,
RUNNING_APP_PACKAGE_2,
)
- assertThat(newHotseatItems.map { it?.targetPackage }).isEqualTo(expectedPackages)
+ assertThat(newHotseatItems.map { it?.targetPackage })
+ .containsExactlyElementsIn(expectedPackages)
}
@Test
@@ -144,7 +146,8 @@
RUNNING_APP_PACKAGE_1,
RUNNING_APP_PACKAGE_2,
)
- assertThat(newHotseatItems.map { it?.targetPackage }).isEqualTo(expectedPackages)
+ assertThat(newHotseatItems.map { it?.targetPackage })
+ .containsExactlyElementsIn(expectedPackages)
}
@Test
@@ -155,7 +158,8 @@
whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
taskbarRunningAppsController.updateRunningApps()
- assertThat(taskbarRunningAppsController.runningApps).isEqualTo(emptySet<String>())
+ assertThat(taskbarRunningAppsController.runningApps).isEmpty()
+ assertThat(taskbarRunningAppsController.minimizedApps).isEmpty()
}
@Test
@@ -167,7 +171,28 @@
taskbarRunningAppsController.updateRunningApps()
assertThat(taskbarRunningAppsController.runningApps)
- .isEqualTo(setOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
+ .containsExactly(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)
+ assertThat(taskbarRunningAppsController.minimizedApps).isEmpty()
+ }
+
+ @Test
+ fun getMinimizedApps_inDesktopMode_returnsAllAppsRunningAndInvisibleAppsMinimized() {
+ setInDesktopMode(true)
+ val runningTasks =
+ ArrayList(
+ listOf(
+ createDesktopTaskInfo(RUNNING_APP_PACKAGE_1) { isVisible = true },
+ createDesktopTaskInfo(RUNNING_APP_PACKAGE_2) { isVisible = true },
+ createDesktopTaskInfo(RUNNING_APP_PACKAGE_3) { isVisible = false },
+ )
+ )
+ whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
+ taskbarRunningAppsController.updateRunningApps()
+
+ assertThat(taskbarRunningAppsController.runningApps)
+ .containsExactly(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2, RUNNING_APP_PACKAGE_3)
+ assertThat(taskbarRunningAppsController.minimizedApps)
+ .containsExactly(RUNNING_APP_PACKAGE_3)
}
private fun createHotseatItemsFromPackageNames(packageNames: List<String>): List<ItemInfo> {
@@ -180,11 +205,15 @@
return ArrayList(packageNames.map { createDesktopTaskInfo(packageName = it) })
}
- private fun createDesktopTaskInfo(packageName: String): RunningTaskInfo {
+ private fun createDesktopTaskInfo(
+ packageName: String,
+ init: RunningTaskInfo.() -> Unit = { isVisible = true },
+ ): RunningTaskInfo {
return RunningTaskInfo().apply {
taskId = nextTaskId++
configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FREEFORM
realActivity = ComponentName(packageName, "TestActivity")
+ init()
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index 094fd4c..4459ed6 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -162,8 +162,8 @@
final Context targetContext = getInstrumentation().getTargetContext();
final DisplayController.DisplayInfoChangeListener listener =
(context, info, flags) -> {
- if (LauncherInstrumentation.getNavigationModel(info.navigationMode.resValue)
- == expectedMode) {
+ if (LauncherInstrumentation.getNavigationModel(
+ info.getNavigationMode().resValue) == expectedMode) {
latch.countDown();
}
};
diff --git a/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt b/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt
index 2916952..5157c71 100644
--- a/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt
@@ -18,6 +18,7 @@
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.doReturn
import org.mockito.kotlin.verifyZeroInteractions
import org.mockito.kotlin.whenever
@@ -79,7 +80,7 @@
@Test
fun onDisplayInfoChanged_noButton_registerExclusionListener() {
- whenever(windowManagerProxy.getNavigationMode(context)).thenReturn(NavigationMode.NO_BUTTON)
+ doReturn(NavigationMode.NO_BUTTON).whenever(info).getNavigationMode()
underTest.onDisplayInfoChanged(context, info, CHANGE_ROTATION or CHANGE_NAVIGATION_MODE)
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index bfd7bdb..6be082a 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -129,8 +129,6 @@
overview.getCurrentTask()
.tapMenu()
.hasMenuItem("Save app pair"));
- } else {
- overview.getOverviewGroupActions().assertHasAction("Save app pair");
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
index e4f8b6c..106e590 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
@@ -54,7 +54,7 @@
@Test
@PortraitLandscape
- @NavigationModeSwitch
+ @NavigationModeSwitch(mode = ZERO_BUTTON)
public void goHome() throws Exception {
assumeTrue(mLauncher.isTablet());
@@ -87,7 +87,7 @@
@Test
@PortraitLandscape
- @NavigationModeSwitch
+ @NavigationModeSwitch(mode = ZERO_BUTTON)
@ScreenRecordRule.ScreenRecord // b/336606166
@TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/336606166
public void switchToOverview() throws Exception {
@@ -100,7 +100,7 @@
@Test
@PortraitLandscape
- @NavigationModeSwitch
+ @NavigationModeSwitch(mode = ZERO_BUTTON)
public void testAllAppsFromHome() throws Exception {
assumeTrue(mLauncher.isTablet());
@@ -110,7 +110,7 @@
}
@Test
- @NavigationModeSwitch
+ @NavigationModeSwitch(mode = ZERO_BUTTON)
@PortraitLandscape
public void testQuickSwitchFromHome() throws Exception {
assumeTrue(mLauncher.isTablet());
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index b936ad0..1d333fd 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deïnstalleer"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Appinligting"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installeer privaat"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Deïnstalleer app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installeer"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Moenie voorstel nie"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Vasspeldvoorspelling"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 19d4604..f57812e 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"አራግፍ"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"የመተግበሪያ መረጃ"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"በግል ይጫኑ"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"መተግበሪያን አራግፍ"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ጫን"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"መተግበሪያውን አይጠቁሙ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"የፒን ግምት"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 500fe61..e6f8d4a 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"إلغاء التثبيت"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"معلومات عن التطبيق"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"تثبيت في مساحة خاصّة"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"إلغاء تثبيت التطبيق"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"تثبيت"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"عدم اقتراح التطبيق"</string>
<string name="pin_prediction" msgid="4196423321649756498">"تثبيت التطبيق المتوقّع"</string>
@@ -183,7 +184,7 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"فلتر"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"تعذَّر <xliff:g id="WHAT">%1$s</xliff:g>."</string>
<string name="private_space_label" msgid="2359721649407947001">"مساحة خاصة"</string>
- <string name="private_space_secondary_label" msgid="9203933341714508907">"النقر للإعداد أو الفتح"</string>
+ <string name="private_space_secondary_label" msgid="9203933341714508907">"انقر للإعداد أو الفتح"</string>
<string name="ps_container_title" msgid="4391796149519594205">"المساحة الخاصة"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"إعدادات المساحة الخاصة"</string>
<string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"المساحة الخاصة غير مُقفلة."</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index cb490b5..54cc638 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"আনইনষ্টল কৰক"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"এপ্ সম্পৰ্কীয় তথ্য"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"গোপনে ইনষ্টল কৰক"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"এপ্ আনইনষ্টল কৰক"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ইনষ্টল কৰক"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"পৰামৰ্শ নিদিব"</string>
<string name="pin_prediction" msgid="4196423321649756498">"পূৰ্বানুমান কৰা এপ্টো পিন কৰক"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index c6cc267..2f71bbd 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Sistemdən sil"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Tətbiq haqqında"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Məxfi quraşdırın"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Tətbiqi sistemdən silin"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Quraşdırın"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Tətbiq təklif olunmasın"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Proqnozlaşdırılan tətbiqi bərkidin"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 830de4e..7858529 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Podaci o aplikaciji"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instaliraj na privatni"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Deinstalirajte aplikaciju"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Zakači predviđanje"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 1a3a870..c3359c8 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Дэінсталяваць"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Звесткі аб праграме"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Усталяваць прыватна"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Выдаліць праграму"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Усталяваць"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не прапаноўваць праграму"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Замацаваць прапанаваную праграму"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 5030e7c..26044e7 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Деинсталиране"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Информация за прилож."</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Инстал. в частно простр."</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Деинсталиране на приложението"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Инсталиране"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Без предлагане на приложение"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Фиксиране на предвиждането"</string>
@@ -182,14 +183,14 @@
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Отмяна на паузата"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Филтър"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Неуспешно: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
- <string name="private_space_label" msgid="2359721649407947001">"Лично пространство"</string>
+ <string name="private_space_label" msgid="2359721649407947001">"Частно пространство"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"Докоснете за настройване или отваряне"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Лично"</string>
- <string name="ps_container_settings" msgid="6059734123353320479">"Настройки за личното пространство"</string>
+ <string name="ps_container_settings" msgid="6059734123353320479">"Настройки за частното пространство"</string>
<string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Частно, отключено."</string>
<string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Частно, заключено."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Заключване"</string>
- <string name="ps_container_transition" msgid="8667331812048014412">"Преминаване към личното пространство"</string>
+ <string name="ps_container_transition" msgid="8667331812048014412">"Преминаване към частното пространство"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Инсталиране"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Инсталиране на приложения в частно пространство"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Препълване"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 34edae0..a159bd9 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"আনইনস্টল করুন"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"অ্যাপের তথ্য"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"প্রাইভেট প্রোফাইলে ইনস্টল করুন"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"অ্যাপ আনইনস্টল করুন"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ইনস্টল করুন"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"অ্যাপ সাজেস্ট করবেন না"</string>
<string name="pin_prediction" msgid="4196423321649756498">"আপনার প্রয়োজন হতে পারে এমন অ্যাপ পিন করুন"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 1ad9a5c..8b2e821 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Inform. o aplikaciji"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instaliraj u Privatno"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Deinstalirajte aplikaciju"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Zakači predviđanje"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 33f75b5..c621b1c 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstal·la"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Informació de l\'aplicació"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instal·la en privat"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Desinstal·la l\'aplicació"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instal·la"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"No suggereixis l\'aplicació"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixa la predicció"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 6ac1d57..8b2e716 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odinstalovat"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"O aplikaci"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalovat soukromě"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Odinstalovat aplikaci"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Nainstalovat"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Nenavrhovat aplikaci"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Připnout předpověď"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index bf09aeb..b413440 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Afinstaller"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Appinfo"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installer (privat)"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Afinstaller appen"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Foreslå ikke en app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fastgør forslaget"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 834100b..42e3bac 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstallieren"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"App-Info"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Vertraul. installieren"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"App deinstallieren"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installieren"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"App nicht vorschlagen"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Vorgeschlagene App fixieren"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index f0496b5..4eac9ca 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Απεγκατάσταση"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Πληροφ. εφαρμογής"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Εγκατ. στο απόρρητο"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Απεγκατάσταση εφαρμογής"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Εγκατάσταση"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Να μην προτείνεται"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Καρφίτσωμα πρόβλεψης"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 83f1977..7c78fc7 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"App info"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Install in private"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Uninstall app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin prediction"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 4bf147c..e6a7ea1 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"App info"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Install in private"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Uninstall app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin Prediction"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 83f1977..7c78fc7 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"App info"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Install in private"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Uninstall app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin prediction"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 83f1977..7c78fc7 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"App info"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Install in private"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Uninstall app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin prediction"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 24cc5ac..13616d6 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"App info"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Install in private"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Uninstall app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin Prediction"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 2e6d840..71a48cb 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -58,7 +58,7 @@
<string name="widgets_full_sheet_cancel_button_description" msgid="5766167035728653605">"Borra el texto del cuadro de búsqueda"</string>
<string name="no_widgets_available" msgid="4337693382501046170">"Los widgets y accesos directos no están disponibles"</string>
<string name="no_search_results" msgid="3787956167293097509">"No se encontraron widgets ni accesos directos"</string>
- <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Personales"</string>
+ <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Personal"</string>
<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>
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Información de app"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalar en privado"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Desinstalar app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"No sugerir app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fijar predicción"</string>
@@ -167,8 +168,8 @@
<string name="action_deep_shortcut" msgid="2864038805849372848">"Accesos directos"</string>
<string name="action_dismiss_notification" msgid="5909461085055959187">"Descartar"</string>
<string name="accessibility_close" msgid="2277148124685870734">"Cerrar"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personales"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"De trabajo"</string>
+ <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
+ <string name="all_apps_work_tab" msgid="4884822796154055118">"Trabajo"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabajo"</string>
<string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Las apps de trabajo tienen una insignia y el administrador de TI las puede ver"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"Entendido"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 463509a..b5208bd 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Información de la aplicación"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Descargar en privado"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Desinstalar aplicación"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"No sugerir aplicación"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fijar predicción"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 291831a..20a99d3 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalli"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Rakenduse teave"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Privaatselt installimine"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Desinstalli rakendus"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installimine"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ära soovita rakendust"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Kinnita ennustus"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 1a28d70..a477580 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalatu"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Aplikazioaren informazioa"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalatu pribatuan"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Desinstalatu aplikazioa"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalatu"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ez iradoki aplikazioa"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Ainguratu iragarpena"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 1ac2e9a..bdf4736 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"حذف نصب"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"اطلاعات برنامه"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"نصب در نمایه خصوصی"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"حذف نصب برنامه"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"نصب"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"برنامه پیشنهاد داده نشود"</string>
<string name="pin_prediction" msgid="4196423321649756498">"سنجاق کردن پیشنهاد"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index b4fa543..e934044 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Poista asennus"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Sovelluksen tiedot"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Asenna yksityisesti"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Sovelluksen poistaminen"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Asenna"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Älä ehdota sovellusta"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Kiinnitä sovellus"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 9f07ffd..4372caa 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Désinstaller"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Détails de l\'appli"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installer dans privé"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Désinstaller l\'appli"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne pas suggérer d\'appli"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Épingler la prédiction"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index dd9ec40..841fc84 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Désinstaller"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Infos sur l\'appli"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installer en mode privé"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Désinstaller l\'application"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne pas suggérer d\'appli"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Épingler la prédiction"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 8940daf..83fcbcd 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Información da app"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalar en privado"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Desinstalar aplicación"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Non suxerir app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixar predición"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index e595588..963c6d1 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"અનઇન્સ્ટૉલ કરો"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ઍપની માહિતી"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ખાનગીમાં ઇન્સ્ટૉલ કરો"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"ઍપ અનઇન્સ્ટૉલ કરો"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ઇન્સ્ટૉલ કરો"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ઍપ સૂચવશો નહીં"</string>
<string name="pin_prediction" msgid="4196423321649756498">"પૂર્વાનુમાનને પિન કરો"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 0c71db8..f2ac2e8 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"अनइंस्टॉल करें"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ऐप्लिकेशन की जानकारी"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"निजी तौर पर इंस्टॉल करें"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"ऐप्लिकेशन अनइंस्टॉल करें"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"इंस्टॉल करें"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ऐप्लिकेशन का सुझाव न दें"</string>
<string name="pin_prediction" msgid="4196423321649756498">"सुझाए गए ऐप्लिकेशन को पिन करें"</string>
@@ -123,7 +124,7 @@
<string name="title_missing_notification_access" msgid="7503287056163941064">"सूचना के ऐक्सेस की ज़रूरत है"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"सूचना बिंदु दिखाने के लिए, <xliff:g id="NAME">%1$s</xliff:g> के ऐप्लिकेशन सूचना चालू करें"</string>
<string name="title_change_settings" msgid="1376365968844349552">"सेटिंग बदलें"</string>
- <string name="notification_dots_service_title" msgid="4284221181793592871">"नई सूचनाएं बताने वाला गोल निशान दिखाएं"</string>
+ <string name="notification_dots_service_title" msgid="4284221181793592871">"सूचनाएं बताने वाले डॉट दिखाएं"</string>
<string name="developer_options_title" msgid="700788437593726194">"डेवलपर के लिए सेटिंग और टूल"</string>
<string name="auto_add_shortcuts_label" msgid="4926805029653694105">"होम स्क्रीन पर ऐप्लिकेशन के आइकॉन जोड़ें"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"नए ऐप्लिकेशन के लिए"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index d07775c..fec8e28 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Podaci o aplikaciji"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instaliraj u privatno"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Deinstaliraj aplikaciju"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Prikvači predviđenu apl."</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 86ec374..f69e1fb 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Eltávolítás"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Alkalmazásinfó"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Privát telepítés"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Alkalmazás eltávolítása"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Telepítés"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne javasoljon appot"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Várható kitűzése"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 4bc54ab..7e220bf 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Ապատեղադրել"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Հավելվածի մասին"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Տեղադրել մասնավորում"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Ապատեղադրել հավելվածը"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Տեղադրել"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Չառաջարկել"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Ամրացնել առաջարկվող հավելվածը"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index cd614d0..fc81717 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstal"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Info aplikasi"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instal di ruang privasi"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Uninstal aplikasi"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instal"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Jangan sarankan apl"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin Prediksi"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 53b8e90..5339b93 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Fjarlægja"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Forritsupplýsingar"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Setja upp á lokuðum prófíl"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Fjarlægja forrit"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Setja upp"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ekki fá tillögu að forriti"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Festa tillögu"</string>
@@ -182,14 +183,14 @@
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Ljúka hléi"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Sía"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Mistókst: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
- <string name="private_space_label" msgid="2359721649407947001">"Einkarými"</string>
+ <string name="private_space_label" msgid="2359721649407947001">"Leynirými"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"Ýttu til að setja upp eða opna"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Lokað"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Stillingar einkarýmis"</string>
<string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Lokað, ólæst."</string>
<string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Lokað, læst."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Læsa"</string>
- <string name="ps_container_transition" msgid="8667331812048014412">"Einkarými að breytast"</string>
+ <string name="ps_container_transition" msgid="8667331812048014412">"Leynirými að breytast"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Setja upp"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Setja upp forrit í leynirými"</string>
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Yfirflæði"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index af0e2b9..5ef0145 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Disinstalla"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Informazioni app"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installa in privato"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Disinstalla app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installa"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Non suggerire app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Blocca previsione"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 7075d59..0d18cdf 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"להסרת התקנה"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"פרטי אפליקציה"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"התקנה במרחב הפרטי"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"הסרת האפליקציה"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"התקנה"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"בלי להציע את האפליקציה"</string>
<string name="pin_prediction" msgid="4196423321649756498">"הצמדת החיזוי"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index d957c5c..163afd4 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"アンインストール"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"アプリ情報"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"非公開インストール"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"アプリをアンインストール"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"インストール"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"アプリを表示しない"</string>
<string name="pin_prediction" msgid="4196423321649756498">"アプリの候補を固定"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 8a1eb21..d7157e9 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"დეინსტალაცია"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"აპის შესახებ"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"კერძოში ინსტალაცია"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"აპის დეინსტალაცია"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ინსტალაცია"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"არ შემომთავაზო აპი"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ჩამაგრების პროგნოზირება"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index f70888a..c53cd03 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Жою"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Қолданба ақпараты"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Құпия профильге орнату"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Қолданбаны жою"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Орнату"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Қолданба ұсынбау"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Болжанған қолданбаны бекіту"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 14ff3c9..f0c9fd9 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"លុប"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ព័ត៌មានកម្មវិធី"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ដំឡើងជាលក្ខណៈឯកជន"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"លុបកម្មវិធី"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ដំឡើង"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"កុំណែនាំកម្មវិធី"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ខ្ទាស់ការព្យាករ"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index f918d18..9a81382 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"ಅನ್ಇನ್ಸ್ಟಾಲ್"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ಆ್ಯಪ್ ಮಾಹಿತಿ"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ಖಾಸಗಿಯಾಗಿ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"ಆ್ಯಪ್ ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ಸ್ಥಾಪಿಸಿ"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ಆ್ಯಪ್ ಅನ್ನು ಸೂಚಿಸಬೇಡಿ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ಮುನ್ನೋಟ ಪಿನ್ ಮಾಡಿ"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index b59ccd6..6ff9d90 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"제거"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"앱 정보"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"비공개 스페이스에 설치"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"앱 제거"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"설치"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"앱 제안 받지 않음"</string>
<string name="pin_prediction" msgid="4196423321649756498">"예상 앱 고정"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index e4bbc01..44ef720 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Чыгарып салуу"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Колдонмо тууралуу"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Жеке мейкиндикке орнотуу"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Колдонмону чыгарып салуу"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Орнотуу"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Cунушталбасын"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Божомолдонгон колдонмону кадап коюу"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 17f226e..f8ecb7e 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"ຖອນການຕິດຕັ້ງ"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ຂໍ້ມູນແອັບ"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ຕິດຕັ້ງໃນສ່ວນຕົວ"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"ຖອນການຕິດຕັ້ງແອັບ"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ຕິດຕັ້ງ"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ຢ່າແນະນຳແອັບ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ປັກໝຸດການຄາດເດົາ"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 17cb3cf..b851d55 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Pašalinti"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Programos inform."</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Įdiegti privačiai"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Pašalinti programą"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Įdiegti"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Nesiūlyti programos"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Prisegti numatymą"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index e514afc..2c1ec75 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Atinstalēt"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Par lietotni"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalēt privāti"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Atinstalēt lietotni"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalēt"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Neieteikt lietotni"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Piespraust prognozēto lietotni"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 3169f7d..b87c2ce 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Деинсталирај"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Инф. за апликација"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Инстал. во приватен"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Деинсталирај ја апликацијата"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Инсталирај"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлагај апл."</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закачи го предвидувањето"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 952e607..beb2f6f 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"അൺഇൻസ്റ്റാൾ"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ആപ്പ് വിവരങ്ങൾ"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"സ്വകാര്യമായി ഇൻസ്റ്റാൾ ചെയ്യൂ"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"ആപ്പ് അൺഇൻസ്റ്റാൾ ചെയ്യുക"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ഇൻസ്റ്റാൾ ചെയ്യുക"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ആപ്പ് നിർദ്ദേശിക്കേണ്ട"</string>
<string name="pin_prediction" msgid="4196423321649756498">"പ്രവചനം പിൻ ചെയ്യുക"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 7209c85..7b4bce7 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Устгах"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Аппын мэдээлэл"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Хувийнхад суулгах"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Аппыг устгах"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Суулгах"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Апп бүү санал болго"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Таамаглалыг бэхлэх"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 5c08f2e..8adb240 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"अनइंस्टॉल करा"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"अॅप माहिती"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"खाजगीत इंस्टॉल करा"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"अॅप अनइंस्टॉल करा"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"इंस्टॉल करा"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ॲप सुचवू नका"</string>
<string name="pin_prediction" msgid="4196423321649756498">"पूर्वानुमान पिन करा"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 20627c8..f194bc1 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Nyahpasang"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Maklumat apl"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Pasang dalam persendirian"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Nyahpasang apl"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Pasang"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Jangan cadangkan apl"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Sematkan Ramalan"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index b77ee98..7dc3b5a 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"ဖယ်ရှားရန်"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"အက်ပ်အချက်အလက်"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"သီးသန့်တွင် ထည့်သွင်းရန်"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"အက်ပ်ကို ဖယ်ရှားရန်"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ထည့်သွင်းရန်"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"အက်ပ်အကြံမပြုပါနှင့်"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ခန့်မှန်းချက်ကို ပင်ထိုးရန်"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index c262517..856ce9f 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Avinstaller"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Info om appen"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installer privat"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Avinstaller appen"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ikke foreslå app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fest forslaget"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index c47d38e..2197a8b 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"अनइन्स्टल गर्नुहोस्"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"एपसम्बन्धी जानकारी"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"निजी प्रोफाइलमा इन्स्टल गर्नुहोस्"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"एप अनइन्स्टल गर्नुहोस्"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"स्थापना गर्नुहोस्"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"एप सिफारिस नगर्नुहोस्"</string>
<string name="pin_prediction" msgid="4196423321649756498">"सिफारिस गरिएको एप पिन गर्नुहोस्"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 09a4090..bd4508c 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deïnstalleren"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"App-info"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Privé installeren"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"App verwijderen"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installeren"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Geen app voorstellen"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Vastzetvoorspelling"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index ea68d8c..e2035a2 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"ଅନଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ଆପ ସୂଚନା"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ପ୍ରାଇଭେଟରେ ଇନଷ୍ଟଲ କର"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"ଆପ ଅନଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ଆପ ପରାମର୍ଶ ଦିଅନ୍ତୁ ନାହିଁ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ପୂର୍ବାନୁମାନକୁ ପିନ୍ କରନ୍ତୁ"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 073acfa..f412820 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"ਅਣਸਥਾਪਤ ਕਰੋ"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ਐਪ ਜਾਣਕਾਰੀ"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ਨਿੱਜੀ ਵਜੋਂ ਸਥਾਪਤ ਕਰੋ"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"ਐਪ ਅਣਸਥਾਪਤ ਕਰੋ"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ਸਥਾਪਤ ਕਰੋ"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ਐਪ ਦਾ ਸੁਝਾਅ ਨਾ ਦਿਓ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ਪੂਰਵ-ਅਨੁਮਾਨ ਪਿੰਨ ਕਰੋ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 04a4419..a97d56e 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odinstaluj"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"O aplikacji"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Zainstaluj prywatnie"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Odinstaluj aplikację"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Zainstaluj"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Nie proponuj aplikacji"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Przypnij podpowiedź"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 07b32b1..3257915 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Info. da app"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalar em privado"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Desinstalar app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Não sugerir app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixar previsão"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index d06806d..27aa1ee 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Informações do app"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalar em particular"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Desinstalar app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Não sugerir esse app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixar previsão"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index fdd1f27..959bb1c 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Dezinstalează"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Informații despre aplicații"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalează în privat"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Dezinstalează aplicația"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalează"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Nu sugera aplicația"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixează predicția"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index b797b32..1844933 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Удалить"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"О приложении"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Частная установка"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Удалить приложение"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Установить"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не рекомендовать"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закрепить рекомендацию"</string>
@@ -184,7 +185,7 @@
<string name="remote_action_failed" msgid="1383965239183576790">"Не удалось выполнить действие (<xliff:g id="WHAT">%1$s</xliff:g>)."</string>
<string name="private_space_label" msgid="2359721649407947001">"Частное пространство"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"Нажмите, чтобы настроить или открыть"</string>
- <string name="ps_container_title" msgid="4391796149519594205">"Доступно только вам"</string>
+ <string name="ps_container_title" msgid="4391796149519594205">"Частный профиль"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Настройки личного пространства"</string>
<string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Личное, разблокировано."</string>
<string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Личное, заблокировано."</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 9d85606..d5a0114 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"අස්ථාපනය කරන්න"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"යෙදුම් තොරතුරු"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"පෞද්ගලිකව ස්ථාපනය කරන්න"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"යෙදුම අස්ථාපනය කරන්න"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ස්ථාපනය කරන්න"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"යෙදුම යෝජනා නොකරන්න"</string>
<string name="pin_prediction" msgid="4196423321649756498">"පුරෝකථනය අමුණන්න"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 0d9001a..3d12a65 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odinštalovať"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Info o aplikácii"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Inštalovať v súkromí"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Odinštalovať aplikáciu"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Inštalovať"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Nenavrhovať aplikáciu"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pripnúť predpoveď"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index e16ec59..070ccbb 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odmesti"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Podatki o aplikaciji"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Namesti v zasebno"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Odmesti aplikacijo"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Namesti"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlagaj"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Predvidevanje pripenjanja"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 1f2aa26..df2395a 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Çinstalo"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Info mbi aplikacionin"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalo në private"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Çinstalo aplikacionin"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalo"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Mos sugjero aplikacion"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Gozhdo parashikimin"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 3d0ad3b..0721730 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Деинсталирај"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Подаци о апликацији"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Инсталирај на приватни"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Деинсталирајте апликацију"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Инсталирај"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлажи апликацију"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закачи предвиђање"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index ee2b328..2b6a9aa 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Avinstallera"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Info om appen"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installera i privat"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Avinstallera appen"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installera"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Föreslå inte app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fäst förslag"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index a7f5fdd..d44eb13 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Ondoa"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Maelezo ya programu"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Sakinisha faraghani"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Ondoa programu"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Sakinisha"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Isipendekeze programu"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Bandika Utabiri"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 06eaa44..efa4b85 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -84,6 +84,8 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"நிறுவல் நீக்கு"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ஆப்ஸ் தகவல்"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"தனிப்பட்டதில் நிறுவு"</string>
+ <!-- no translation found for uninstall_private_system_shortcut_label (8423460530441627982) -->
+ <skip />
<string name="install_drop_target_label" msgid="2539096853673231757">"நிறுவு"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"பரிந்துரைக்காதே"</string>
<string name="pin_prediction" msgid="4196423321649756498">"கணிக்கப்பட்ட ஆப்ஸைப் பின் செய்தல்"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 55aae20..bd09562 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"అన్ఇన్స్టాల్ చేయండి"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"యాప్ సమాచారం"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ప్రైవేట్ ఇన్స్టాల్"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"యాప్ను అన్ఇన్స్టాల్ చేయండి"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ఇన్స్టాల్ చేయండి"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"యాప్ సూచించకు"</string>
<string name="pin_prediction" msgid="4196423321649756498">"సూచనను పిన్ చేయండి"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 56864a6..dcaa17b 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"ถอนการติดตั้ง"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ข้อมูลแอป"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ติดตั้งในแบบส่วนตัว"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"ถอนการติดตั้งแอป"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ติดตั้ง"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ไม่ต้องแนะนำแอป"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ปักหมุดแอปที่คาดการณ์ไว้"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 1a3d719..ba4b6aa 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"I-uninstall"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Impormasyon ng app"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Pribadong i-install"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"I-uninstall ang app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"I-install"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Huwag magmungkahi"</string>
<string name="pin_prediction" msgid="4196423321649756498">"I-pin ang Hula"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 6d3fc6f..e46ffd1 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Kaldır"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Uygulama bilgileri"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Özel olarak yükle"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Uygulamanın yüklemesini kaldır"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Yükle"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Uygulamayı önerme"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Tahmini Sabitle"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index a69f4b0..9cca61f 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Видалити додаток"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Про додаток"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Установити приватно"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Видалити додаток"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Установити"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не пропонувати додаток"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закріпити передбачений додаток"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 99d3a7b..5fbfc52 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"اَن انسٹال کریں"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ایپ کی معلومات"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"پرائیویٹ میں انسٹال کریں"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"ایپ کو اَن انسٹال کریں"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"انسٹال کریں"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ایپ تجویز نہ کریں"</string>
<string name="pin_prediction" msgid="4196423321649756498">"پیشگوئی پن کریں"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 2334a61..10e928b 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"O‘chirib tashlash"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Ilova haqida"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Maxfiy oʻrnatish"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Ilovani oʻchirish"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"O‘rnatish"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Tavsiya qilinmasin"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Tavsiyani mahkamlash"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index feaddcd..9eebdd7 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Gỡ cài đặt"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Thông tin ứng dụng"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Cài đặt ở chế độ riêng tư"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Gỡ cài đặt ứng dụng"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Cài đặt"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Không gợi ý ứng dụng"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Ghim ứng dụng dự đoán"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 58533c3..3c430c1 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"卸载"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"应用信息"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"安装到私密个人资料中"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"卸载应用"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"安装"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"不要提供应用建议"</string>
<string name="pin_prediction" msgid="4196423321649756498">"固定预测的应用"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 6070b4e..ce26039 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"解除安裝"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"應用程式資料"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"安裝在私人資料夾中"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"解除安裝應用程式"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"安裝"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"不要提供應用程式建議"</string>
<string name="pin_prediction" msgid="4196423321649756498">"固定預測"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 0b40dd0..fc0dddf 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"解除安裝"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"應用程式資訊"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"安裝在私人空間中"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"解除安裝應用程式"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"安裝"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"不要提供應用程式建議"</string>
<string name="pin_prediction" msgid="4196423321649756498">"固定預測的應用程式"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 99abe05..1471564 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -84,6 +84,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Khipha"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Ulwazi nge-app"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Faka ngokugodliwe"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Khipha i-app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Faka"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ungaphakamisi uhlelo lokusebenza"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Ukubikezela Iphinikhodi"</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index e31a35f..2741158 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -416,6 +416,9 @@
<dimen name="taskbar_running_app_indicator_height">0dp</dimen>
<dimen name="taskbar_running_app_indicator_width">0dp</dimen>
<dimen name="taskbar_running_app_indicator_top_margin">0dp</dimen>
+ <dimen name="taskbar_minimized_app_indicator_height">0dp</dimen>
+ <dimen name="taskbar_minimized_app_indicator_width">0dp</dimen>
+ <dimen name="taskbar_minimized_app_indicator_top_margin">0dp</dimen>
<!-- Transient taskbar (placeholders to compile in Launcher3 without Quickstep) -->
<dimen name="transient_taskbar_padding">0dp</dimen>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 2a8298f..7d09164 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -186,9 +186,20 @@
// These fields, related to showing running apps, are only used for Taskbar.
private final Size mRunningAppIndicatorSize;
private final int mRunningAppIndicatorTopMargin;
+ private final Size mMinimizedAppIndicatorSize;
+ private final int mMinimizedAppIndicatorTopMargin;
private final Paint mRunningAppIndicatorPaint;
private final Rect mRunningAppIconBounds = new Rect();
- private boolean mIsRunning;
+ private RunningAppState mRunningAppState;
+
+ /**
+ * Various options for the running state of an app.
+ */
+ public enum RunningAppState {
+ NOT_RUNNING,
+ RUNNING,
+ MINIMIZED,
+ }
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mStayPressed;
@@ -259,9 +270,16 @@
mRunningAppIndicatorSize = new Size(
getResources().getDimensionPixelSize(R.dimen.taskbar_running_app_indicator_width),
getResources().getDimensionPixelSize(R.dimen.taskbar_running_app_indicator_height));
+ mMinimizedAppIndicatorSize = new Size(
+ getResources().getDimensionPixelSize(R.dimen.taskbar_minimized_app_indicator_width),
+ getResources().getDimensionPixelSize(
+ R.dimen.taskbar_minimized_app_indicator_height));
mRunningAppIndicatorTopMargin =
getResources().getDimensionPixelSize(
R.dimen.taskbar_running_app_indicator_top_margin);
+ mMinimizedAppIndicatorTopMargin =
+ getResources().getDimensionPixelSize(
+ R.dimen.taskbar_minimized_app_indicator_top_margin);
mRunningAppIndicatorPaint = new Paint();
mRunningAppIndicatorPaint.setColor(getResources().getColor(
R.color.taskbar_running_app_indicator_color, context.getTheme()));
@@ -414,8 +432,8 @@
/** Updates whether the app this view represents is currently running. */
@UiThread
- public void updateRunningState(boolean isRunning) {
- mIsRunning = isRunning;
+ public void updateRunningState(RunningAppState runningAppState) {
+ mRunningAppState = runningAppState;
}
protected void setItemInfo(ItemInfoWithIcon itemInfo) {
@@ -667,18 +685,20 @@
/** Draws a line under the app icon if this is representing a running app in Desktop Mode. */
protected void drawRunningAppIndicatorIfNecessary(Canvas canvas) {
- if (!mIsRunning || mDisplay != DISPLAY_TASKBAR) {
+ if (mRunningAppState == RunningAppState.NOT_RUNNING || mDisplay != DISPLAY_TASKBAR) {
return;
}
getIconBounds(mRunningAppIconBounds);
// TODO(b/333872717): update color, shape, and size of indicator
- int indicatorTop = mRunningAppIconBounds.bottom + mRunningAppIndicatorTopMargin;
- canvas.drawRect(
- mRunningAppIconBounds.centerX() - mRunningAppIndicatorSize.getWidth() / 2,
- indicatorTop,
- mRunningAppIconBounds.centerX() + mRunningAppIndicatorSize.getWidth() / 2,
- indicatorTop + mRunningAppIndicatorSize.getHeight(),
- mRunningAppIndicatorPaint);
+ boolean isMinimized = mRunningAppState == RunningAppState.MINIMIZED;
+ int indicatorTop =
+ mRunningAppIconBounds.bottom + (isMinimized ? mMinimizedAppIndicatorTopMargin
+ : mRunningAppIndicatorTopMargin);
+ final Size indicatorSize =
+ isMinimized ? mMinimizedAppIndicatorSize : mRunningAppIndicatorSize;
+ canvas.drawRect(mRunningAppIconBounds.centerX() - indicatorSize.getWidth() / 2,
+ indicatorTop, mRunningAppIconBounds.centerX() + indicatorSize.getWidth() / 2,
+ indicatorTop + indicatorSize.getHeight(), mRunningAppIndicatorPaint);
}
@Override
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index a667c96..0daabb1 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -32,6 +32,7 @@
import static com.android.launcher3.testing.shared.ResourceUtils.INVALID_RESOURCE_HANDLE;
import static com.android.launcher3.testing.shared.ResourceUtils.pxFromDp;
import static com.android.launcher3.testing.shared.ResourceUtils.roundPxValueFromFloat;
+import static com.android.wm.shell.Flags.enableTinyTaskbar;
import android.annotation.SuppressLint;
import android.content.Context;
@@ -353,7 +354,7 @@
isTablet = info.isTablet(windowBounds);
isPhone = !isTablet;
isTwoPanels = isTablet && isMultiDisplay;
- isTaskbarPresent = isTablet
+ isTaskbarPresent = (isTablet || (enableTinyTaskbar() && isGestureMode))
&& WindowManagerProxy.INSTANCE.get(context).isTaskbarDrawnInProcess();
// Some more constants.
@@ -2402,7 +2403,7 @@
mTransposeLayoutWithOrientation = !mInfo.isTablet(mWindowBounds);
}
if (mIsGestureMode == null) {
- mIsGestureMode = mInfo.navigationMode.hasGestures;
+ mIsGestureMode = mInfo.getNavigationMode().hasGestures;
}
if (mDotRendererCache == null) {
mDotRendererCache = new SparseArray<>();
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
index 16630967..a67a362 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
@@ -267,13 +267,15 @@
PrivateProfileManager privateProfileManager = mApps.getPrivateProfileManager();
if (privateProfileManager != null) {
// Set the alpha of the private space icon to 0 upon expanding the header so the
- // alpha can animate -> 1.
+ // alpha can animate -> 1. This should only be in effect when doing a
+ // transitioning between Locked/Unlocked state.
boolean isPrivateSpaceItem =
privateProfileManager.isPrivateSpaceItem(adapterItem);
if (icon.getAlpha() == 0 || icon.getAlpha() == 1) {
icon.setAlpha(isPrivateSpaceItem
- && (privateProfileManager.getAnimationScrolling() ||
- privateProfileManager.getAnimate())
+ && privateProfileManager.isStateTransitioning()
+ && (privateProfileManager.isScrolling() ||
+ privateProfileManager.getReadyToAnimate())
&& privateProfileManager.getCurrentState() == STATE_ENABLED
? 0 : 1);
}
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index 27340a3..a620490 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -114,16 +114,21 @@
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
- mAnimationScrolling = false;
+ mIsScrolling = false;
}
}
};
private Intent mAppInstallerIntent = new Intent();
private PrivateAppsSectionDecorator mPrivateAppsSectionDecorator;
private boolean mPrivateSpaceSettingsAvailable;
+ // Returns if the animation is currently running.
private boolean mIsAnimationRunning;
- private boolean mAnimate;
- private boolean mAnimationScrolling;
+ // mAnimate denotes if private space is ready to be animated.
+ private boolean mReadyToAnimate;
+ // Returns when the recyclerView is currently scrolling.
+ private boolean mIsScrolling;
+ // mIsStateTransitioning indicates that private space is transitioning between states.
+ private boolean mIsStateTransitioning;
private Runnable mOnPSHeaderAdded;
@Nullable
private RelativeLayout mPSHeader;
@@ -230,9 +235,11 @@
if (mPSHeader != null) {
mPSHeader.setAlpha(1);
}
- if (transitioningFromLockedToUnlocked(previousState, updatedState)) {
+ // It's possible that previousState is 0 when reset is first called.
+ mIsStateTransitioning = previousState != STATE_UNKNOWN && previousState != updatedState;
+ if (previousState == STATE_DISABLED && updatedState == STATE_ENABLED) {
postUnlock();
- } else if (transitioningFromUnlockedToLocked(previousState, updatedState)){
+ } else if (previousState == STATE_ENABLED && updatedState == STATE_DISABLED){
executeLock();
}
resetPrivateSpaceDecorator(updatedState);
@@ -321,7 +328,7 @@
@Override
public void setQuietMode(boolean enable) {
super.setQuietMode(enable);
- mAnimate = true;
+ mReadyToAnimate = true;
}
/**
@@ -343,7 +350,7 @@
void setAnimationRunning(boolean isAnimationRunning) {
if (!isAnimationRunning) {
- mAnimate = false;
+ mReadyToAnimate = false;
}
mIsAnimationRunning = isAnimationRunning;
}
@@ -352,14 +359,6 @@
return mIsAnimationRunning;
}
- private boolean transitioningFromLockedToUnlocked(int previousState, int updatedState) {
- return previousState == STATE_DISABLED && updatedState == STATE_ENABLED;
- }
-
- private boolean transitioningFromUnlockedToLocked(int previousState, int updatedState) {
- return previousState == STATE_ENABLED && updatedState == STATE_DISABLED;
- }
-
@Override
public Predicate<UserHandle> getUserMatcher() {
return mPrivateProfileMatcher;
@@ -386,7 +385,7 @@
}
// Set the transition duration for the settings and lock button to animate.
ViewGroup settingAndLockGroup = mPSHeader.findViewById(R.id.settingsAndLockGroup);
- if (mAnimate) {
+ if (mReadyToAnimate) {
enableLayoutTransition(settingAndLockGroup);
} else {
// Ensure any unwanted animations to not happen.
@@ -681,6 +680,7 @@
}
});
animatorSet.addListener(forEndCallback(() -> {
+ mIsStateTransitioning = false;
setAnimationRunning(false);
getMainRecyclerView().setChildAttachedConsumer(child -> child.setAlpha(1));
mStatsLogManager.logger().sendToInteractionJankMonitor(
@@ -712,7 +712,6 @@
animateCollapseAnimation());
}
}
- animatorSet.setDuration(EXPAND_COLLAPSE_DURATION);
animatorSet.start();
}
@@ -773,7 +772,7 @@
public void endTransition(LayoutTransition transition, ViewGroup viewGroup,
View view, int i) {
settingsAndLockGroup.setLayoutTransition(null);
- mAnimate = false;
+ mReadyToAnimate = false;
}
});
settingsAndLockGroup.setLayoutTransition(settingsAndLockTransition);
@@ -873,7 +872,7 @@
/** Starts the smooth scroll with the provided smoothScroller and add idle listener. */
private void startAnimationScroll(AllAppsRecyclerView allAppsRecyclerView,
RecyclerView.LayoutManager layoutManager, RecyclerView.SmoothScroller smoothScroller) {
- mAnimationScrolling = true;
+ mIsScrolling = true;
layoutManager.startSmoothScroll(smoothScroller);
allAppsRecyclerView.removeOnScrollListener(mOnIdleScrollListener);
allAppsRecyclerView.addOnScrollListener(mOnIdleScrollListener);
@@ -887,12 +886,24 @@
return mAllApps.mAH.get(ActivityAllAppsContainerView.AdapterHolder.MAIN).mRecyclerView;
}
- boolean getAnimate() {
- return mAnimate;
+ /** Returns if private space is readily available to be animated. */
+ boolean getReadyToAnimate() {
+ return mReadyToAnimate;
}
- boolean getAnimationScrolling() {
- return mAnimationScrolling;
+ /** Returns when a smooth scroll is happening. */
+ boolean isScrolling() {
+ return mIsScrolling;
+ }
+
+ /**
+ * Returns when private space is in the process of transitioning. This is different from
+ * getAnimate() since mStateTransitioning checks from the time transitioning starts happening
+ * in reset() as oppose to when private space is animating. This should be used to ensure
+ * Private Space state during onBind().
+ */
+ boolean isStateTransitioning() {
+ return mIsStateTransitioning;
}
int getPsHeaderHeight() {
diff --git a/src/com/android/launcher3/allapps/UserProfileManager.java b/src/com/android/launcher3/allapps/UserProfileManager.java
index 3351ee3..eb74d20 100644
--- a/src/com/android/launcher3/allapps/UserProfileManager.java
+++ b/src/com/android/launcher3/allapps/UserProfileManager.java
@@ -40,11 +40,13 @@
* {@link PrivateProfileManager} which manages private profile state.
*/
public abstract class UserProfileManager {
+ public static final int STATE_UNKNOWN = 0;
public static final int STATE_ENABLED = 1;
public static final int STATE_DISABLED = 2;
public static final int STATE_TRANSITION = 3;
@IntDef(value = {
+ STATE_UNKNOWN,
STATE_ENABLED,
STATE_DISABLED,
STATE_TRANSITION
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 92fc38f..21eee55 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -170,7 +170,7 @@
* Returns the current navigation mode
*/
public static NavigationMode getNavigationMode(Context context) {
- return INSTANCE.get(context).getInfo().navigationMode;
+ return INSTANCE.get(context).getInfo().getNavigationMode();
}
/**
@@ -302,7 +302,7 @@
Info newInfo = new Info(displayInfoContext, wmProxy, oldInfo.mPerDisplayBounds);
if (newInfo.densityDpi != oldInfo.densityDpi || newInfo.fontScale != oldInfo.fontScale
- || newInfo.navigationMode != oldInfo.navigationMode) {
+ || newInfo.getNavigationMode() != oldInfo.getNavigationMode()) {
// Cache may not be valid anymore, recreate without cache
newInfo = new Info(displayInfoContext, wmProxy,
wmProxy.estimateInternalDisplayBounds(displayInfoContext));
@@ -318,7 +318,7 @@
if (newInfo.densityDpi != oldInfo.densityDpi || newInfo.fontScale != oldInfo.fontScale) {
change |= CHANGE_DENSITY;
}
- if (newInfo.navigationMode != oldInfo.navigationMode) {
+ if (newInfo.getNavigationMode() != oldInfo.getNavigationMode()) {
change |= CHANGE_NAVIGATION_MODE;
}
if (!newInfo.supportedBounds.equals(oldInfo.supportedBounds)
@@ -369,7 +369,7 @@
// Configuration property
public final float fontScale;
private final int densityDpi;
- public final NavigationMode navigationMode;
+ private final NavigationMode navigationMode;
private final PortraitSize mScreenSizeDp;
// WindowBounds
@@ -553,7 +553,7 @@
pw.println(" rotation=" + info.rotation);
pw.println(" fontScale=" + info.fontScale);
pw.println(" densityDpi=" + info.densityDpi);
- pw.println(" navigationMode=" + info.navigationMode.name());
+ pw.println(" navigationMode=" + info.getNavigationMode().name());
pw.println(" isTaskbarPinned=" + info.mIsTaskbarPinned);
pw.println(" isTaskbarPinnedInDesktopMode=" + info.mIsTaskbarPinnedInDesktopMode);
pw.println(" isInDesktopMode=" + info.mIsInDesktopMode);
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index 5ce455a..85aad89 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -92,7 +92,7 @@
protected @NonNull AnimatorPlaybackController mOpenCloseAnimation;
protected ViewGroup mContent;
- protected final View mColorScrim;
+ protected final @Nullable View mColorScrim;
/**
* Interpolator for {@link #mOpenCloseAnimation} when we are closing due to dragging downwards.
@@ -216,6 +216,9 @@
animation.addFloat(
this, TRANSLATION_SHIFT, fromTranslationShift, toTranslationShift, LINEAR);
+ if (mColorScrim != null) {
+ animation.setViewAlpha(mColorScrim, 1 - toTranslationShift, getScrimInterpolator());
+ }
onOpenCloseAnimationPending(animation);
mOpenCloseAnimation = animation.createPlaybackController();
@@ -254,9 +257,6 @@
protected void setTranslationShift(float translationShift) {
mTranslationShift = translationShift;
mContent.setTranslationY(mTranslationShift * getShiftRange());
- if (mColorScrim != null) {
- mColorScrim.setAlpha(1 - mTranslationShift);
- }
invalidate();
}
@@ -500,6 +500,10 @@
return Interpolators.ACCELERATE;
}
+ protected Interpolator getScrimInterpolator() {
+ return LINEAR;
+ }
+
protected void onCloseComplete() {
mIsOpen = false;
getPopupContainer().removeView(this);
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index df8f635..cdbd0c0 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -109,6 +109,13 @@
private float mLastTouchY;
private boolean mIsDragging;
+ /**
+ * Tracks whether a keyboard hide request has been sent due to downward scrolling.
+ * <p>
+ * Set to true when scrolling down and reset when scrolling up to prevents redundant hide
+ * requests during continuous downward scrolls.
+ */
+ private boolean mRequestedHideKeyboard;
private boolean mIsThumbDetached;
private final boolean mCanThumbDetach;
private boolean mIgnoreDragGesture;
@@ -241,6 +248,7 @@
public boolean handleTouchEvent(MotionEvent ev, Point offset) {
int x = (int) ev.getX() - offset.x;
int y = (int) ev.getY() - offset.y;
+ ActivityContext activityContext = ActivityContext.lookupContext(getContext());
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
@@ -248,6 +256,7 @@
mDownX = x;
mDownY = mLastY = y;
mDownTimeStampMillis = ev.getDownTime();
+ mRequestedHideKeyboard = false;
if ((Math.abs(mDy) < mDeltaThreshold &&
mRv.getScrollState() != SCROLL_STATE_IDLE)) {
@@ -260,6 +269,15 @@
}
break;
case MotionEvent.ACTION_MOVE:
+ if (y > mLastY) {
+ if (!mRequestedHideKeyboard) {
+ activityContext.hideKeyboard();
+ }
+ mRequestedHideKeyboard = true;
+ } else {
+ mRequestedHideKeyboard = false;
+ }
+
mLastY = y;
int absDeltaY = Math.abs(y - mDownY);
int absDeltaX = Math.abs(x - mDownX);
@@ -294,7 +312,6 @@
}
private void calcTouchOffsetAndPrepToFastScroll(int downY, int lastY) {
- ActivityContext.lookupContext(getContext()).hideKeyboard();
mIsDragging = true;
if (mCanThumbDetach) {
mIsThumbDetached = true;
diff --git a/tests/Android.bp b/tests/Android.bp
index 5794cce..1dcb2a6 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -198,6 +198,9 @@
"androidx.test.uiautomator_uiautomator",
"androidx.core_core-animation-testing",
"androidx.test.ext.junit",
+ "androidx.test.espresso.core",
+ "androidx.test.espresso.contrib",
+ "androidx.test.espresso.intents",
"androidx.test.rules",
"uiautomator-helpers",
"inline-mockito-robolectric-prebuilt",
@@ -217,4 +220,5 @@
],
instrumentation_for: "Launcher3",
upstream: true,
+ strict_mode: false,
}
diff --git a/tests/src/com/android/launcher3/settings/SettingsActivityTest.java b/tests/multivalentTests/src/com/android/launcher3/settings/SettingsActivityTest.java
similarity index 100%
rename from tests/src/com/android/launcher3/settings/SettingsActivityTest.java
rename to tests/multivalentTests/src/com/android/launcher3/settings/SettingsActivityTest.java
diff --git a/tests/multivalentTestsForDeviceless b/tests/multivalentTestsForDeviceless
deleted file mode 120000
index 20ee34a..0000000
--- a/tests/multivalentTestsForDeviceless
+++ /dev/null
@@ -1 +0,0 @@
-multivalentTests
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/dragging/TaplDragTest.java b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
index 1c41ded..d43402b 100644
--- a/tests/src/com/android/launcher3/dragging/TaplDragTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
@@ -221,24 +221,7 @@
public void testDragAppIconToMultipleWorkspaceCells() throws Exception {
long startTime, endTime, elapsedTime;
Point[] targets = TestUtil.getCornersAndCenterPositions(mLauncher);
-
- for (Point target : targets) {
- startTime = SystemClock.uptimeMillis();
- final HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
- allApps.freeze();
- try {
- allApps.getAppIcon(TEST_APP_NAME).dragToWorkspace(target.x, target.y);
- } finally {
- allApps.unfreeze();
- }
- // Reset the workspace for the next shortcut creation.
- reinitializeLauncherData(true);
- endTime = SystemClock.uptimeMillis();
- elapsedTime = endTime - startTime;
- Log.d("testDragAppIconToWorkspaceCellTime",
- "Milliseconds taken to drag app icon to workspace cell: " + elapsedTime);
- }
-
+ reinitializeLauncherData(true);
// test to move a shortcut to other cell.
final HomeAppIcon launcherTestAppIcon = createShortcutInCenterIfNotExist(TEST_APP_NAME);
for (Point target : targets) {
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 2e3944d..e10893e 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -359,21 +359,6 @@
}
/**
- * Gets Overview Actions specific to grouped tasks.
- *
- * @return The Overview group actions bar
- */
- @NonNull
- public OverviewActions getOverviewGroupActions() {
- try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
- "want to get overview group actions")) {
- verifyActiveContainer();
- UiObject2 groupActions = mLauncher.waitForOverviewObject("group_action_buttons");
- return new OverviewActions(groupActions, mLauncher);
- }
- }
-
- /**
* Returns if clear all button is visible.
*/
public boolean isClearAllVisible() {
@@ -469,13 +454,13 @@
if (isActionsViewVisible()) {
if (task.isTaskSplit()) {
- mLauncher.waitForOverviewObject("group_action_buttons");
+ mLauncher.waitForOverviewObject("action_save_app_pair");
} else {
mLauncher.waitForOverviewObject("action_buttons");
}
} else {
mLauncher.waitUntilOverviewObjectGone("action_buttons");
- mLauncher.waitUntilOverviewObjectGone("group_action_buttons");
+ mLauncher.waitUntilOverviewObjectGone("action_save_app_pair");
}
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 68b0a36..d85f630 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -711,7 +711,7 @@
final LogEventChecker eventChecker = mEventChecker;
mEventChecker = null;
if (checkEvents) {
- final String eventMismatch = eventChecker.verify(0, false);
+ final String eventMismatch = eventChecker.verify(0);
if (eventMismatch != null) {
message = message + ";\n" + eventMismatch;
}
@@ -2408,7 +2408,7 @@
if (mEventChecker != null) {
mEventChecker = null;
if (mCheckEventsForSuccessfulGestures) {
- final String message = eventChecker.verify(WAIT_TIME_MS, true);
+ final String message = eventChecker.verify(WAIT_TIME_MS);
if (message != null) {
dumpDiagnostics(message);
checkForAnomaly();
diff --git a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
index 672c6e0..055a357 100644
--- a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
+++ b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
@@ -15,10 +15,6 @@
*/
package com.android.launcher3.tapl;
-import static com.android.launcher3.testing.shared.TestProtocol.SEQUENCE_MAIN;
-import static com.android.launcher3.testing.shared.TestProtocol.SEQUENCE_PILFER;
-import static com.android.launcher3.testing.shared.TestProtocol.SEQUENCE_TIS;
-
import android.os.SystemClock;
import com.android.launcher3.testing.shared.TestProtocol;
@@ -87,25 +83,11 @@
mLauncher.getTestInfo(TestProtocol.REQUEST_STOP_EVENT_LOGGING);
}
- String verify(long waitForExpectedCountMs, boolean successfulGesture) {
+ String verify(long waitForExpectedCountMs) {
final ListMap<String> actualEvents = finishSync(waitForExpectedCountMs);
if (actualEvents == null) return "null event sequences because launcher likely died";
- final String lowLevelDiags = lowLevelMismatchDiagnostics(actualEvents);
- // If we have a sequence mismatch for a successful gesture, we want to provide all low-level
- // details.
- if (successfulGesture) {
- return lowLevelDiags;
- }
-
- final String sequenceMismatchInEnglish = highLevelMismatchDiagnostics(actualEvents);
-
- if (sequenceMismatchInEnglish != null) {
- LauncherInstrumentation.log(lowLevelDiags);
- return "Hint: " + sequenceMismatchInEnglish;
- } else {
- return lowLevelDiags;
- }
+ return lowLevelMismatchDiagnostics(actualEvents);
}
private String lowLevelMismatchDiagnostics(ListMap<String> actualEvents) {
@@ -140,42 +122,6 @@
return hasMismatches ? "Mismatching events: " + sb.toString() : null;
}
- private String highLevelMismatchDiagnostics(ListMap<String> actualEvents) {
- if (!mExpectedEvents.getNonNull(SEQUENCE_TIS).isEmpty()
- && actualEvents.getNonNull(SEQUENCE_TIS).isEmpty()) {
- return "TouchInteractionService didn't receive any of the touch events sent by the "
- + "test";
- }
- if (getMismatchPosition(mExpectedEvents.getNonNull(SEQUENCE_TIS),
- actualEvents.getNonNull(SEQUENCE_TIS)) != -1) {
- // If TIS has a mismatch that we can't convert to high-level diags, don't convert
- // other sequences either.
- return null;
- }
-
- if (mExpectedEvents.getNonNull(SEQUENCE_PILFER).size() == 1
- && actualEvents.getNonNull(SEQUENCE_PILFER).isEmpty()) {
- return "Launcher didn't detect the navigation gesture sent by the test";
- }
- if (mExpectedEvents.getNonNull(SEQUENCE_PILFER).isEmpty()
- && actualEvents.getNonNull(SEQUENCE_PILFER).size() == 1) {
- return "Launcher detected a navigation gesture, but the test didn't send one";
- }
- if (getMismatchPosition(mExpectedEvents.getNonNull(SEQUENCE_PILFER),
- actualEvents.getNonNull(SEQUENCE_PILFER)) != -1) {
- // If Pilfer has a mismatch that we can't convert to high-level diags, don't analyze
- // other sequences.
- return null;
- }
-
- if (!mExpectedEvents.getNonNull(SEQUENCE_MAIN).isEmpty()
- && actualEvents.getNonNull(SEQUENCE_MAIN).isEmpty()) {
- return "None of the touch or keyboard events sent by the test was received by "
- + "Launcher's main thread";
- }
- return null;
- }
-
// If the list of actual events matches the list of expected events, returns -1, otherwise
// the position of the mismatch.
private static int getMismatchPosition(List<Pattern> expected, List<String> actual) {
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewActions.java b/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
index 486a63b..d7c40a0 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
@@ -17,7 +17,6 @@
package com.android.launcher3.tapl;
import androidx.annotation.NonNull;
-import androidx.test.uiautomator.By;
import androidx.test.uiautomator.UiObject2;
/**
@@ -111,12 +110,4 @@
}
}
}
-
- /** Asserts that an item matching the given string is present in the overview actions. */
- public void assertHasAction(String text) {
- try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
- "want to check if the action [" + text + "] is present")) {
- mLauncher.waitForObjectInContainer(mOverviewActions, By.text(text));
- }
- }
}