Merge "Don't show fastScrollBar when collapsing" into main
diff --git a/Android.bp b/Android.bp
index 4354b66..8f2e5a6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -204,6 +204,7 @@
"com_android_launcher3_flags_lib",
"com_android_wm_shell_flags_lib",
"android.appwidget.flags-aconfig-java",
+ "com.android.window.flags.window-aconfig-java",
],
sdk_version: "current",
min_sdk_version: min_launcher3_sdk_version,
diff --git a/aconfig/Android.bp b/aconfig/Android.bp
index 5413601..bca7494 100644
--- a/aconfig/Android.bp
+++ b/aconfig/Android.bp
@@ -20,7 +20,7 @@
aconfig_declarations {
name: "com_android_launcher3_flags",
package: "com.android.launcher3",
- container: "system",
+ container: "system_ext",
srcs: ["**/*.aconfig"],
}
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 147cac6..a37141c 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -1,5 +1,5 @@
package: "com.android.launcher3"
-container: "system"
+container: "system_ext"
flag {
name: "enable_expanding_pause_work_button"
@@ -186,3 +186,23 @@
description: "Use an activity for home screen overlay"
bug: "273828110"
}
+
+flag {
+ name: "grid_migration_fix"
+ namespace: "launcher"
+ description: "Keep items in place when migrating to a bigger grid"
+ bug: "325286145"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "narrow_grid_restore"
+ namespace: "launcher"
+ description: "Using only the most recent workspace when restoring to avoid confusion."
+ bug: "325285743"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/aconfig/launcher_search.aconfig b/aconfig/launcher_search.aconfig
index 2f2690e..31d8d34 100644
--- a/aconfig/launcher_search.aconfig
+++ b/aconfig/launcher_search.aconfig
@@ -1,5 +1,5 @@
package: "com.android.launcher3"
-container: "system"
+container: "system_ext"
flag {
name: "enable_private_space"
@@ -41,4 +41,4 @@
namespace: "launcher_search"
description: "This flag disables drag and drop for Private Space Items."
bug: "289223923"
-}
\ No newline at end of file
+}
diff --git a/quickstep/res/layout/task_menu.xml b/quickstep/res/layout/task_menu.xml
index 622edfe..b6d8786 100644
--- a/quickstep/res/layout/task_menu.xml
+++ b/quickstep/res/layout/task_menu.xml
@@ -35,11 +35,17 @@
android:paddingBottom="@dimen/task_menu_edge_padding"
android:textSize="16sp"/>
- <LinearLayout
- android:id="@+id/menu_option_layout"
+ <ScrollView
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:showDividers="middle" />
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:id="@+id/menu_option_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:showDividers="middle" />
+
+ </ScrollView>
</com.android.quickstep.views.TaskMenuView>
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 853ac74..3331321 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -401,6 +401,9 @@
<dimen name="taskbar_pinning_popup_menu_width">300dp</dimen>
<dimen name="taskbar_pinning_popup_menu_vertical_margin">16dp</dimen>
+ <!--- Floating Ime Inset height-->
+ <dimen name="floating_ime_inset_height">60dp</dimen>
+
<!-- Recents overview -->
<dimen name="recents_filter_icon_size">30dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index 842f0ef..15180ef 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -35,7 +35,7 @@
import androidx.annotation.UiThread;
import com.android.systemui.animation.RemoteAnimationDelegate;
-import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
+import com.android.systemui.animation.RemoteAnimationRunnerCompat;
import java.lang.ref.WeakReference;
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 2a6e37d..75b8796c 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -161,10 +161,10 @@
import com.android.systemui.animation.DelegateTransitionAnimatorController;
import com.android.systemui.animation.LaunchableView;
import com.android.systemui.animation.RemoteAnimationDelegate;
+import com.android.systemui.animation.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.system.BlurUtils;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.wm.shell.startingsurface.IStartingWindowListener;
import java.io.PrintWriter;
diff --git a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
index 68e7824..8c4db4a 100644
--- a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
+++ b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
@@ -219,7 +219,9 @@
final boolean isHorizontallyResizable =
(info.resizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0;
if (mDesiredWidgetWidth > 0 && isHorizontallyResizable) {
- if (info.maxResizeWidth > 0 && info.maxResizeWidth < mDesiredWidgetWidth) {
+ if (info.maxResizeWidth > 0
+ && info.maxResizeWidth >= info.minWidth
+ && info.maxResizeWidth < mDesiredWidgetWidth) {
return rejectWidget(
widget,
"maxResizeWidth[%d] < mDesiredWidgetWidth[%d]",
@@ -227,12 +229,13 @@
mDesiredWidgetWidth);
}
- final int minWidth = info.minResizeWidth > 0 ? info.minResizeWidth : info.minWidth;
+ final int minWidth = Math.min(info.minResizeWidth, info.minWidth);
if (minWidth > mDesiredWidgetWidth) {
return rejectWidget(
widget,
- "minWidth[%d] > mDesiredWidgetWidth[%d]",
- minWidth,
+ "min(minWidth[%d], minResizeWidth[%d]) > mDesiredWidgetWidth[%d]",
+ info.minWidth,
+ info.minResizeWidth,
mDesiredWidgetWidth);
}
}
@@ -240,7 +243,9 @@
final boolean isVerticallyResizable =
(info.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0;
if (mDesiredWidgetHeight > 0 && isVerticallyResizable) {
- if (info.maxResizeHeight > 0 && info.maxResizeHeight < mDesiredWidgetHeight) {
+ if (info.maxResizeHeight > 0
+ && info.maxResizeHeight >= info.minHeight
+ && info.maxResizeHeight < mDesiredWidgetHeight) {
return rejectWidget(
widget,
"maxResizeHeight[%d] < mDesiredWidgetHeight[%d]",
@@ -248,20 +253,19 @@
mDesiredWidgetHeight);
}
- final int minHeight = info.minResizeHeight > 0 ? info.minResizeHeight : info.minHeight;
+ final int minHeight = Math.min(info.minResizeHeight, info.minHeight);
if (minHeight > mDesiredWidgetHeight) {
return rejectWidget(
widget,
- "minHeight[%d] > mDesiredWidgetHeight[%d]",
- minHeight,
+ "min(minHeight[%d], minResizeHeight[%d]) > mDesiredWidgetHeight[%d]",
+ info.minHeight,
+ info.minResizeHeight,
mDesiredWidgetHeight);
}
}
- if (!isHorizontallyResizable
- && !isVerticallyResizable
- && (info.minWidth < mDesiredWidgetWidth || info.minHeight < mDesiredWidgetHeight)) {
- return rejectWidget(widget, "too small and not resizeable");
+ if (!isHorizontallyResizable || !isVerticallyResizable) {
+ return rejectWidget(widget, "not resizeable");
}
return acceptWidget(widget);
@@ -271,12 +275,15 @@
WidgetItem widget, String rejectionReason, Object... args) {
return new WidgetAcceptabilityVerdict(
false,
- widget.label,
+ widget.widgetInfo != null
+ ? widget.widgetInfo.provider.flattenToShortString()
+ : widget.label,
String.format(Locale.ENGLISH, rejectionReason, args));
}
private static WidgetAcceptabilityVerdict acceptWidget(WidgetItem widget) {
- return new WidgetAcceptabilityVerdict(true, widget.label, "");
+ return new WidgetAcceptabilityVerdict(
+ true, widget.widgetInfo.provider.flattenToShortString(), "");
}
private record WidgetAcceptabilityVerdict(
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index 2d4894c..4741ddd 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -285,7 +285,8 @@
if (dragLayer != null) {
dragLayer.setVisibility(visibility);
}
- if (mLauncher instanceof QuickstepLauncher ql && ql.getTaskbarUIController() != null) {
+ if (mLauncher instanceof QuickstepLauncher ql && ql.getTaskbarUIController() != null
+ && mVisibleFreeformTasksCount != 0) {
ql.getTaskbarUIController().onLauncherVisibilityChanged(visibility == VISIBLE);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 200ea54..87662e6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -72,6 +72,8 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import androidx.core.graphics.Insets;
+import androidx.core.view.WindowInsetsCompat;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
@@ -418,6 +420,28 @@
}
/**
+ * Returns if software keyboard is docked or input toolbar is placed at the taskbar area
+ */
+ public boolean isImeDocked() {
+ View dragLayer = getDragLayer();
+ WindowInsets insets = dragLayer.getRootWindowInsets();
+ if (insets == null) {
+ return false;
+ }
+
+ WindowInsetsCompat insetsCompat =
+ WindowInsetsCompat.toWindowInsetsCompat(insets, dragLayer.getRootView());
+
+ if (insetsCompat.isVisible(WindowInsetsCompat.Type.ime())) {
+ Insets imeInsets = insetsCompat.getInsets(WindowInsetsCompat.Type.ime());
+ return imeInsets.bottom >= getResources().getDimensionPixelSize(
+ R.dimen.floating_ime_inset_height);
+ } else {
+ return false;
+ }
+ }
+
+ /**
* Show Taskbar upon receiving broadcast
*/
public void showTaskbarFromBroadcast() {
@@ -505,52 +529,26 @@
/**
* Creates {@link WindowManager.LayoutParams} for Taskbar, and also sets LP.paramsForRotation
- * for taskbar showing as navigation bar
+ * for taskbar
*/
private WindowManager.LayoutParams createAllWindowParams() {
final int windowType =
ENABLE_TASKBAR_NAVBAR_UNIFICATION ? TYPE_NAVIGATION_BAR : TYPE_NAVIGATION_BAR_PANEL;
WindowManager.LayoutParams windowLayoutParams =
createDefaultWindowLayoutParams(windowType, TaskbarActivityContext.WINDOW_TITLE);
- if (!isPhoneButtonNavMode()) {
- return windowLayoutParams;
- }
- // Provide WM layout params for all rotations to cache, see NavigationBar#getBarLayoutParams
- int width = WindowManager.LayoutParams.MATCH_PARENT;
- int height = WindowManager.LayoutParams.MATCH_PARENT;
- int gravity = Gravity.BOTTOM;
windowLayoutParams.paramsForRotation = new WindowManager.LayoutParams[4];
for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
WindowManager.LayoutParams lp =
createDefaultWindowLayoutParams(windowType,
TaskbarActivityContext.WINDOW_TITLE);
- switch (rot) {
- case Surface.ROTATION_0, Surface.ROTATION_180 -> {
- // Defaults are fine
- width = WindowManager.LayoutParams.MATCH_PARENT;
- height = mLastRequestedNonFullscreenSize;
- gravity = Gravity.BOTTOM;
- }
- case Surface.ROTATION_90 -> {
- width = mLastRequestedNonFullscreenSize;
- height = WindowManager.LayoutParams.MATCH_PARENT;
- gravity = Gravity.END;
- }
- case Surface.ROTATION_270 -> {
- width = mLastRequestedNonFullscreenSize;
- height = WindowManager.LayoutParams.MATCH_PARENT;
- gravity = Gravity.START;
- }
-
+ if (isPhoneButtonNavMode()) {
+ populatePhoneButtonNavModeWindowLayoutParams(rot, lp);
}
- lp.width = width;
- lp.height = height;
- lp.gravity = gravity;
windowLayoutParams.paramsForRotation[rot] = lp;
}
- // Override current layout params
+ // Override with current layout params
WindowManager.LayoutParams currentParams =
windowLayoutParams.paramsForRotation[getDisplay().getRotation()];
windowLayoutParams.width = currentParams.width;
@@ -560,6 +558,32 @@
return windowLayoutParams;
}
+ /**
+ * Update {@link WindowManager.LayoutParams} with values specific to phone and 3 button
+ * navigation users
+ */
+ private void populatePhoneButtonNavModeWindowLayoutParams(int rot,
+ WindowManager.LayoutParams lp) {
+ lp.width = WindowManager.LayoutParams.MATCH_PARENT;
+ lp.height = WindowManager.LayoutParams.MATCH_PARENT;
+ lp.gravity = Gravity.BOTTOM;
+
+ // Override with per-rotation specific values
+ switch (rot) {
+ case Surface.ROTATION_0, Surface.ROTATION_180 -> {
+ lp.height = mLastRequestedNonFullscreenSize;
+ }
+ case Surface.ROTATION_90 -> {
+ lp.width = mLastRequestedNonFullscreenSize;
+ lp.gravity = Gravity.END;
+ }
+ case Surface.ROTATION_270 -> {
+ lp.width = mLastRequestedNonFullscreenSize;
+ lp.gravity = Gravity.START;
+ }
+ }
+ }
+
public void onConfigurationChanged(@Config int configChanges) {
mControllers.onConfigurationChanged(configChanges);
if (!mIsUserSetupComplete) {
@@ -920,8 +944,10 @@
}
if (landscapePhoneButtonNav) {
mWindowLayoutParams.width = size;
+ mWindowLayoutParams.paramsForRotation[getDisplay().getRotation()].width = size;
} else {
mWindowLayoutParams.height = size;
+ mWindowLayoutParams.paramsForRotation[getDisplay().getRotation()].height = size;
}
mControllers.taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
notifyUpdateLayoutParams();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index f6478df..7f201b4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -30,9 +30,12 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
+import android.view.WindowInsets;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.core.graphics.Insets;
+import androidx.core.view.WindowInsetsCompat;
import com.android.app.viewcapture.SettingsAwareViewCapture;
import com.android.launcher3.AbstractFloatingView;
@@ -111,6 +114,18 @@
}
@Override
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ if (insets != null) {
+ WindowInsetsCompat insetsCompat = WindowInsetsCompat.toWindowInsetsCompat(insets, this);
+ Insets imeInsets = insetsCompat.getInsets(WindowInsetsCompat.Type.ime());
+ if (imeInsets != null) {
+ mControllerCallbacks.onImeInsetChanged();
+ }
+ }
+ return insets;
+ }
+
+ @Override
public void recreateControllers() {
mControllers = mControllerCallbacks.getTouchControllers();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 74eda24..e48c20d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -276,6 +276,13 @@
}
/**
+ * Called when an IME inset is changed.
+ */
+ public void onImeInsetChanged() {
+ mControllers.taskbarStashController.onImeInsetChanged();
+ }
+
+ /**
* Called when a child is removed from TaskbarDragLayer.
*/
public void onDragLayerViewRemoved() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index aa457ca..567fad0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -118,11 +118,9 @@
getProvidedInsets(insetsRoundedCornerFlag)
}
- if (!context.isGestureNav) {
- if (windowLayoutParams.paramsForRotation != null) {
- for (layoutParams in windowLayoutParams.paramsForRotation) {
- layoutParams.providedInsets = getProvidedInsets(insetsRoundedCornerFlag)
- }
+ if (windowLayoutParams.paramsForRotation != null) {
+ for (layoutParams in windowLayoutParams.paramsForRotation) {
+ layoutParams.providedInsets = getProvidedInsets(insetsRoundedCornerFlag)
}
}
@@ -156,19 +154,12 @@
)
}
- val gravity = windowLayoutParams.gravity
-
// Pre-calculate insets for different providers across different rotations for this gravity
for (rotation in Surface.ROTATION_0..Surface.ROTATION_270) {
// Add insets for navbar rotated params
- if (windowLayoutParams.paramsForRotation != null) {
- val layoutParams = windowLayoutParams.paramsForRotation[rotation]
- for (provider in layoutParams.providedInsets) {
- setProviderInsets(provider, layoutParams.gravity, rotation)
- }
- }
- for (provider in windowLayoutParams.providedInsets) {
- setProviderInsets(provider, gravity, rotation)
+ val layoutParams = windowLayoutParams.paramsForRotation[rotation]
+ for (provider in layoutParams.providedInsets) {
+ setProviderInsets(provider, layoutParams.gravity, rotation)
}
}
context.notifyUpdateLayoutParams()
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index c4be85f..854b0d0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -310,8 +310,16 @@
boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivity);
boolean isInSetup = !mActivity.isUserSetupComplete() || setupUIVisible;
- boolean isStashedInAppAuto =
- isTransientTaskbar && !mTaskbarSharedState.getTaskbarWasPinned();
+ boolean taskbarWasPinned = mTaskbarSharedState.getTaskbarWasPinned();
+ boolean isStashedInAppAuto = isTransientTaskbar && !taskbarWasPinned;
+
+ // now that we know we need to keep transient taskbar unstashed after unpinning animation
+ // we need to reset the shared state, so everytime user recreates taskbar we don't unstash
+ // transient taskbar by default.
+ if (mTaskbarSharedState.getTaskbarWasPinned()) {
+ mTaskbarSharedState.setTaskbarWasPinned(false);
+ }
+
if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
isStashedInAppAuto = isStashedInAppAuto && mTaskbarSharedState.taskbarWasStashedAuto;
}
@@ -324,8 +332,7 @@
// us that we're paused until a bit later. This avoids flickering upon recreating taskbar.
updateStateForFlag(FLAG_IN_APP, true);
applyState(/* duration = */ 0);
- if (mTaskbarSharedState.getTaskbarWasPinned()
- || !mTaskbarSharedState.taskbarWasStashedAuto) {
+ if (taskbarWasPinned || !mTaskbarSharedState.taskbarWasStashedAuto) {
tryStartTaskbarTimeout();
}
notifyStashChange(/* visible */ false, /* stashed */ isStashedInApp());
@@ -893,6 +900,10 @@
}
// Only update the following flags when system gesture is not in progress.
+ setStashedImeState();
+ }
+
+ private void setStashedImeState() {
boolean shouldStashForIme = shouldStashForIme();
updateStateForFlag(FLAG_STASHED_IN_TASKBAR_ALL_APPS, false);
if (hasAnyFlag(FLAG_STASHED_IN_APP_IME) != shouldStashForIme) {
@@ -904,6 +915,13 @@
}
/**
+ * Should be called when Ime inset is changed to determine if taskbar should be stashed
+ */
+ public void onImeInsetChanged() {
+ setStashedImeState();
+ }
+
+ /**
* When hiding the IME, delay the unstash animation to align with the end of the transition.
*/
private long getTaskbarStashStartDelayForIme() {
@@ -952,7 +970,7 @@
*
* <p>Do not stash if in small screen, with 3 button nav, and in landscape (or seascape).
* <p>Do not stash if taskbar is transient.
- * <p>Do not stash if hardware keyboard is attached and taskbar is pinned.
+ * <p>Do not stash if hardware keyboard is attached and taskbar is pinned and IME is docked
*/
private boolean shouldStashForIme() {
if (DisplayController.isTransientTaskbar(mActivity)) {
@@ -963,8 +981,10 @@
&& mActivity.getDeviceProfile().isLandscape) {
return false;
}
- // Do not stash if pinned taskbar and hardware keyboard is attached.
- if (mActivity.isHardwareKeyboard() && DisplayController.isPinnedTaskbar(mActivity)) {
+
+ // Do not stash if pinned taskbar, hardware keyboard is attached and no IME is docked
+ if (mActivity.isHardwareKeyboard() && DisplayController.isPinnedTaskbar(mActivity)
+ && !mActivity.isImeDocked()) {
return false;
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
index 5c4eb9d..dcc3b05 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -21,6 +21,7 @@
import android.app.Person;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.LauncherUserInfo;
@@ -156,6 +157,13 @@
}
}
+ /**
+ * Checks if an activity is flagged as non-resizeable.
+ */
+ public static boolean isNonResizeableActivity(LauncherActivityInfo lai) {
+ return lai.getActivityInfo().resizeMode == ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+ }
+
private static class NoopDrawable extends ColorDrawable {
@Override
public int getIntrinsicHeight() {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index dbaeafb..2eced74 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -112,7 +112,8 @@
boolean exitingOverview = !FeatureFlags.enableSplitContextually() && !toState.overviewUi;
if (mRecentsView.isSplitSelectionActive() && exitingOverview) {
setter.add(mRecentsView.getSplitSelectController().getSplitAnimationController()
- .createPlaceholderDismissAnim(mLauncher, LAUNCHER_SPLIT_SELECTION_EXIT_HOME));
+ .createPlaceholderDismissAnim(mLauncher, LAUNCHER_SPLIT_SELECTION_EXIT_HOME,
+ setter.getDuration()));
setter.setViewAlpha(
mRecentsView.getSplitInstructionsView(),
0,
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 93ee76e..2c45129 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -200,7 +200,7 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
@@ -599,9 +599,10 @@
ArrayList<TouchController> list = new ArrayList<>();
list.add(getDragController());
- Consumer<AnimatorSet> splitAnimator = animatorSet ->
+ BiConsumer<AnimatorSet, Long> splitAnimator = (animatorSet, duration) ->
animatorSet.play(mSplitSelectStateController.getSplitAnimationController()
- .createPlaceholderDismissAnim(this, LAUNCHER_SPLIT_SELECTION_EXIT_HOME));
+ .createPlaceholderDismissAnim(this, LAUNCHER_SPLIT_SELECTION_EXIT_HOME,
+ duration));
switch (mode) {
case NO_BUTTON:
list.add(new NoButtonQuickSwitchTouchController(this));
@@ -650,10 +651,13 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ // Back dispatcher is registered in {@link BaseActivity#onCreate}. For predictive back to
+ // work, we must opt-in BEFORE registering back dispatcher. So we need to call
+ // setEnableOnBackInvokedCallback() before super.onCreate()
if (Utilities.ATLEAST_U && enablePredictiveBackGesture()) {
getApplicationInfo().setEnableOnBackInvokedCallback(true);
}
+ super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mPendingSplitSelectInfo = ObjectWrapper.unwrap(
savedInstanceState.getIBinder(PENDING_SPLIT_SELECT_INFO));
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index 82a9c05..e8b5081 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -54,7 +54,7 @@
import com.android.quickstep.util.OverviewToHomeAnim;
import com.android.quickstep.views.RecentsView;
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
/**
* Handles swiping up on the nav bar to go home from launcher, e.g. overview or all apps.
@@ -67,7 +67,7 @@
private static final float OVERVIEW_TO_HOME_SCRIM_MULTIPLIER = 0.5f;
private final Launcher mLauncher;
- private final Consumer<AnimatorSet> mCancelSplitRunnable;
+ private final BiConsumer<AnimatorSet, Long> mCancelSplitRunnable;
private final SingleAxisSwipeDetector mSwipeDetector;
private final float mPullbackDistance;
@@ -81,7 +81,7 @@
* Animation should be added to the provided AnimatorSet
*/
public NavBarToHomeTouchController(Launcher launcher,
- Consumer<AnimatorSet> cancelSplitRunnable) {
+ BiConsumer<AnimatorSet, Long> cancelSplitRunnable) {
mLauncher = launcher;
mCancelSplitRunnable = cancelSplitRunnable;
mSwipeDetector = new SingleAxisSwipeDetector(mLauncher, this,
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index fc3eeba..26e994f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -56,7 +56,7 @@
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
/**
* Touch controller which handles swipe and hold from the nav bar to go to Overview. Swiping above
@@ -72,7 +72,7 @@
private static final float TRANSLATION_ANIM_VELOCITY_DP_PER_MS = 0.8f;
private final VibratorWrapper mVibratorWrapper;
- private final Consumer<AnimatorSet> mCancelSplitRunnable;
+ private final BiConsumer<AnimatorSet, Long> mCancelSplitRunnable;
private final RecentsView mRecentsView;
private final MotionPauseDetector mMotionPauseDetector;
private final float mMotionPauseMinDisplacement;
@@ -93,7 +93,7 @@
* Animation should be added to the provided AnimatorSet
*/
public NoButtonNavbarToOverviewTouchController(Launcher l,
- Consumer<AnimatorSet> cancelSplitRunnable) {
+ BiConsumer<AnimatorSet, Long> cancelSplitRunnable) {
super(l);
mRecentsView = l.getOverviewPanel();
mMotionPauseDetector = new MotionPauseDetector(l);
@@ -208,9 +208,10 @@
// Normally we compute the duration based on the velocity and distance to the given
// state, but since the hint state tracks the entire screen without a clear endpoint, we
// need to manually set the duration to a reasonable value.
- animator.setDuration(HINT_STATE.getTransitionDuration(mLauncher, true /* isToState */));
+ long duration = HINT_STATE.getTransitionDuration(mLauncher, true /* isToState */);
+ animator.setDuration(duration);
AnimatorSet animatorSet = new AnimatorSet();
- mCancelSplitRunnable.accept(animatorSet);
+ mCancelSplitRunnable.accept(animatorSet, duration);
animatorSet.start();
}
if (FeatureFlags.ENABLE_PREMIUM_HAPTICS_ALL_APPS.get() &&
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index b7a907f..a92e77a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -324,12 +324,12 @@
@Override
public void onDragEnd(PointF velocity) {
+ cancelAnimations();
boolean horizontalFling = mSwipeDetector.isFling(velocity.x);
boolean verticalFling = mSwipeDetector.isFling(velocity.y);
boolean noFling = !horizontalFling && !verticalFling;
if (mMotionPauseDetector.isPaused() && noFling) {
// Going to Overview.
- cancelAnimations();
InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_QUICK_SWITCH);
StateAnimationConfig config = new StateAnimationConfig();
@@ -455,7 +455,6 @@
nonOverviewAnim.setDuration(Math.max(xDuration, yDuration));
mNonOverviewAnim.setEndAction(() -> onAnimationToStateCompleted(targetState));
- cancelAnimations();
xOverviewAnim.start();
yOverviewAnim.start();
nonOverviewAnim.start();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index ef5096b..e9f2d4f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -21,7 +21,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.os.SystemClock;
import android.os.VibrationEffect;
import android.view.MotionEvent;
import android.view.View;
@@ -80,6 +79,7 @@
private float mDisplacementShift;
private float mProgressMultiplier;
private float mEndDisplacement;
+ private boolean mDraggingEnabled = true;
private FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck();
private Float mOverrideVelocity = null;
@@ -270,6 +270,8 @@
@Override
public void onDragStart(boolean start, float startDisplacement) {
+ if (!mDraggingEnabled) return;
+
RecentsPagedOrientationHandler orientationHandler =
mRecentsView.getPagedOrientationHandler();
if (mCurrentAnimation == null) {
@@ -285,6 +287,8 @@
@Override
public boolean onDrag(float displacement) {
+ if (!mDraggingEnabled) return true;
+
RecentsPagedOrientationHandler orientationHandler =
mRecentsView.getPagedOrientationHandler();
float totalDisplacement = displacement + mDisplacementShift;
@@ -317,12 +321,9 @@
mOverrideVelocity = -mTaskBeingDragged.getResources().getDimension(velocityDimenId);
// Once halfway through task dismissal interpolation, switch from reversible
- // dragging-task animation to playing the remaining task translation animations
- final long now = SystemClock.uptimeMillis();
- MotionEvent upAction = MotionEvent.obtain(now, now,
- MotionEvent.ACTION_UP, 0.0f, 0.0f, 0);
- mDetector.onTouchEvent(upAction);
- upAction.recycle();
+ // dragging-task animation to playing the remaining task translation animations,
+ // while this is in progress disable dragging.
+ mDraggingEnabled = false;
}
} else {
mCurrentAnimation.setPlayFraction(
@@ -343,7 +344,7 @@
R.dimen.max_task_dismiss_drag_velocity);
velocity = Utilities.boundToRange(velocity, -maxTaskDismissDragVelocity,
maxTaskDismissDragVelocity);
- boolean fling = mDetector.isFling(velocity);
+ boolean fling = mDraggingEnabled && mDetector.isFling(velocity);
final boolean goingToEnd;
boolean blockedFling = fling && mFlingBlockCheck.isBlocked();
if (blockedFling) {
@@ -371,19 +372,21 @@
MIN_TASK_DISMISS_ANIMATION_DURATION, MAX_TASK_DISMISS_ANIMATION_DURATION);
mCurrentAnimation.setEndAction(this::clearState);
- mCurrentAnimation.startWithVelocity(mActivity, goingToEnd,
- velocity * orientationHandler.getSecondaryTranslationDirectionFactor(),
+ mCurrentAnimation.startWithVelocity(mActivity, goingToEnd, Math.abs(velocity),
mEndDisplacement, animationDuration);
if (goingUp && goingToEnd && !mIsDismissHapticRunning) {
VibratorWrapper.INSTANCE.get(mActivity).vibrate(TASK_DISMISS_VIBRATION_PRIMITIVE,
TASK_DISMISS_VIBRATION_PRIMITIVE_SCALE, TASK_DISMISS_VIBRATION_FALLBACK);
mIsDismissHapticRunning = true;
}
+
+ mDraggingEnabled = true;
}
private void clearState() {
mDetector.finishedScrolling();
mDetector.setDetectableScrollConditions(0, false);
+ mDraggingEnabled = true;
mTaskBeingDragged = null;
mCurrentAnimation = null;
mIsDismissHapticRunning = false;
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 8535a33..c3a4351 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -187,7 +187,10 @@
// Allow null-pointer to catch illegal states.
runOnTISBinder(tisBinder -> tisBinder.getTaskbarManager().recreateTaskbar());
return response;
-
+ case TestProtocol.REQUEST_TASKBAR_IME_DOCKED:
+ return getTISBinderUIProperty(Bundle::putBoolean, tisBinder ->
+ tisBinder.getTaskbarManager()
+ .getCurrentActivityContext().isImeDocked());
case TestProtocol.REQUEST_UNSTASH_BUBBLE_BAR_IF_STASHED:
runOnTISBinder(tisBinder -> {
// Allow null-pointer to catch illegal states.
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index a1a3145..4e62d60 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -115,7 +115,6 @@
ActiveGestureLog.INSTANCE.addLog(
/* event= */ "startRecentsAnimation",
/* gestureEvent= */ START_RECENTS_ANIMATION);
- mRecentsAnimationStartPending = true;
// Notify if recents animation is still running
if (mController != null) {
String msg = "New recents animation started before old animation completed";
@@ -300,10 +299,16 @@
options.setTransientLaunch();
}
options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime);
- SystemUiProxy.INSTANCE.getNoCreate().startRecentsActivity(intent, options, mCallbacks);
+ mRecentsAnimationStartPending = SystemUiProxy.INSTANCE.getNoCreate()
+ .startRecentsActivity(intent, options, mCallbacks);
} else {
- UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance()
- .startRecentsActivity(intent, eventTime, mCallbacks, null, null));
+ UI_HELPER_EXECUTOR.execute(
+ () -> ActivityManagerWrapper.getInstance().startRecentsActivity(
+ intent,
+ eventTime,
+ mCallbacks,
+ result -> mRecentsAnimationStartPending = result,
+ MAIN_EXECUTOR.getHandler()));
}
gestureState.setState(STATE_RECENTS_ANIMATION_INITIALIZED);
return mCallbacks;
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 03e6c99..e30ea7a 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -82,9 +82,9 @@
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskThumbnailView;
import com.android.quickstep.views.TaskView;
+import com.android.systemui.animation.RemoteAnimationTargetCompat;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
-import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import java.util.ArrayList;
import java.util.List;
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index ce8df9b..ef6e085 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -113,7 +113,7 @@
public void saveAppPair(GroupedTaskView gtv) {
TaskView.TaskIdAttributeContainer[] attributes = gtv.getTaskIdAttributeContainers();
WorkspaceItemInfo recentsInfo1 = attributes[0].getItemInfo();
- WorkspaceItemInfo recentsInfo2 = attributes[0].getItemInfo();
+ WorkspaceItemInfo recentsInfo2 = attributes[1].getItemInfo();
WorkspaceItemInfo app1 = lookupLaunchableItem(recentsInfo1.getComponentKey());
WorkspaceItemInfo app2 = lookupLaunchableItem(recentsInfo2.getComponentKey());
diff --git a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
index 6d9ecd9..132d1c1 100644
--- a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
+++ b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
@@ -30,7 +30,7 @@
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.states.StateAnimationConfig;
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
/**
* Runs an animation from overview to home. Currently, this animation is just a wrapper around the
@@ -44,14 +44,14 @@
private final Launcher mLauncher;
private final Runnable mOnReachedHome;
@Nullable
- private final Consumer<AnimatorSet> mSplitCancelConsumer;
+ private final BiConsumer<AnimatorSet, Long> mSplitCancelConsumer;
// Only run mOnReachedHome when both of these are true.
private boolean mIsHomeStaggeredAnimFinished;
private boolean mIsOverviewHidden;
public OverviewToHomeAnim(Launcher launcher, Runnable onReachedHome,
- @Nullable Consumer<AnimatorSet> splitCancelConsumer) {
+ @Nullable BiConsumer<AnimatorSet, Long> splitCancelConsumer) {
mLauncher = launcher;
mOnReachedHome = onReachedHome;
mSplitCancelConsumer = splitCancelConsumer;
@@ -103,7 +103,7 @@
if (mSplitCancelConsumer != null) {
// Clear split state when swiping to home
- mSplitCancelConsumer.accept(anim);
+ mSplitCancelConsumer.accept(anim, config.duration);
}
anim.play(stateAnim);
stateManager.setCurrentAnimation(anim, NORMAL);
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index 1eb71fc..b7b1d8f 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -242,7 +242,7 @@
return
}
- val anim = createPlaceholderDismissAnim(launcher, splitDismissEvent)
+ val anim = createPlaceholderDismissAnim(launcher, splitDismissEvent, null /*duration*/)
anim.start()
}
@@ -251,8 +251,10 @@
* for why split is being dismissed
*/
fun createPlaceholderDismissAnim(launcher: StatefulActivity<*>,
- splitDismissEvent: EventEnum) : AnimatorSet {
+ splitDismissEvent: EventEnum,
+ duration: Long?) : AnimatorSet {
val animatorSet = AnimatorSet()
+ duration?.let { animatorSet.duration = it }
val recentsView : RecentsView<*, *> = launcher.getOverviewPanel()
val floatingTask: FloatingTaskView = splitSelectStateController.firstFloatingTaskView
?: return animatorSet
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index f06418b..8e2520e 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -101,9 +101,9 @@
import com.android.quickstep.views.GroupedTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.SplitInstructionsView;
+import com.android.systemui.animation.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
import com.android.wm.shell.splitscreen.ISplitSelectListener;
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index 4c7d5c4..f2c9f27 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -28,7 +28,6 @@
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RoundRectShape;
-import android.os.SystemProperties;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
@@ -52,7 +51,7 @@
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.QuickStepContract;
-import com.android.wm.shell.Flags;
+import com.android.window.flags.Flags;
import kotlin.Unit;
@@ -69,11 +68,6 @@
// TODO(b/249371338): TaskView needs to be refactored to have better support for N tasks.
public class DesktopTaskView extends TaskView {
- private static final boolean DESKTOP_MODE_SUPPORTED = SystemProperties.getBoolean(
- "persist.wm.debug.desktop_mode_2", false);
-
- private static final boolean ENABLE_DESKTOP_WINDOWING = Flags.enableDesktopWindowing();
-
private static final String TAG = DesktopTaskView.class.getSimpleName();
private static final boolean DEBUG = false;
@@ -96,13 +90,7 @@
/** Check whether desktop windowing is enabled */
public static boolean isDesktopModeSupported() {
- // Check for aconfig flag first
- if (ENABLE_DESKTOP_WINDOWING) {
- return true;
- }
- // Fall back to sysprop flag
- // TODO(b/304778354): remove sysprop once desktop aconfig flag supports dynamic overriding
- return DESKTOP_MODE_SUPPORTED;
+ return Flags.enableDesktopWindowingMode();
}
public DesktopTaskView(Context context) {
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index a5e8989..2bd48d5 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -18,6 +18,8 @@
import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.launcher3.Flags.enableOverviewIconMenu;
+import static com.android.launcher3.testing.shared.TestProtocol.TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE;
+import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.quickstep.views.TaskThumbnailView.DIM_ALPHA;
@@ -136,6 +138,17 @@
};
}
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (!enableOverviewIconMenu()) {
+ int maxMenuHeight = calculateMaxHeight();
+ if (MeasureSpec.getSize(heightMeasureSpec) > maxMenuHeight) {
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxMenuHeight, MeasureSpec.AT_MOST);
+ }
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
public void onRotationChanged() {
if (mOpenCloseAnimator != null && mOpenCloseAnimator.isRunning()) {
mOpenCloseAnimator.end();
@@ -359,6 +372,8 @@
mOpenCloseAnimator.addListener(new AnimationSuccessListener() {
@Override
public void onAnimationStart(Animator animation) {
+ testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
+ "TaskMenuView.java.animateOpenOrClosed: onAnimationStart");
setVisibility(VISIBLE);
if (closing && mOnClosingStartCallback != null) {
mOnClosingStartCallback.run();
@@ -367,6 +382,8 @@
@Override
public void onAnimationSuccess(Animator animator) {
+ testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
+ "TaskMenuView.java.animateOpenOrClosed: onAnimationSuccess");
if (closing) {
closeComplete();
}
@@ -393,6 +410,18 @@
return new RoundedRectRevealOutlineProvider(radius, radius, fromRect, toRect);
}
+ /**
+ * Calculates max height based on how much space we have available.
+ * If not enough space then the view will scroll. The maximum menu size will sit inside the task
+ * with a margin on the top and bottom.
+ */
+ private int calculateMaxHeight() {
+ float taskBottom = mTaskView.getHeight() + mTaskView.getPersistentTranslationY();
+ float taskInsetMargin = getResources().getDimension(R.dimen.task_card_margin);
+
+ return (int) (taskBottom - taskInsetMargin - getTranslationY());
+ }
+
private void setOnClosingStartCallback(Runnable onClosingStartCallback) {
mOnClosingStartCallback = onClosingStartCallback;
}
diff --git a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
index 9ad360f..6a48b77 100644
--- a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
+++ b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
@@ -25,8 +25,6 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.tapl.LaunchedAppState;
-import com.android.launcher3.tapl.LauncherInstrumentation;
-import com.android.launcher3.tapl.LauncherInstrumentation.ContainerType;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.quickstep.views.RecentsView;
@@ -55,31 +53,6 @@
}
}
- @Override
- protected void checkLauncherState(Launcher launcher, ContainerType expectedContainerType,
- boolean isResumed, boolean isStarted) {
- if (ENABLE_SHELL_TRANSITIONS || !isInLiveTileMode(launcher, expectedContainerType)) {
- super.checkLauncherState(launcher, expectedContainerType, isResumed, isStarted);
- } else {
- assertTrue("[Live Tile] hasBeenResumed() == isStarted(), hasBeenResumed(): "
- + isResumed, isResumed != isStarted);
- }
- }
-
- @Override
- protected void checkLauncherStateInOverview(Launcher launcher,
- ContainerType expectedContainerType, boolean isStarted, boolean isResumed) {
- if (ENABLE_SHELL_TRANSITIONS || !isInLiveTileMode(launcher, expectedContainerType)) {
- super.checkLauncherStateInOverview(launcher, expectedContainerType, isStarted,
- isResumed);
- } else {
- assertTrue(
- "[Live Tile] Launcher is not started or has been resumed in state: "
- + expectedContainerType,
- isStarted && !isResumed);
- }
- }
-
protected void assertTestActivityIsRunning(int activityNumber, String message) {
assertTrue(message, mDevice.wait(
Until.hasObject(By.pkg(getAppPackageName()).text("TestActivity" + activityNumber)),
@@ -94,15 +67,4 @@
isInLaunchedApp(launcher)));
return launchedAppState;
}
-
- private boolean isInLiveTileMode(Launcher launcher,
- LauncherInstrumentation.ContainerType expectedContainerType) {
- if (expectedContainerType != LauncherInstrumentation.ContainerType.OVERVIEW) {
- return false;
- }
-
- RecentsView recentsView = launcher.getOverviewPanel();
- return recentsView.getSizeStrategy().isInLiveTileMode()
- && recentsView.getRunningTaskViewId() != -1;
- }
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index c0b31b7..45a9527 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -373,7 +373,7 @@
boolean isTransientTaskbar = mLauncher.isTransientTaskbar();
// Expect task bar invisible when the launched app was the IME activity.
LaunchedAppState launchedAppState = getAndAssertLaunchedApp();
- if (!isTransientTaskbar && isHardwareKeyboard()) {
+ if (!isTransientTaskbar && isHardwareKeyboard() && !mLauncher.isImeDocked()) {
launchedAppState.assertTaskbarVisible();
} else {
launchedAppState.assertTaskbarHidden();
@@ -503,6 +503,7 @@
@Test
@PortraitLandscape
+ @ScreenRecord // b/326839375
public void testOverviewDeadzones() throws Exception {
startTestAppsWithCheck();
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index c101762..fe62a01 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -400,6 +400,9 @@
<dimen name="taskbar_button_margin_split">0dp</dimen>
<dimen name="taskbar_button_margin_6_5">0dp</dimen>
+ <!--- Floating Ime Inset height-->
+ <dimen name="floating_ime_inset_height">0dp</dimen>
+
<!-- Bubble bar (placeholders to compile in Launcher3 without Quickstep) -->
<dimen name="bubblebar_hotseat_adjustment_threshold">0dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 379cdda..fa7057f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -46,6 +46,10 @@
<string name="save_app_pair">Save app pair</string>
<!-- App pair default title -->
<string name="app_pair_default_title"><xliff:g id="app1" example="Chrome">%1$s</xliff:g> | <xliff:g id="app2" example="YouTube">%2$s</xliff:g></string>
+ <!-- Displayed when an app pair can't launch at this screen size [CHAR_LIMIT=none] -->
+ <string name="app_pair_unlaunchable_at_screen_size">This pair isn\'t supported at this screen size</string>
+ <!-- Displayed when an app pair can't launch at this screen size, but user can unfold device to restore functionality [CHAR_LIMIT=none] -->
+ <string name="app_pair_needs_unfold">Unfold your device to use this pair</string>
<!-- Widgets -->
<!-- Message to tell the user to press and hold on a widget to add it [CHAR_LIMIT=50] -->
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 1ab6222..c1ebbe5 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -263,7 +263,7 @@
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.shared.LauncherOverlayManager;
import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayTouchProxy;
-import com.android.wm.shell.Flags;
+import com.android.window.flags.Flags;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -319,10 +319,6 @@
private static final FloatProperty<Hotseat> HOTSEAT_WIDGET_SCALE =
HOTSEAT_SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_WIDGET_TRANSITION);
- private static final boolean ENABLE_DESKTOP_WINDOWING = Flags.enableDesktopWindowing();
- private static final boolean DESKTOP_MODE_SUPPORTED =
- "1".equals(Utilities.getSystemProperty("persist.wm.debug.desktop_mode_2", "0"));
-
private final ModelCallbacks mModelCallbacks = createModelCallbacks();
private final KeyboardShortcutsDelegate mKeyboardShortcutsDelegate =
@@ -2724,8 +2720,7 @@
}
private void updateDisallowBack() {
- // TODO(b/304778354): remove sysprop once desktop aconfig flag supports dynamic overriding
- if (ENABLE_DESKTOP_WINDOWING || DESKTOP_MODE_SUPPORTED) {
+ if (Flags.enableDesktopWindowingMode()) {
// Do not disable back in launcher when prototype behavior is enabled
return;
}
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index 6422943..1ebd49e 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -60,9 +60,10 @@
*/
public class PrivateProfileManager extends UserProfileManager {
- private static final String SAFETY_CENTER_INTENT = Intent.ACTION_SAFETY_CENTER;
- private static final String PS_SETTINGS_FRAGMENT_KEY = ":settings:fragment_args_key";
- private static final String PS_SETTINGS_FRAGMENT_VALUE = "AndroidPrivateSpace_personal";
+ // TODO (b/324573634): Fix the intent string.
+ public static final Intent PRIVATE_SPACE_INTENT = new
+ Intent("com.android.settings.action.PRIVATE_SPACE_SETUP_FLOW");
+
private final ActivityAllAppsContainerView<?> mAllApps;
private final Predicate<UserHandle> mPrivateProfileMatcher;
private Set<String> mPreInstalledSystemPackages = new HashSet<>();
@@ -158,18 +159,23 @@
}
}
- /** Opens the Private Space Settings Entry Point. */
+ /** Opens the Private Space Settings Page. */
public void openPrivateSpaceSettings() {
- Intent psSettingsIntent = new Intent(SAFETY_CENTER_INTENT);
- psSettingsIntent.putExtra(PS_SETTINGS_FRAGMENT_KEY, PS_SETTINGS_FRAGMENT_VALUE);
- mAllApps.getContext().startActivity(psSettingsIntent);
+ if (mPrivateSpaceSettingsAvailable) {
+ mAllApps.getContext().startActivity(PRIVATE_SPACE_INTENT);
+ }
}
- /** Whether Private Space Settings Entry Point is available on the device. */
+ /** Returns whether or not Private Space Settings Page is available. */
public boolean isPrivateSpaceSettingsAvailable() {
return mPrivateSpaceSettingsAvailable;
}
+ /** Sets whether Private Space Settings Page is available. */
+ public boolean setPrivateSpaceSettingsAvailable(boolean value) {
+ return mPrivateSpaceSettingsAvailable = value;
+ }
+
/** Initializes binder call based properties in non-main thread.
* <p>
* This can cause the Private Space container items to not load/respond correctly sometimes,
@@ -183,19 +189,14 @@
Preconditions.assertNonUiThread();
setPreInstalledSystemPackages();
setAppInstallerIntent();
- setPrivateSpaceSettingsAvailable();
+ initializePrivateSpaceSettingsState();
}
- private void setPrivateSpaceSettingsAvailable() {
- if (mPrivateSpaceSettingsAvailable) {
- return;
- }
+ private void initializePrivateSpaceSettingsState() {
Preconditions.assertNonUiThread();
- Intent psSettingsIntent = new Intent(SAFETY_CENTER_INTENT);
- psSettingsIntent.putExtra(PS_SETTINGS_FRAGMENT_KEY, PS_SETTINGS_FRAGMENT_VALUE);
ResolveInfo resolveInfo = mAllApps.getContext().getPackageManager()
- .resolveActivity(psSettingsIntent, PackageManager.MATCH_SYSTEM_ONLY);
- mPrivateSpaceSettingsAvailable = resolveInfo != null;
+ .resolveActivity(PRIVATE_SPACE_INTENT, PackageManager.MATCH_SYSTEM_ONLY);
+ setPrivateSpaceSettingsAvailable(resolveInfo != null);
}
private void setPreInstalledSystemPackages() {
diff --git a/src/com/android/launcher3/apppairs/AppPairIcon.java b/src/com/android/launcher3/apppairs/AppPairIcon.java
index 9b85a65..48d0fbd 100644
--- a/src/com/android/launcher3/apppairs/AppPairIcon.java
+++ b/src/com/android/launcher3/apppairs/AppPairIcon.java
@@ -17,6 +17,7 @@
package com.android.launcher3.apppairs;
import android.content.Context;
+import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
@@ -33,11 +34,13 @@
import com.android.launcher3.Reorderable;
import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.util.MultiTranslateDelegate;
import com.android.launcher3.views.ActivityContext;
import java.util.Collections;
import java.util.Comparator;
+import java.util.function.Predicate;
/**
* A {@link android.widget.FrameLayout} used to represent an app pair icon on the workspace.
@@ -48,6 +51,11 @@
public class AppPairIcon extends FrameLayout implements DraggableView, Reorderable {
private static final String TAG = "AppPairIcon";
+ /**
+ * Indicates that the app pair is currently launchable on the current screen.
+ */
+ private boolean mIsLaunchableAtScreenSize = true;
+
// A view that holds the app pair icon graphic.
private AppPairIconGraphic mIconGraphic;
// A view that holds the app pair's title.
@@ -86,6 +94,13 @@
icon.setOnClickListener(activity.getItemOnClickListener());
icon.mInfo = appPairInfo;
+ if (icon.mInfo.contents.size() != 2) {
+ Log.wtf(TAG, "AppPair contents not 2, size: " + icon.mInfo.contents.size());
+ return icon;
+ }
+
+ icon.checkScreenSize();
+
// Set up icon drawable area
icon.mIconGraphic = icon.findViewById(R.id.app_pair_icon_graphic);
icon.mIconGraphic.init(activity.getDeviceProfile(), icon);
@@ -109,11 +124,6 @@
* Returns a formatted accessibility title for app pairs.
*/
public String getAccessibilityTitle(FolderInfo appPairInfo) {
- if (appPairInfo.contents.size() != 2) {
- Log.wtf(TAG, "AppPair contents not 2, size: " + appPairInfo.contents.size());
- return "";
- }
-
CharSequence app1 = appPairInfo.contents.get(0).title;
CharSequence app2 = appPairInfo.contents.get(1).title;
return getContext().getString(R.string.app_pair_name_format, app1, app2);
@@ -167,4 +177,40 @@
public View getIconDrawableArea() {
return mIconGraphic;
}
+
+ public boolean isLaunchableAtScreenSize() {
+ return mIsLaunchableAtScreenSize;
+ }
+
+ /**
+ * Checks if the app pair is launchable in the current device configuration.
+ *
+ * App pairs can be "disabled" in two ways:
+ * 1) One of the member WorkspaceItemInfos is disabled (i.e. the app software itself is paused
+ * by the user or can't be launched).
+ * 2) This specific instance of an app pair can't be launched due to screen size requirements.
+ *
+ * This method checks and updates #2. Both #1 and #2 are checked when app pairs are drawn
+ * {@link AppPairIconGraphic#dispatchDraw(Canvas)} or clicked on
+ * {@link com.android.launcher3.touch.ItemClickHandler#onClickAppPairIcon(View)}
+ */
+ public void checkScreenSize() {
+ DeviceProfile dp = ActivityContext.lookupContext(getContext()).getDeviceProfile();
+ // If user is on a small screen, we can't launch if either of the apps is non-resizeable
+ mIsLaunchableAtScreenSize =
+ dp.isTablet || getInfo().contents.stream().noneMatch(
+ wii -> wii.hasStatusFlag(WorkspaceItemInfo.FLAG_NON_RESIZEABLE));
+ }
+
+ /**
+ * Called when WorkspaceItemInfos get updated, and the app pair icon may need to be redrawn.
+ */
+ public void maybeRedrawForWorkspaceUpdate(Predicate<WorkspaceItemInfo> itemCheck) {
+ // If either of the app pair icons return true on the predicate (i.e. in the list of
+ // updated apps), redraw the icon graphic (icon background and both icons).
+ if (getInfo().contents.stream().anyMatch(itemCheck)) {
+ checkScreenSize();
+ mIconGraphic.invalidate();
+ }
+ }
}
diff --git a/src/com/android/launcher3/apppairs/AppPairIconBackground.java b/src/com/android/launcher3/apppairs/AppPairIconBackground.java
index 4e60ece..b5011f1 100644
--- a/src/com/android/launcher3/apppairs/AppPairIconBackground.java
+++ b/src/com/android/launcher3/apppairs/AppPairIconBackground.java
@@ -157,7 +157,7 @@
@Override
public void setAlpha(int i) {
- // Required by Drawable but not used.
+ mBackgroundPaint.setAlpha(i);
}
@Override
diff --git a/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt b/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt
index ab5ba54..365edf8 100644
--- a/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt
+++ b/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt
@@ -46,6 +46,9 @@
private const val CENTER_CHANNEL_SCALE = 1 / 30f
private const val BIG_RADIUS_SCALE = 1 / 5f
private const val SMALL_RADIUS_SCALE = 1 / 15f
+ // Disabled alpha is 38%, or 97/255
+ private const val DISABLED_ALPHA = 97
+ private const val ENABLED_ALPHA = 255
}
// App pair icons are slightly smaller than regular icons, so we pad the icon by this much on
@@ -133,7 +136,13 @@
override fun dispatchDraw(canvas: Canvas) {
super.dispatchDraw(canvas)
+
+ val drawAlpha =
+ if (!parentIcon.isLaunchableAtScreenSize || parentIcon.info.isDisabled) DISABLED_ALPHA
+ else ENABLED_ALPHA
+
// Draw background
+ appPairBackground.alpha = drawAlpha
appPairBackground.draw(canvas)
// Make sure icons are loaded and fresh
@@ -147,6 +156,7 @@
} else {
canvas.translate(width / 2f - memberIconSize / 2f, innerPadding)
}
+ appIcon1?.alpha = drawAlpha
appIcon1?.draw(canvas)
canvas.restore()
@@ -164,6 +174,7 @@
height - (innerPadding + memberIconSize)
)
}
+ appIcon2?.alpha = drawAlpha
appIcon2?.draw(canvas)
canvas.restore()
}
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 71ab51c..17cef90 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -475,12 +475,24 @@
mItemsDeleted = c.commitDeleted();
processFolderItems();
+ processAppPairItems();
c.commitRestoredItems();
}
}
/**
+ * After all items have been processed and added to the BgDataModel, this method requests
+ * high-res icons for the items that are part of an app pair
+ */
+ private void processAppPairItems() {
+ mBgDataModel.workspaceItems.stream()
+ .filter((itemInfo -> itemInfo.itemType == ITEM_TYPE_APP_PAIR))
+ .forEach(fi -> ((FolderInfo) fi).contents.forEach(item ->
+ mIconCache.getTitleAndIcon(item, false /*useLowResIcon*/)));
+ }
+
+ /**
* Initialized the UserManagerState, and determines which users are unlocked. Additionally, if
* the user is unlocked, it queries LauncherAppsService for pinned shortcuts and stores the
* result in a class variable to be used in other methods while processing workspace items.
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 4d06c2e..0ba468d 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -48,6 +48,7 @@
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.ShortcutRequest;
+import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ItemInfoMatcher;
@@ -284,6 +285,12 @@
}
}
if (si.itemType == Favorites.ITEM_TYPE_APPLICATION) {
+ if (activities != null && !activities.isEmpty()) {
+ si.status = ApiWrapper
+ .isNonResizeableActivity(activities.get(0))
+ ? si.status | WorkspaceItemInfo.FLAG_NON_RESIZEABLE
+ : si.status & ~WorkspaceItemInfo.FLAG_NON_RESIZEABLE;
+ }
iconCache.getTitleAndIcon(si, si.usingLowResIcon());
infoUpdated = true;
}
diff --git a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
index e38af01..59f56df 100644
--- a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
+++ b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
@@ -38,6 +38,7 @@
import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.pm.PackageInstallInfo
import com.android.launcher3.shortcuts.ShortcutKey
+import com.android.launcher3.uioverrides.ApiWrapper
import com.android.launcher3.util.ComponentKey
import com.android.launcher3.util.PackageManagerHelper
import com.android.launcher3.util.PackageUserKey
@@ -321,6 +322,9 @@
}
val activityInfo = c.launcherActivityInfo
if (activityInfo != null) {
+ if (ApiWrapper.isNonResizeableActivity(activityInfo)) {
+ info.status = info.status or WorkspaceItemInfo.FLAG_NON_RESIZEABLE
+ }
info.setProgressLevel(
PackageManagerHelper.getLoadingProgress(activityInfo),
PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING
diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
index 435d223..9917ad7 100644
--- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
+++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
@@ -75,6 +75,12 @@
public static final int FLAG_START_FOR_RESULT = 1 << 4;
/**
+ * The app is flagged non-resizeable, meaning that it does not support multi-window on small
+ * screens.
+ */
+ public static final int FLAG_NON_RESIZEABLE = 1 << 5;
+
+ /**
* The intent used to start the application.
*/
@NonNull
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 4abefc7..111931e 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -41,6 +41,7 @@
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.BuildConfig;
+import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
@@ -149,7 +150,15 @@
private static void onClickAppPairIcon(View v) {
Launcher launcher = Launcher.getLauncher(v.getContext());
AppPairIcon appPairIcon = (AppPairIcon) v;
- if (appPairIcon.getInfo().isDisabled()) {
+ if (!appPairIcon.isLaunchableAtScreenSize()) {
+ // Display a message for app pairs that are disabled due to screen size
+ boolean isFoldable = InvariantDeviceProfile.INSTANCE.get(launcher)
+ .supportedProfiles.stream().anyMatch(dp -> dp.isTwoPanels);
+ Toast.makeText(launcher, isFoldable
+ ? R.string.app_pair_needs_unfold
+ : R.string.app_pair_unlaunchable_at_screen_size,
+ Toast.LENGTH_SHORT).show();
+ } else if (appPairIcon.getInfo().isDisabled()) {
WorkspaceItemInfo app1 = appPairIcon.getInfo().contents.get(0);
WorkspaceItemInfo app2 = appPairIcon.getInfo().contents.get(1);
// Show the user why the app pair is disabled.
diff --git a/src/com/android/launcher3/util/ActivityTracker.java b/src/com/android/launcher3/util/ActivityTracker.java
index 7af1a13..405d2bb 100644
--- a/src/com/android/launcher3/util/ActivityTracker.java
+++ b/src/com/android/launcher3/util/ActivityTracker.java
@@ -15,13 +15,14 @@
*/
package com.android.launcher3.util;
+import static com.android.launcher3.testing.shared.TestProtocol.GET_FROM_RECENTS_FAILURE;
+import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
+
import androidx.annotation.Nullable;
import com.android.launcher3.BaseActivity;
import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.HashSet;
import java.util.concurrent.CopyOnWriteArrayList;
/**
@@ -40,6 +41,9 @@
public void onActivityDestroyed(T activity) {
if (mCurrentActivity.get() == activity) {
+ testLogD(GET_FROM_RECENTS_FAILURE,
+ String.format("ActivityTracker.onActivityDestroyed this=%s, activity=%s",
+ this, activity));
mCurrentActivity.clear();
}
}
@@ -71,6 +75,8 @@
}
public boolean handleCreate(T activity) {
+ testLogD(GET_FROM_RECENTS_FAILURE,
+ String.format("ActivityTracker.handleCreate this=%s, activity=%s", this, activity));
mCurrentActivity = new WeakReference<>(activity);
return handleIntent(activity, false /* alreadyOnHome */);
}
diff --git a/src/com/android/launcher3/util/LauncherBindableItemsContainer.java b/src/com/android/launcher3/util/LauncherBindableItemsContainer.java
index f73940b..69786bb 100644
--- a/src/com/android/launcher3/util/LauncherBindableItemsContainer.java
+++ b/src/com/android/launcher3/util/LauncherBindableItemsContainer.java
@@ -19,6 +19,7 @@
import android.view.View;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.apppairs.AppPairIcon;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.graphics.PreloadIconDrawable;
@@ -58,6 +59,8 @@
: null);
} else if (info instanceof FolderInfo && v instanceof FolderIcon) {
((FolderIcon) v).updatePreviewItems(updates::contains);
+ } else if (info instanceof FolderInfo && v instanceof AppPairIcon appPairIcon) {
+ appPairIcon.maybeRedrawForWorkspaceUpdate(updates::contains);
}
// Iterate all items
@@ -86,6 +89,8 @@
((PendingAppWidgetHostView) v).applyState();
} else if (v instanceof FolderIcon && info instanceof FolderInfo) {
((FolderIcon) v).updatePreviewItems(updates::contains);
+ } else if (info instanceof FolderInfo && v instanceof AppPairIcon appPairIcon) {
+ appPairIcon.maybeRedrawForWorkspaceUpdate(updates::contains);
}
// process all the shortcuts
return false;
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index 230a651..31f5d65 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -322,8 +322,8 @@
}
/**
- * Returns if the software keyboard is hidden. Hardware keyboards do not display on screen by
- * default.
+ * Returns if the software keyboard (including input toolbar) is hidden. Hardware
+ * keyboards do not display on screen by default.
*/
default boolean isSoftwareKeyboardHidden() {
if (isHardwareKeyboard()) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
index f10ab48..ef3ccf0 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
@@ -124,6 +124,7 @@
widget.applyFromCellItem(widgetItem, 1f,
bitmap -> holder.onPreviewLoaded(Pair.create(widgetItem, bitmap)),
holder.previewCache.get(widgetItem));
+ widget.requestLayout();
}
}
}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
index b9f9ac5..efde7d8 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -107,6 +107,15 @@
.authority(context.getPackageName()).build());
}
+ /**
+ * Checks if an activity is flagged as non-resizeable.
+ */
+ public static boolean isNonResizeableActivity(LauncherActivityInfo lai) {
+ // Overridden in quickstep
+ return false;
+ }
+
+
private static class NoopDrawable extends ColorDrawable {
@Override
public int getIntrinsicHeight() {
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index 7059268..7cb7964 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -301,6 +301,24 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
+ <activity-alias android:name="SplitTask1"
+ android:label="1st TopLeft"
+ android:exported="true"
+ android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity-alias>
+ <activity-alias android:name="SplitTask2"
+ android:label="2nd BottomRight"
+ android:exported="true"
+ android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity-alias>
<activity-alias android:name="MaxShortcutsActivity"
android:label="TestActivityMaxShortcuts"
android:exported="true"
diff --git a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index 4e1e9c8..afda3a3 100644
--- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -101,6 +101,7 @@
public static final String REQUEST_TASKBAR_FROM_NAV_THRESHOLD = "taskbar-from-nav-threshold";
public static final String REQUEST_STASHED_TASKBAR_SCALE = "taskbar-stash-handle-scale";
public static final String REQUEST_RECREATE_TASKBAR = "recreate-taskbar";
+ public static final String REQUEST_TASKBAR_IME_DOCKED = "taskbar-ime-docked";
public static final String REQUEST_APP_LIST_FREEZE_FLAGS = "app-list-freeze-flags";
public static final String REQUEST_APPS_LIST_SCROLL_Y = "apps-list-scroll-y";
public static final String REQUEST_TASKBAR_APPS_LIST_SCROLL_Y = "taskbar-apps-list-scroll-y";
@@ -172,6 +173,10 @@
public static final String OVERVIEW_OVER_HOME = "b/279059025";
public static final String UIOBJECT_STALE_ELEMENT = "b/319501259";
public static final String ACTIVITY_NOT_RESUMED_AFTER_BACK = "b/322823209";
+ public static final String GET_FROM_RECENTS_FAILURE = "b/321775748";
+ public static final String SUCCESSFUL_GESTURE_MISMATCH_EVENTS = "b/324940434";
+ public static final String TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE = "b/326908466";
+ public static final String TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE = "b/326073471";
public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display";
diff --git a/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 679bd01..1f824b8 100644
--- a/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -55,14 +55,11 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
-import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.tapl.HomeAllApps;
import com.android.launcher3.tapl.HomeAppIcon;
import com.android.launcher3.tapl.LauncherInstrumentation;
-import com.android.launcher3.tapl.LauncherInstrumentation.ContainerType;
import com.android.launcher3.tapl.TestHelpers;
import com.android.launcher3.testcomponent.TestCommandReceiver;
-import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.LooperExecutor;
import com.android.launcher3.util.SimpleBroadcastReceiver;
import com.android.launcher3.util.TestUtil;
@@ -204,10 +201,6 @@
mLauncher.setSystemHealthSupplier(startTime -> TestCommandReceiver.callCommand(
TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE, startTime.toString())
.getString("result"));
- mLauncher.setOnSettledStateAction(
- containerType -> executeOnLauncher(
- launcher ->
- checkLauncherIntegrity(launcher, containerType)));
}
mLauncher.enableDebugTracing();
// Avoid double-reporting of Launcher crashes.
@@ -561,16 +554,20 @@
true /* newTask */);
}
- public static void startTestActivity(int activityNumber) {
+ public static void startTestActivity(String activityName, String activityLabel) {
final String packageName = getAppPackageName();
final Intent intent = getInstrumentation().getContext().getPackageManager().
getLaunchIntentForPackage(packageName);
intent.setComponent(new ComponentName(packageName,
- "com.android.launcher3.tests.Activity" + activityNumber));
- startIntent(intent, By.pkg(packageName).text("TestActivity" + activityNumber),
+ "com.android.launcher3.tests." + activityName));
+ startIntent(intent, By.pkg(packageName).text(activityLabel),
false /* newTask */);
}
+ public static void startTestActivity(int activityNumber) {
+ startTestActivity("Activity" + activityNumber, "TestActivity" + activityNumber);
+ }
+
public static void startImeTestActivity() {
final String packageName = getAppPackageName();
final Intent intent = getInstrumentation().getContext().getPackageManager().
@@ -638,86 +635,6 @@
return launcher.getAppsView().getActiveRecyclerView().computeVerticalScrollOffset();
}
- private void checkLauncherIntegrity(
- Launcher launcher, ContainerType expectedContainerType) {
- if (launcher != null) {
- final StateManager<LauncherState> stateManager = launcher.getStateManager();
- final LauncherState stableState = stateManager.getCurrentStableState();
-
- assertTrue("Stable state != state: " + stableState.getClass().getSimpleName() + ", "
- + stateManager.getState().getClass().getSimpleName(),
- stableState == stateManager.getState());
-
- final boolean isResumed = launcher.hasBeenResumed();
- final boolean isStarted = launcher.isStarted();
- checkLauncherState(launcher, expectedContainerType, isResumed, isStarted);
-
- final int ordinal = stableState.ordinal;
-
- switch (expectedContainerType) {
- case WORKSPACE:
- case WIDGETS: {
- assertTrue(
- "Launcher is not resumed in state: " + expectedContainerType,
- isResumed);
- assertTrue(TestProtocol.stateOrdinalToString(ordinal),
- ordinal == TestProtocol.NORMAL_STATE_ORDINAL);
- break;
- }
- case HOME_ALL_APPS: {
- assertTrue(
- "Launcher is not resumed in state: " + expectedContainerType,
- isResumed);
- assertTrue(TestProtocol.stateOrdinalToString(ordinal),
- ordinal == TestProtocol.ALL_APPS_STATE_ORDINAL);
- break;
- }
- case OVERVIEW: {
- verifyOverviewState(launcher, expectedContainerType, isStarted, isResumed,
- ordinal, TestProtocol.OVERVIEW_STATE_ORDINAL);
- break;
- }
- case SPLIT_SCREEN_SELECT: {
- verifyOverviewState(launcher, expectedContainerType, isStarted, isResumed,
- ordinal, TestProtocol.OVERVIEW_SPLIT_SELECT_ORDINAL);
- break;
- }
- case TASKBAR_ALL_APPS:
- case LAUNCHED_APP: {
- assertTrue("Launcher is resumed in state: " + expectedContainerType,
- !isResumed);
- assertTrue(TestProtocol.stateOrdinalToString(ordinal),
- ordinal == TestProtocol.NORMAL_STATE_ORDINAL);
- break;
- }
- default:
- throw new IllegalArgumentException(
- "Illegal container: " + expectedContainerType);
- }
- } else {
- assertTrue(
- "Container type is not LAUNCHED_APP, TASKBAR_ALL_APPS "
- + "or FALLBACK_OVERVIEW: " + expectedContainerType,
- expectedContainerType == ContainerType.LAUNCHED_APP
- || expectedContainerType == ContainerType.TASKBAR_ALL_APPS
- || expectedContainerType == ContainerType.FALLBACK_OVERVIEW);
- }
- }
-
- protected void checkLauncherState(Launcher launcher, ContainerType expectedContainerType,
- boolean isResumed, boolean isStarted) {
- assertTrue("hasBeenResumed() != isStarted(), hasBeenResumed(): " + isResumed,
- isResumed == isStarted);
- assertTrue("hasBeenResumed() != isUserActive(), hasBeenResumed(): " + isResumed,
- isResumed == launcher.isUserActive());
- }
-
- protected void checkLauncherStateInOverview(Launcher launcher,
- ContainerType expectedContainerType, boolean isStarted, boolean isResumed) {
- assertTrue("Launcher is not resumed in state: " + expectedContainerType,
- isResumed);
- }
-
protected void onLauncherActivityClose(Launcher launcher) {
}
@@ -746,10 +663,4 @@
}
return homeAppIcon;
}
-
- private void verifyOverviewState(Launcher launcher, ContainerType expectedContainerType,
- boolean isStarted, boolean isResumed, int ordinal, int expectedOrdinal) {
- checkLauncherStateInOverview(launcher, expectedContainerType, isStarted, isResumed);
- assertEquals(TestProtocol.stateOrdinalToString(ordinal), ordinal, expectedOrdinal);
- }
}
diff --git a/tests/multivalentTests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/multivalentTests/tapl/com/android/launcher3/tapl/AllApps.java
index 2dbc29d..9591891 100644
--- a/tests/multivalentTests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/multivalentTests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -261,7 +261,7 @@
int attempts = 0;
final Rect margins = new Rect(
/* left= */ 0,
- getTopVisibleIconBounds(allAppsContainer).bottom,
+ mHeight / 2,
/* right= */ 0,
/* bottom= */ getAppsListRecyclerBottomPadding());
diff --git a/tests/multivalentTests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/multivalentTests/tapl/com/android/launcher3/tapl/AppIcon.java
index 156568b..7c6d684 100644
--- a/tests/multivalentTests/tapl/com/android/launcher3/tapl/AppIcon.java
+++ b/tests/multivalentTests/tapl/com/android/launcher3/tapl/AppIcon.java
@@ -16,6 +16,9 @@
package com.android.launcher3.tapl;
+import static com.android.launcher3.testing.shared.TestProtocol.TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE;
+
+import android.util.Log;
import android.widget.TextView;
import androidx.annotation.NonNull;
@@ -49,7 +52,7 @@
/**
* Find an app icon with the given name.
*
- * @param appName app icon to look for
+ * @param appName app icon to look for
* @param launcher (optional) - only match ui elements from Launcher's package
*/
static BySelector getAppIconSelector(String appName, LauncherInstrumentation launcher) {
@@ -95,6 +98,8 @@
@Override
protected void waitForLongPressConfirmation() {
+ Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+ "AppIcon.waitForLongPressConfirmation, resName: popupContainer");
mLauncher.waitForLauncherObject("popup_container");
}
diff --git a/tests/multivalentTests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/multivalentTests/tapl/com/android/launcher3/tapl/Launchable.java
index ed47334..9d3bc6e 100644
--- a/tests/multivalentTests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/multivalentTests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -17,8 +17,10 @@
package com.android.launcher3.tapl;
import static com.android.launcher3.testing.shared.TestProtocol.SPRING_LOADED_STATE_ORDINAL;
+import static com.android.launcher3.testing.shared.TestProtocol.TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE;
import android.graphics.Point;
+import android.util.Log;
import android.view.MotionEvent;
import androidx.test.uiautomator.UiObject2;
@@ -113,11 +115,15 @@
iconCenter.y - getStartDragThreshold());
if (runToSpringLoadedState) {
+ Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+ "Launchable.startDrag: actionName: long-pressing and triggering drag start"
+ + " iconCenter: " + iconCenter + " dragStartCenter: "
+ + dragStartCenter);
mLauncher.runToState(() -> movePointerForStartDrag(
- downTime,
- iconCenter,
- dragStartCenter,
- expectLongClickEvents),
+ downTime,
+ iconCenter,
+ dragStartCenter,
+ expectLongClickEvents),
SPRING_LOADED_STATE_ORDINAL, "long-pressing and triggering drag start");
} else {
movePointerForStartDrag(
diff --git a/tests/multivalentTests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/multivalentTests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index 200f2ff..b5414b7 100644
--- a/tests/multivalentTests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/multivalentTests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -24,7 +24,9 @@
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_SHELL_DRAG_READY;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_STASHED_TASKBAR_SCALE;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_TASKBAR_FROM_NAV_THRESHOLD;
+import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
import static com.android.launcher3.testing.shared.TestProtocol.TEST_INFO_RESPONSE_FIELD;
+import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import android.graphics.Point;
import android.graphics.Rect;
@@ -139,6 +141,8 @@
return new Taskbar(mLauncher);
} finally {
+ testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
+ "swipeUpToUnstashTaskbar: completed gesture");
mLauncher.getTestInfo(REQUEST_DISABLE_BLOCK_TIMEOUT);
}
}
diff --git a/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 326802f..053b360 100644
--- a/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -30,7 +30,10 @@
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_GET_SPLIT_SELECTION_ACTIVE;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_NUM_ALL_APPS_COLUMNS;
+import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
+import static com.android.launcher3.testing.shared.TestProtocol.TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE;
import static com.android.launcher3.testing.shared.TestProtocol.TEST_INFO_RESPONSE_FIELD;
+import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import android.app.ActivityManager;
import android.app.Instrumentation;
@@ -94,7 +97,6 @@
import java.util.Optional;
import java.util.concurrent.TimeoutException;
import java.util.function.BooleanSupplier;
-import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Pattern;
@@ -200,8 +202,6 @@
private boolean mIgnoreTaskbarVisibility = false;
- private Consumer<ContainerType> mOnSettledStateAction;
-
private LogEventChecker mEventChecker;
// UI anomaly checker provided by the test.
@@ -655,10 +655,6 @@
this.mSystemHealthSupplier = supplier;
}
- public void setOnSettledStateAction(Consumer<ContainerType> onSettledStateAction) {
- mOnSettledStateAction = onSettledStateAction;
- }
-
public void onTestStart() {
mTestStartTime = System.currentTimeMillis();
}
@@ -869,8 +865,6 @@
final UiObject2 container = verifyVisibleObjects(containerType);
- if (mOnSettledStateAction != null) mOnSettledStateAction.accept(containerType);
-
return container;
}
@@ -1172,7 +1166,11 @@
log("Hierarchy before clicking home:");
dumpViewHierarchy();
action = "clicking home button";
-
+ Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+ "LauncherInstrumentation.goHome: isThreeFingerTrackpadGesture: "
+ + isThreeFingerTrackpadGesture
+ + "getNavigationModel() == NavigationModel.ZERO_BUTTON: " + (
+ getNavigationModel() == NavigationModel.ZERO_BUTTON));
runToState(
getHomeButton()::click,
NORMAL_STATE_ORDINAL,
@@ -1216,7 +1214,8 @@
waitForNavigationUiObject("back").click();
}
if (launcherVisible) {
- if (getContext().getApplicationInfo().isOnBackInvokedCallbackEnabled()) {
+ if (InstrumentationRegistry.getTargetContext().getApplicationInfo()
+ .isOnBackInvokedCallbackEnabled()) {
expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ON_BACK_INVOKED);
} else {
expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_KEY_BACK_DOWN);
@@ -1518,6 +1517,8 @@
@NonNull
UiObject2 waitForLauncherObject(String resName) {
+ Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+ "LauncherInstrumentation.waitForLauncherObject");
return waitForObjectBySelector(getLauncherObjectSelector(resName));
}
@@ -1547,12 +1548,16 @@
@NonNull
List<UiObject2> waitForObjectsBySelector(BySelector selector) {
+ Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+ "LauncherInstrumentation.waitForObjectsBySelector");
final List<UiObject2> objects = mDevice.wait(Until.findObjects(selector), WAIT_TIME_MS);
assertNotNull("Can't find any view in Launcher, selector: " + selector, objects);
return objects;
}
private UiObject2 waitForObjectBySelector(BySelector selector) {
+ Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+ "LauncherInstrumentation.waitForObjectBySelector");
final UiObject2 object = mDevice.wait(Until.findObject(selector), WAIT_TIME_MS);
assertNotNull("Can't find a view in Launcher, selector: " + selector, object);
return object;
@@ -1595,6 +1600,9 @@
void runToState(Runnable command, int expectedState, boolean requireEvent, String actionName) {
if (requireEvent) {
+ Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+ "LauncherInstrumentation.runToState: command: " + command + " expectedState: "
+ + expectedState + " actionName: " + actionName + "requireEvent: true");
runToState(command, expectedState, actionName);
} else {
command.run();
@@ -1972,11 +1980,15 @@
mPointerCount = 1;
pointerCount = mPointerCount;
}
+ Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+ "LauncherInstrumentation.sendPointer: ACTION_DOWN");
break;
case MotionEvent.ACTION_UP:
if (hasTIS && gestureScope == GestureScope.EXPECT_PILFER) {
expectEvent(TestProtocol.SEQUENCE_PILFER, EVENT_PILFER_POINTERS);
}
+ Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+ "LauncherInstrumentation.sendPointer: ACTION_UP");
break;
case MotionEvent.ACTION_POINTER_DOWN:
mPointerCount++;
@@ -2241,6 +2253,11 @@
.getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
+ public boolean isImeDocked() {
+ return getTestInfo(TestProtocol.REQUEST_TASKBAR_IME_DOCKED).getBoolean(
+ TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ }
+
/** Enables transient taskbar for testing purposes only. */
public void enableTransientTaskbar(boolean enable) {
getTestInfo(enable
@@ -2312,9 +2329,13 @@
}
if (mEventChecker != null) {
+ testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS, "eventsCheck: mEventChecker exists");
mEventChecker = null;
if (mCheckEventsForSuccessfulGestures) {
final String message = eventChecker.verify(WAIT_TIME_MS, true);
+ testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
+ "mCheckEventsForSuccessfulGestures = true | eventsCheck: message="
+ + message);
if (message != null) {
dumpDiagnostics(message);
checkForAnomaly();
diff --git a/tests/multivalentTests/tapl/com/android/launcher3/tapl/LogEventChecker.java b/tests/multivalentTests/tapl/com/android/launcher3/tapl/LogEventChecker.java
index 672c6e0..70d63bd 100644
--- a/tests/multivalentTests/tapl/com/android/launcher3/tapl/LogEventChecker.java
+++ b/tests/multivalentTests/tapl/com/android/launcher3/tapl/LogEventChecker.java
@@ -18,6 +18,8 @@
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 static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
+import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import android.os.SystemClock;
@@ -88,6 +90,7 @@
}
String verify(long waitForExpectedCountMs, boolean successfulGesture) {
+ testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS, "LogEventChecker.java - verify");
final ListMap<String> actualEvents = finishSync(waitForExpectedCountMs);
if (actualEvents == null) return "null event sequences because launcher likely died";
diff --git a/tests/multivalentTests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/multivalentTests/tapl/com/android/launcher3/tapl/Workspace.java
index 506e563..4e92634 100644
--- a/tests/multivalentTests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/multivalentTests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -25,6 +25,7 @@
import static com.android.launcher3.testing.shared.TestProtocol.ALL_APPS_STATE_ORDINAL;
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_STATE_ORDINAL;
+import static com.android.launcher3.testing.shared.TestProtocol.TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE;
import static com.android.launcher3.testing.shared.TestProtocol.UIOBJECT_STALE_ELEMENT;
import static junit.framework.TestCase.assertNotNull;
@@ -626,6 +627,8 @@
try (LauncherInstrumentation.Closable ignored = launcher.addContextLayer(
"want to drag icon to workspace")) {
final long downTime = SystemClock.uptimeMillis();
+ Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+ "Workspace.dragIconToWorkspace: starting drag | downtime: " + downTime);
Point dragStart = launchable.startDrag(
downTime,
expectLongClickEvents,
diff --git a/tests/multivalentTests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java b/tests/multivalentTests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java
index e5a2a2e..b42d43b 100644
--- a/tests/multivalentTests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java
+++ b/tests/multivalentTests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java
@@ -15,7 +15,10 @@
*/
package com.android.launcher3.tapl;
+import static com.android.launcher3.testing.shared.TestProtocol.TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE;
+
import android.graphics.Point;
+import android.util.Log;
import java.util.function.Supplier;
@@ -76,6 +79,9 @@
LauncherInstrumentation.Closable c = launcher.addContextLayer(
String.format("want to drag the icon to cell(%d, %d)", cellX, cellY))) {
final Supplier<Point> dest = () -> Workspace.getCellCenter(launcher, cellX, cellY);
+ Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+ "WorkspaceDragSource.dragToWorkspace: dragging icon to workspace | dest: "
+ + dest.get());
Workspace.dragIconToWorkspace(
launcher,
launchable,
diff --git a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
index 2905d85..3ba563d 100644
--- a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
@@ -19,6 +19,7 @@
import android.content.res.Configuration
import android.graphics.Point
import android.graphics.Rect
+import android.platform.test.flag.junit.SetFlagsRule
import android.platform.test.rule.AllowedDevices
import android.platform.test.rule.DeviceProduct
import android.platform.test.rule.IgnoreLimit
@@ -33,6 +34,7 @@
import com.android.launcher3.util.NavigationMode
import com.android.launcher3.util.WindowBounds
import com.android.launcher3.util.rule.TestStabilityRule
+import com.android.launcher3.util.rule.setFlags
import com.android.launcher3.util.window.CachedDisplayInfo
import com.android.launcher3.util.window.WindowManagerProxy
import com.google.common.truth.Truth
@@ -64,6 +66,8 @@
private val windowManagerProxy: WindowManagerProxy = mock()
private val launcherPrefs: LauncherPrefs = mock()
+ @get:Rule val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT)
+
@Rule @JvmField val testStabilityRule = TestStabilityRule()
@Rule @JvmField val limitDevicesRule = LimitDevicesRule()
@@ -270,6 +274,7 @@
isGestureMode: Boolean = true,
densityDpi: Int
) {
+ setFlagsRule.setFlags(false, Flags.FLAG_ENABLE_TWOLINE_TOGGLE)
val windowsBounds = perDisplayBoundsCache[displayInfo]!!
val realBounds = windowsBounds[rotation]
whenever(windowManagerProxy.getDisplayInfo(any())).thenReturn(displayInfo)
diff --git a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
index ea7feb5..0907f8f 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
@@ -76,9 +76,6 @@
new UserIconInfo(MAIN_HANDLE, UserIconInfo.TYPE_MAIN);
private static final UserIconInfo PRIVATE_ICON_INFO =
new UserIconInfo(PRIVATE_HANDLE, UserIconInfo.TYPE_PRIVATE);
- private static final String SAFETY_CENTER_INTENT = Intent.ACTION_SAFETY_CENTER;
- private static final String PS_SETTINGS_FRAGMENT_KEY = ":settings:fragment_args_key";
- private static final String PS_SETTINGS_FRAGMENT_VALUE = "AndroidPrivateSpace_personal";
private PrivateProfileManager mPrivateProfileManager;
@Mock
@@ -180,9 +177,9 @@
@Test
public void openPrivateSpaceSettings_triggersSecurityAndPrivacyIntent() {
- Intent expectedIntent = new Intent(SAFETY_CENTER_INTENT);
- expectedIntent.putExtra(PS_SETTINGS_FRAGMENT_KEY, PS_SETTINGS_FRAGMENT_VALUE);
+ Intent expectedIntent = PrivateProfileManager.PRIVATE_SPACE_INTENT;
ArgumentCaptor<Intent> acIntent = ArgumentCaptor.forClass(Intent.class);
+ mPrivateProfileManager.setPrivateSpaceSettingsAvailable(true);
mPrivateProfileManager.openPrivateSpaceSettings();
@@ -190,9 +187,6 @@
Intent actualIntent = acIntent.getValue();
assertEquals("Intent Action is different", expectedIntent.getAction(),
actualIntent.getAction());
- assertEquals("Settings Fragment is incorrect in Intent",
- expectedIntent.getStringExtra(PS_SETTINGS_FRAGMENT_KEY),
- actualIntent.getStringExtra(PS_SETTINGS_FRAGMENT_KEY));
}
private static void awaitTasksCompleted() throws Exception {
diff --git a/tests/src/com/android/launcher3/dragging/TaplDragTest.java b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
index 615f679..d1227d8 100644
--- a/tests/src/com/android/launcher3/dragging/TaplDragTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.dragging;
+import static com.android.launcher3.testing.shared.TestProtocol.TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE;
import static com.android.launcher3.util.TestConstants.AppNames.GMAIL_APP_NAME;
import static com.android.launcher3.util.TestConstants.AppNames.MAPS_APP_NAME;
import static com.android.launcher3.util.TestConstants.AppNames.PHOTOS_APP_NAME;
@@ -233,6 +234,11 @@
final HomeAppIcon launcherTestAppIcon = createShortcutInCenterIfNotExist(TEST_APP_NAME);
for (Point target : targets) {
startTime = SystemClock.uptimeMillis();
+ Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+ "TaplDragTest.java.testDragAppIconToMultipleWorkspaceCells: shortcut name: "
+ + launcherTestAppIcon.getIconName()
+ + " | target cell coordinates: (" + target.x + ", " + target.y
+ + ") | start time: " + startTime);
launcherTestAppIcon.dragToWorkspace(target.x, target.y);
endTime = SystemClock.uptimeMillis();
elapsedTime = endTime - startTime;
diff --git a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
index 8631f03..7a0b60a 100644
--- a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
+++ b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
@@ -2,35 +2,23 @@
import static android.os.Process.myUserHandle;
-import static androidx.test.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING;
-import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY;
import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY2;
import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY3;
import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE;
+import static com.android.launcher3.util.TestUtil.runOnExecutorSync;
import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
-import static com.android.launcher3.util.TestUtil.DUMMY_CLASS_NAME;
-import static com.android.launcher3.util.TestUtil.DUMMY_PACKAGE;
-import static com.android.launcher3.util.TestUtil.runOnExecutorSync;
-
-import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.content.Context;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import androidx.test.uiautomator.UiDevice;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.icons.BitmapInfo;
@@ -40,7 +28,6 @@
import com.android.launcher3.util.LauncherLayoutBuilder;
import com.android.launcher3.util.LauncherModelHelper;
import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.util.TestUtil;
import com.android.launcher3.util.rule.TestStabilityRule;
import org.junit.After;
@@ -50,7 +37,6 @@
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
-import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -65,18 +51,9 @@
@Rule(order = 0)
public TestRule testStabilityRule = new TestStabilityRule();
- @Rule
- public final CheckFlagsRule mCheckFlagsRule =
- DeviceFlagsValueProvider.createCheckFlagsRule();
-
private static final String PENDING_APP_1 = TEST_PACKAGE + ".pending1";
private static final String PENDING_APP_2 = TEST_PACKAGE + ".pending2";
- private static final String ARCHIVED_PACKAGE = DUMMY_PACKAGE;
- private static final String ARCHIVED_CLASS_NAME = DUMMY_CLASS_NAME;
- private static final String ARCHIVED_TITLE = "Aardwolf";
-
-
private LauncherModelHelper mModelHelper;
private Context mContext;
@@ -88,7 +65,6 @@
mContext = mModelHelper.sandboxContext;
mSession1 = mModelHelper.createInstallerSession(PENDING_APP_1);
mModelHelper.createInstallerSession(PENDING_APP_2);
- TestUtil.installDummyApp();
LauncherLayoutBuilder builder = new LauncherLayoutBuilder()
.atHotseat(1).putFolder("MyFolder")
@@ -105,22 +81,14 @@
.addApp(PENDING_APP_2, TEST_ACTIVITY) // 8
.addApp(PENDING_APP_2, TEST_ACTIVITY2) // 9
.addApp(PENDING_APP_2, TEST_ACTIVITY3) // 10
-
- // Dummy Test Package
- .addApp(ARCHIVED_PACKAGE, ARCHIVED_CLASS_NAME) // 11
.build();
mModelHelper.setupDefaultLayoutProvider(builder);
mModelHelper.loadModelSync();
- assertEquals(11, mModelHelper.getBgDataModel().itemsIdMap.size());
-
- UiDevice device = UiDevice.getInstance(getInstrumentation());
- assertThat(device.executeShellCommand(String.format("pm archive %s", ARCHIVED_PACKAGE)))
- .isEqualTo("Success\n");
+ assertEquals(10, mModelHelper.getBgDataModel().itemsIdMap.size());
}
@After
- public void tearDown() throws IOException {
- TestUtil.uninstallDummyApp();
+ public void tearDown() {
mModelHelper.destroy();
}
@@ -180,47 +148,6 @@
});
}
- @Test
- @RequiresFlagsEnabled(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING)
- public void testSessionUpdate_archivedApps_sessionInfoPrioritized() {
- // Run on model executor so that no other task runs in the middle.
- runOnExecutorSync(MODEL_EXECUTOR, () -> {
- // Clear all icons from apps list so that its easy to check what was updated
- allItems().forEach(wi -> wi.bitmap = BitmapInfo.LOW_RES_INFO);
- int mSession2 = mModelHelper.createInstallerSession(ARCHIVED_PACKAGE);
- mModelHelper.getModel().enqueueModelUpdateTask(
- newTask(CacheDataUpdatedTask.OP_CACHE_UPDATE, ARCHIVED_PACKAGE));
- List<Integer> pendingArchivedAppIds = List.of(11);
- // Mark the app items as archived.
- allItems().forEach(wi -> {
- if (pendingArchivedAppIds.contains(wi.id)) {
- wi.runtimeStatusFlags |= FLAG_ARCHIVED;
- }
- });
- // Before cache is updated with sessionInfo, confirm the title.
- for (WorkspaceItemInfo info : allItems()) {
- if (pendingArchivedAppIds.contains(info.id)) {
- assertEquals(info.title, ARCHIVED_TITLE);
- }
- }
-
- // Update the cache with session details.
- LauncherAppState.getInstance(mContext).getIconCache().updateSessionCache(
- new PackageUserKey(ARCHIVED_PACKAGE, myUserHandle()),
- mContext.getPackageManager().getPackageInstaller().getSessionInfo(mSession2));
-
- // Trigger a refresh for workspace itemInfo objects.
- mModelHelper.getModel().enqueueModelUpdateTask(
- newTask(CacheDataUpdatedTask.OP_SESSION_UPDATE, ARCHIVED_PACKAGE));
- // Verify the new title from session is applied to the iconInfo.
- for (WorkspaceItemInfo info : allItems()) {
- if (pendingArchivedAppIds.contains(info.id)) {
- assertEquals(info.title, ARCHIVED_PACKAGE);
- }
- }
- });
- }
-
private void verifyUpdate(int... idsUpdated) {
IntSet updates = IntSet.wrap(idsUpdated);
for (WorkspaceItemInfo info : allItems()) {
diff --git a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt b/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
index 60a4d2d..2118ed6 100644
--- a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
+++ b/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
@@ -24,11 +24,13 @@
import com.android.launcher3.util.LauncherModelHelper
import com.android.launcher3.util.LauncherModelHelper.*
import com.android.launcher3.util.TestUtil
+import com.android.launcher3.util.rule.TestStabilityRule
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import java.util.concurrent.CountDownLatch
import org.junit.After
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -56,6 +58,8 @@
TEST_ACTIVITY14
)
+ @get:Rule(order = 0) val testStabilityRule = TestStabilityRule()
+
@Before
fun setUp() {
modelHelper = LauncherModelHelper()
@@ -87,6 +91,9 @@
@Test
@Throws(Exception::class)
+ @TestStabilityRule.Stability(
+ flavors = TestStabilityRule.LOCAL or TestStabilityRule.PLATFORM_POSTSUBMIT
+ ) // b/319923578
fun folderLoadedWithHighRes_max_3x3() {
val idp = LauncherAppState.getIDP(modelHelper.sandboxContext)
idp.numFolderColumns = intArrayOf(3, 3, 3, 3)
@@ -100,6 +107,9 @@
@Test
@Throws(Exception::class)
+ @TestStabilityRule.Stability(
+ flavors = TestStabilityRule.LOCAL or TestStabilityRule.PLATFORM_POSTSUBMIT
+ ) // b/319923578
fun folderLoadedWithHighRes_max_4x4() {
val idp = LauncherAppState.getIDP(modelHelper.sandboxContext)
idp.numFolderColumns = intArrayOf(4, 4, 4, 4)
@@ -113,6 +123,10 @@
@Test
@Throws(Exception::class)
+ // Stress tests are long. We permanently demote them from presubmit to match the presubmit SLO.
+ @TestStabilityRule.Stability(
+ flavors = TestStabilityRule.LOCAL or TestStabilityRule.PLATFORM_POSTSUBMIT
+ ) // b/319923578
fun folderLoadedWithHighRes_differentFolderConfigurations() {
val idp = LauncherAppState.getIDP(modelHelper.sandboxContext)
idp.numFolderColumns = intArrayOf(4, 3, 4, 4)
diff --git a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java b/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
index 58af51c..6df3ecd 100644
--- a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
+++ b/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
@@ -101,6 +101,7 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
Utilities.enableRunningInTestHarnessForTests();
+ mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
mContext = new ActivityContextWrapper(getApplicationContext());
mBubbleTextView = new BubbleTextView(mContext);
mBubbleTextView.reset();