Merge "Revert "Revert "Remove TaplTestsQuickstep tests from PlatinumTes..."" into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index ace2210..5689c8a 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -55,3 +55,17 @@
description: "Enables launcher to listen to all transitions that include home activity"
bug: "306053414"
}
+
+flag {
+ name: "enable_taskbar_pinning"
+ namespace: "launcher"
+ description: "Enables taskbar pinning to allow user to switch between transient and persistent taskbar flavors."
+ bug: "270396583"
+}
+
+flag {
+ name: "enable_split_from_fullscreen_with_keyboard_shortcuts"
+ namespace: "launcher"
+ description: "Enables initiating split from a fullscreen app using keyboard shortcuts"
+ bug: "270394122"
+}
diff --git a/aconfig/launcher_search.aconfig b/aconfig/launcher_search.aconfig
index 87ccec5..fc79200 100644
--- a/aconfig/launcher_search.aconfig
+++ b/aconfig/launcher_search.aconfig
@@ -6,3 +6,10 @@
description: "Enables all Launcher features associated with private space."
bug: "306187906"
}
+
+flag {
+ name: "private_space_animation"
+ namespace: "launcher_search"
+ description: "This flag enables the animation of the Private Space container"
+ bug: "299294792"
+}
\ No newline at end of file
diff --git a/quickstep/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml
index 0fda0bf..fe517fa 100644
--- a/quickstep/res/layout/overview_actions_container.xml
+++ b/quickstep/res/layout/overview_actions_container.xml
@@ -31,7 +31,7 @@
android:layout_height="1dp"
android:layout_weight="1" />
- <Button
+ <com.android.quickstep.views.ScreenshotActionButton
android:id="@+id/action_screenshot"
style="@style/OverviewActionButton"
android:layout_width="wrap_content"
@@ -40,17 +40,12 @@
android:text="@string/action_screenshot"
android:theme="@style/ThemeControlHighlightWorkspaceColor" />
- <Space
- android:id="@+id/action_split_space"
- android:layout_width="@dimen/overview_actions_button_spacing"
- android:layout_height="1dp"
- android:visibility="gone" />
-
- <Button
+ <com.android.quickstep.views.SplitActionButton
android:id="@+id/action_split"
style="@style/OverviewActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/overview_actions_button_spacing"
android:text="@string/action_split"
android:theme="@style/ThemeControlHighlightWorkspaceColor"
android:visibility="gone" />
diff --git a/quickstep/res/layout/taskbar_divider_popup_menu.xml b/quickstep/res/layout/taskbar_divider_popup_menu.xml
index 6fbb586..7f4f76c 100644
--- a/quickstep/res/layout/taskbar_divider_popup_menu.xml
+++ b/quickstep/res/layout/taskbar_divider_popup_menu.xml
@@ -57,7 +57,7 @@
android:paddingStart="12dp"
android:layout_weight="1"
android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
- android:singleLine="true"
+ android:lines="1"
android:ellipsize="end"
android:textSize="14sp"
android:textColor="?android:attr/textColorPrimary"
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index aa42f2f..ef885e8 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -115,7 +115,7 @@
<string name="taskbar_button_a11y" msgid="5241161324875094465">"Erabilerraztasuna"</string>
<string name="taskbar_button_back" msgid="8558862226461164514">"Atzera"</string>
<string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IMEaren etengailua"</string>
- <string name="taskbar_button_recents" msgid="7273376136216613134">"Azkenak"</string>
+ <string name="taskbar_button_recents" msgid="7273376136216613134">"Azkenaldikoak"</string>
<string name="taskbar_button_notifications" msgid="7471740351507357318">"Jakinarazpenak"</string>
<string name="taskbar_button_quick_settings" msgid="227662894293189391">"Ezarpen bizkorrak"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"Zereginen barra"</string>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index dd9fc63..3dade66 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -235,6 +235,7 @@
<string name="toast_split_app_unsupported">Choose another app to use split screen</string>
<!-- Message shown when an action is blocked by a policy enforced by the app or the organization managing the device. [CHAR_LIMIT=NONE] -->
<string name="blocked_by_policy">This action isn\'t allowed by the app or your organization</string>
+ <string name="split_widgets_not_supported">Widgets not currently supported, please select another app</string>
<!-- ******* Skip tutorial dialog ******* -->
<!-- Title for the dialog that allows the user to skip the gesture navigation tutorial. [CHAR_LIMIT=40] -->
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index be4426d..0ef4541 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -23,6 +23,7 @@
import static com.android.launcher3.LauncherAnimUtils.ROTATION_DRAWABLE_PERCENT;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
import static com.android.launcher3.taskbar.LauncherTaskbarUIController.SYSUI_SURFACE_PROGRESS_INDEX;
import static com.android.launcher3.taskbar.TaskbarManager.isPhoneButtonNavMode;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y;
@@ -734,7 +735,7 @@
// TODO(b/244231596) we're getting the incorrect kidsMode value in small-screen
boolean isInKidsMode = mContext.isNavBarKidsModeActive();
- if (TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW) {
+ if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
NavButtonLayoutter navButtonLayoutter =
NavButtonLayoutFactory.Companion.getUiLayoutter(
dp, mNavButtonsView, mImeSwitcherButton,
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 6ee151b..820b996 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -30,12 +30,12 @@
import static com.android.launcher3.Flags.enableCursorHoverStates;
import static com.android.launcher3.Utilities.calculateTextHeight;
import static com.android.launcher3.Utilities.isRunningInTestHarness;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_PINNING;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
import static com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate;
+import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN;
-import static com.android.launcher3.taskbar.TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW;
import static com.android.launcher3.testing.shared.ResourceUtils.getBoolByName;
import static com.android.launcher3.util.VibratorWrapper.EFFECT_CLICK;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
@@ -354,7 +354,7 @@
sharedState.systemBarAttrsBehavior);
onNavButtonsDarkIntensityChanged(sharedState.navButtonsDarkIntensity);
- if (FLAG_HIDE_NAVBAR_WINDOW) {
+ if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
// W/ the flag not set this entire class gets re-created, which resets the value of
// mIsDestroyed. We re-use the class for small-screen, so we explicitly have to mark
// this class as non-destroyed
@@ -454,7 +454,7 @@
*/
private WindowManager.LayoutParams createAllWindowParams() {
final int windowType =
- FLAG_HIDE_NAVBAR_WINDOW ? TYPE_NAVIGATION_BAR : TYPE_NAVIGATION_BAR_PANEL;
+ ENABLE_TASKBAR_NAVBAR_UNIFICATION ? TYPE_NAVIGATION_BAR : TYPE_NAVIGATION_BAR_PANEL;
WindowManager.LayoutParams windowLayoutParams =
createDefaultWindowLayoutParams(windowType, TaskbarActivityContext.WINDOW_TITLE);
boolean isPhoneNavMode = TaskbarManager.isPhoneButtonNavMode(this);
@@ -719,7 +719,7 @@
mIsDestroyed = true;
setUIController(TaskbarUIController.DEFAULT);
mControllers.onDestroy();
- if (!enableTaskbarNoRecreate() && !FLAG_HIDE_NAVBAR_WINDOW) {
+ if (!enableTaskbarNoRecreate() && !ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
mWindowManager.removeViewImmediate(mDragLayer);
mAddedWindow = false;
}
@@ -860,7 +860,7 @@
public int getDefaultTaskbarWindowHeight() {
Resources resources = getResources();
- if (FLAG_HIDE_NAVBAR_WINDOW && mDeviceProfile.isPhone) {
+ if (ENABLE_TASKBAR_NAVBAR_UNIFICATION && mDeviceProfile.isPhone) {
return isThreeButtonNav() ?
resources.getDimensionPixelSize(R.dimen.taskbar_size) :
resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
@@ -871,7 +871,7 @@
}
boolean shouldTreatAsTransient = DisplayController.isTransientTaskbar(this)
- || (ENABLE_TASKBAR_PINNING.get() && !isThreeButtonNav());
+ || (enableTaskbarPinning() && !isThreeButtonNav());
int extraHeightForTaskbarTooltips = enableCursorHoverStates()
? resources.getDimensionPixelSize(R.dimen.arrow_toast_arrow_height)
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index 1eb8d53..a24cf4b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -18,6 +18,8 @@
import static android.view.KeyEvent.ACTION_UP;
import static android.view.KeyEvent.KEYCODE_BACK;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
+
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.RectF;
@@ -126,7 +128,7 @@
}
protected void onDestroy() {
- onDestroy(!TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW);
+ onDestroy(!ENABLE_TASKBAR_NAVBAR_UNIFICATION);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 0b52195..1a34b7a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -41,6 +41,7 @@
import com.android.launcher3.DeviceProfile
import com.android.launcher3.R
import com.android.launcher3.anim.AlphaUpdateListener
+import com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION
import com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate
import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
import com.android.launcher3.util.DisplayController
@@ -253,7 +254,7 @@
visInsetsSizeForTappableElement
),
)
- if ((context.isGestureNav || TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
+ if ((context.isGestureNav || ENABLE_TASKBAR_NAVBAR_UNIFICATION)
&& provider.type == tappableElement()) {
provider.insetsSizeOverrides = insetsSizeOverrideForTappableElement
} else if (provider.type != systemGestures()) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 9bb7e67..c0b07e7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -23,6 +23,7 @@
import static com.android.launcher3.BaseActivity.EVENT_DESTROYED;
import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
import static com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate;
import static com.android.launcher3.util.DisplayController.TASKBAR_NOT_DESTROYED_TAG;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@@ -41,7 +42,6 @@
import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Handler;
-import android.os.SystemProperties;
import android.os.Trace;
import android.provider.Settings;
import android.util.Log;
@@ -71,6 +71,7 @@
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
+import com.android.wm.shell.Flags;
import java.io.PrintWriter;
import java.util.StringJoiner;
@@ -98,9 +99,6 @@
| ActivityInfo.CONFIG_SCREEN_LAYOUT
| ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
- public static final boolean FLAG_HIDE_NAVBAR_WINDOW =
- SystemProperties.getBoolean("persist.wm.debug.hide_navbar_window", false);
-
private static final Uri USER_SETUP_COMPLETE_URI = Settings.Secure.getUriFor(
Settings.Secure.USER_SETUP_COMPLETE);
@@ -198,7 +196,8 @@
Display display =
service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
mContext = service.createWindowContext(display,
- FLAG_HIDE_NAVBAR_WINDOW ? TYPE_NAVIGATION_BAR : TYPE_NAVIGATION_BAR_PANEL, null);
+ ENABLE_TASKBAR_NAVBAR_UNIFICATION ? TYPE_NAVIGATION_BAR : TYPE_NAVIGATION_BAR_PANEL,
+ null);
if (enableTaskbarNoRecreate()) {
mWindowManager = mContext.getSystemService(WindowManager.class);
mTaskbarRootLayout = new FrameLayout(mContext) {
@@ -250,7 +249,7 @@
destroyExistingTaskbar();
} else {
if (dp != null && isTaskbarPresent(dp)) {
- if (FLAG_HIDE_NAVBAR_WINDOW) {
+ if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
// Re-initialize for screen size change? Should this be done
// by looking at screen-size change flag in configDiff in the
// block above?
@@ -295,7 +294,7 @@
debugWhyTaskbarNotDestroyed("destroyExistingTaskbar: " + mTaskbarActivityContext);
if (mTaskbarActivityContext != null) {
mTaskbarActivityContext.onDestroy();
- if (!FLAG_HIDE_NAVBAR_WINDOW || enableTaskbarNoRecreate()) {
+ if (!ENABLE_TASKBAR_NAVBAR_UNIFICATION || enableTaskbarNoRecreate()) {
mTaskbarActivityContext = null;
}
}
@@ -427,7 +426,7 @@
boolean isTaskbarEnabled = dp != null && isTaskbarPresent(dp);
debugWhyTaskbarNotDestroyed("recreateTaskbar: isTaskbarEnabled=" + isTaskbarEnabled
+ " [dp != null (i.e. mUserUnlocked)]=" + (dp != null)
- + " FLAG_HIDE_NAVBAR_WINDOW=" + FLAG_HIDE_NAVBAR_WINDOW
+ + " FLAG_HIDE_NAVBAR_WINDOW=" + ENABLE_TASKBAR_NAVBAR_UNIFICATION
+ " dp.isTaskbarPresent=" + (dp == null ? "null" : dp.isTaskbarPresent));
if (!isTaskbarEnabled) {
SystemUiProxy.INSTANCE.get(mContext)
@@ -493,7 +492,7 @@
* and we are using a single window for taskbar and navbar.
*/
public static boolean isPhoneMode(DeviceProfile deviceProfile) {
- return TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW && deviceProfile.isPhone;
+ return ENABLE_TASKBAR_NAVBAR_UNIFICATION && deviceProfile.isPhone;
}
/**
@@ -505,7 +504,7 @@
}
private boolean isTaskbarPresent(DeviceProfile deviceProfile) {
- return FLAG_HIDE_NAVBAR_WINDOW || deviceProfile.isTaskbarPresent;
+ return ENABLE_TASKBAR_NAVBAR_UNIFICATION || deviceProfile.isTaskbarPresent;
}
public void onRotationProposal(int rotation, boolean isValid) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 5be74be..e5c4c96 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -23,7 +23,7 @@
import static com.android.app.animation.Interpolators.INSTANT;
import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_PINNING;
+import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_HIDE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_SHOW;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TRANSIENT_TASKBAR_HIDE;
@@ -333,7 +333,7 @@
// that taskbar unstashes when going to 3 button mode (supportsVisualStashing() false).
boolean isManuallyStashedInApp = supportsVisualStashing()
&& !isTransientTaskbar
- && !ENABLE_TASKBAR_PINNING.get()
+ && !enableTaskbarPinning()
&& mPrefs.getBoolean(SHARED_PREFS_STASHED_KEY, DEFAULT_STASHED_PREF);
boolean isInSetup = !mActivity.isUserSetupComplete() || setupUIVisible;
updateStateForFlag(FLAG_STASHED_IN_APP_MANUAL, isManuallyStashedInApp);
@@ -365,7 +365,7 @@
* Returns whether the user can manually stash the taskbar based on the current device state.
*/
protected boolean supportsManualStashing() {
- if (ENABLE_TASKBAR_PINNING.get() && LauncherPrefs.get(mActivity).get(TASKBAR_PINNING)) {
+ if (enableTaskbarPinning() && LauncherPrefs.get(mActivity).get(TASKBAR_PINNING)) {
return false;
}
return supportsVisualStashing()
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index a7461b7..81e4ad5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.Flags.enableCursorHoverStates;
import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR;
+import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
import android.content.Context;
@@ -45,7 +46,6 @@
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.icons.ThemedIconDrawable;
import com.android.launcher3.model.data.FolderInfo;
@@ -128,7 +128,7 @@
int actualMargin = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
int actualIconSize = mActivityContext.getDeviceProfile().taskbarIconSize;
- if (FeatureFlags.ENABLE_TASKBAR_PINNING.get()) {
+ if (enableTaskbarPinning()) {
DeviceProfile deviceProfile = mActivityContext.getTransientTaskbarDeviceProfile();
actualIconSize = deviceProfile.taskbarIconSize;
}
@@ -155,12 +155,11 @@
.inflate(R.layout.taskbar_all_apps_button, this, false);
mAllAppsButton.setIconDrawable(resources.getDrawable(
getAllAppsButton(isTransientTaskbar)));
- mAllAppsButton.setScaleX(mIsRtl ? -1 : 1);
mAllAppsButton.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
mAllAppsButton.setForegroundTint(
mActivityContext.getColor(R.color.all_apps_button_color));
- if (FeatureFlags.ENABLE_TASKBAR_PINNING.get()) {
+ if (enableTaskbarPinning()) {
mTaskbarDivider = (IconButtonView) LayoutInflater.from(context).inflate(
R.layout.taskbar_divider,
this, false);
@@ -177,7 +176,7 @@
@DrawableRes
private int getAllAppsButton(boolean isTransientTaskbar) {
boolean shouldSelectTransientIcon =
- (isTransientTaskbar || FeatureFlags.ENABLE_TASKBAR_PINNING.get())
+ (isTransientTaskbar || enableTaskbarPinning())
&& !mActivityContext.isThreeButtonNav();
if (ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
return shouldSelectTransientIcon
@@ -546,7 +545,7 @@
int iconLayoutBoundsWidth =
countExcludingQsb * (mItemMarginLeftRight * 2 + mIconTouchSize);
- if (FeatureFlags.ENABLE_TASKBAR_PINNING.get() && countExcludingQsb > 1) {
+ if (enableTaskbarPinning() && countExcludingQsb > 1) {
// We are removing 4 * mItemMarginLeftRight as there should be no space between
// All Apps icon, divider icon, and first app icon in taskbar
iconLayoutBoundsWidth -= mItemMarginLeftRight * 4;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 78d5bd3..0225de4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -25,7 +25,8 @@
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.anim.AnimatedFloat.VALUE;
import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_PINNING;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
+import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP;
import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_PERSISTENT;
import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_TRANSIENT;
@@ -214,13 +215,13 @@
mActivity.addOnDeviceProfileChangeListener(mDeviceProfileChangeListener);
- if (TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW) {
+ if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
// This gets modified in NavbarButtonsViewController, but the initial value it reads
// may be incorrect since it's state gets destroyed on taskbar recreate, so reset here
mTaskbarIconAlpha.get(ALPHA_INDEX_SMALL_SCREEN)
.animateToValue(isPhoneButtonNavMode(mActivity) ? 0 : 1).start();
}
- if (ENABLE_TASKBAR_PINNING.get()) {
+ if (enableTaskbarPinning()) {
mTaskbarView.addOnLayoutChangeListener(mTaskbarViewLayoutChangeListener);
}
}
@@ -233,7 +234,7 @@
}
public void onDestroy() {
- if (ENABLE_TASKBAR_PINNING.get()) {
+ if (enableTaskbarPinning()) {
mTaskbarView.removeOnLayoutChangeListener(mTaskbarViewLayoutChangeListener);
}
LauncherAppState.getInstance(mActivity).getModel().removeCallbacks(mModelCallbacks);
@@ -366,6 +367,10 @@
float allAppIconTranslateRange = mapRange(scale, transientTaskbarAllAppsOffset,
persistentTaskbarAllAppsOffset);
+ if (mIsRtl) {
+ allAppIconTranslateRange *= -1;
+ }
+
float halfIconCount = iconViews.length / 2.0f;
for (int iconIndex = 0; iconIndex < iconViews.length; iconIndex++) {
View iconView = iconViews[iconIndex];
@@ -671,7 +676,7 @@
// to avoid icons disappearing rather than fading out visually.
setter.setViewAlpha(child, 0, Interpolators.clampToProgress(LINEAR, 0.8f, 1f));
} else if ((isAllAppsButton && !FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get())
- || (isTaskbarDividerView && ENABLE_TASKBAR_PINNING.get())) {
+ || (isTaskbarDividerView && enableTaskbarPinning())) {
if (!isToHome
&& mIsHotseatIconOnTopWhenAligned
&& mIsStashed) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index 12cb8c5..6549ad6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -163,6 +163,7 @@
mBubble = overflow;
mBubbleIcon.setImageBitmap(bitmap);
mAppIcon.setVisibility(GONE); // Overflow doesn't show the app badge
+ setContentDescription(getResources().getString(R.string.bubble_bar_overflow_description));
}
/** Returns the bubble being rendered in this view. */
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
index f5ba8f9..8092582 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
@@ -27,8 +27,10 @@
import android.util.Pair;
import android.view.View;
import android.widget.RemoteViews;
+import android.widget.Toast;
import android.window.SplashScreen;
+import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.ItemInfo;
@@ -56,8 +58,9 @@
return RemoteViews.startPendingIntent(hostView, pendingIntent,
remoteResponse.getLaunchOptions(view));
}
- if (mLauncher.getSplitToWorkspaceController().handleSecondWidgetSelectionForSplit(view,
- pendingIntent)) {
+ if (mLauncher.isSplitSelectionEnabled()) {
+ Toast.makeText(hostView.getContext(), R.string.split_widgets_not_supported,
+ Toast.LENGTH_SHORT).show();
return true;
}
Pair<Intent, ActivityOptions> options = remoteResponse.getLaunchOptions(view);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 22ab79d..165ed80 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -20,6 +20,8 @@
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE;
import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED;
import static com.android.app.animation.Interpolators.EMPHASIZED;
+import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.PENDING_SPLIT_SELECT_INFO;
+import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE;
import static com.android.launcher3.LauncherSettings.Animation.DEFAULT_NO_ICON;
import static com.android.launcher3.LauncherSettings.Animation.VIEW_BACKGROUND;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DebugFlag.java b/quickstep/src/com/android/launcher3/uioverrides/flags/DebugFlag.java
index 481e200..630ef39 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/DebugFlag.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DebugFlag.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.uioverrides.flags;
+import static com.android.launcher3.uioverrides.flags.FlagsFactory.TEAMFOOD_FLAG;
+
import androidx.annotation.NonNull;
import com.android.launcher3.config.FeatureFlags.BooleanFlag;
@@ -35,6 +37,21 @@
this.description = description;
}
+ /**
+ * Returns {@code true} if this flag's value has been modified from its default.
+ * <p>
+ * This helps to identify which flags have been toggled in log dumps and bug reports to
+ * further help triaging and debugging.
+ */
+ boolean currentValueModified() {
+ switch (defaultValue) {
+ case ENABLED: return !get();
+ case TEAMFOOD: return TEAMFOOD_FLAG.get() != get();
+ case DISABLED: return get();
+ default: return true;
+ }
+ }
+
@Override
public String toString() {
return key + ": defaultValue=" + defaultValue + ", mCurrentValue=" + get();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DeviceFlag.java b/quickstep/src/com/android/launcher3/uioverrides/flags/DeviceFlag.java
index 035beb4..915f4ae 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/DeviceFlag.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DeviceFlag.java
@@ -29,6 +29,11 @@
}
@Override
+ boolean currentValueModified() {
+ return super.currentValueModified() || mDefaultValueInCode != get();
+ }
+
+ @Override
public String toString() {
return super.toString() + ", mDefaultValueInCode=" + mDefaultValueInCode;
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java
index 28d4bf8..48d313e 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java
@@ -175,7 +175,7 @@
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {
if (flag instanceof DeviceFlag) {
- pw.println(" " + flag);
+ pw.println((flag.currentValueModified() ? " ->" : " ") + flag);
}
}
}
@@ -185,11 +185,11 @@
pw.println(" " + flag);
}
}
- pw.println("DebugFlags:");
+ pw.println(" DebugFlags:");
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {
if (!(flag instanceof DeviceFlag)) {
- pw.println(" " + flag);
+ pw.println((flag.currentValueModified() ? " ->" : " ") + flag);
}
}
}
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index b06a978..9ee9d85 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -20,6 +20,7 @@
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static android.widget.Toast.LENGTH_SHORT;
+
import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE;
import static com.android.app.animation.Interpolators.DECELERATE;
import static com.android.app.animation.Interpolators.OVERSHOOT_1_2;
@@ -351,7 +352,7 @@
return ROTATION_0;
}
return mRecentsView.getPagedViewOrientedState().getRecentsActivityRotation();
- }, inputConsumer, /* callback = */ () -> {
+ }, inputConsumer, /* onTouchDownCallback = */ () -> {
endRunningWindowAnim(mGestureState.getEndTarget() == HOME /* cancel */);
endLauncherTransitionController();
}, new InputProxyHandlerFactory(mActivityInterface, mGestureState));
@@ -1943,7 +1944,7 @@
mCurrentShift.cancelAnimation();
// Cleanup when switching handlers
- mInputConsumerProxy.unregisterCallback();
+ mInputConsumerProxy.unregisterOnTouchDownCallback();
mActivityInitListener.unregister();
TaskStackChangeListeners.getInstance().unregisterTaskStackListener(
mActivityRestartListener);
@@ -1955,7 +1956,7 @@
mInputConsumerProxy.destroy();
mTaskAnimationManager.setLiveTileCleanUpHandler(null);
}
- mInputConsumerProxy.unregisterCallback();
+ mInputConsumerProxy.unregisterOnTouchDownCallback();
endRunningWindowAnim(false /* cancel */);
if (mGestureEndCallback != null) {
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index 49ec85e..575be5f 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -29,13 +29,15 @@
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET_HOME;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET_NEW_TASK;
-import android.annotation.Nullable;
import android.annotation.TargetApi;
import android.content.Intent;
import android.os.Build;
import android.view.MotionEvent;
import android.view.RemoteAnimationTarget;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.quickstep.TopTaskTracker.CachedTaskInfo;
@@ -303,6 +305,7 @@
/**
* @return the running task for this gesture.
*/
+ @Nullable
public CachedTaskInfo getRunningTask() {
return mRunningTask;
}
@@ -336,7 +339,7 @@
/**
* Updates the running task for the gesture to be the given {@param runningTask}.
*/
- public void updateRunningTask(CachedTaskInfo runningTask) {
+ public void updateRunningTask(@NonNull CachedTaskInfo runningTask) {
mRunningTask = runningTask;
}
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 5784c37..feaa063 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -276,8 +276,11 @@
@Override
public boolean isInLiveTileMode() {
Launcher launcher = getCreatedActivity();
- return launcher != null && launcher.getStateManager().getState() == OVERVIEW &&
- launcher.isStarted();
+
+ return launcher != null
+ && launcher.getStateManager().getState() == OVERVIEW
+ && launcher.isStarted()
+ && TopTaskTracker.INSTANCE.get(launcher).getCachedTopTask(false).isHomeTask();
}
@Override
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 00d8008..92aa9fa 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -1222,7 +1222,7 @@
}
try {
mBackAnimation.setBackToLauncherCallback(callback, runner);
- } catch (RemoteException e) {
+ } catch (RemoteException | SecurityException e) {
Log.e(TAG, "Failed call setBackToLauncherCallback", e);
}
}
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 3d8191d..ddddc89 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -197,7 +197,11 @@
remoteTargetHandles = gluer.assignTargets(targets);
}
}
+ final int recentsActivityRotation =
+ recentsView.getPagedViewOrientedState().getRecentsActivityRotation();
for (RemoteTargetHandle remoteTargetGluer : remoteTargetHandles) {
+ remoteTargetGluer.getTaskViewSimulator().getOrientationState().setRecentsRotation(
+ recentsActivityRotation);
remoteTargetGluer.getTransformParams().setSyncTransactionApplier(applier);
}
diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java
index f1af2ed..a2a6dde 100644
--- a/quickstep/src/com/android/quickstep/TopTaskTracker.java
+++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java
@@ -29,6 +29,7 @@
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@@ -178,6 +179,7 @@
/**
* Returns the CachedTaskInfo for the top most task
*/
+ @NonNull
@UiThread
public CachedTaskInfo getCachedTopTask(boolean filterOnlyVisibleRecents) {
if (filterOnlyVisibleRecents) {
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index b4fe5e4..0ad56fb 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -854,7 +854,11 @@
if (mTaskAnimationManager.isRecentsAnimationRunning()) {
gestureState = new GestureState(mOverviewComponentObserver,
ActiveGestureLog.INSTANCE.getLogId());
- taskInfo = previousGestureState.getRunningTask();
+ TopTaskTracker.CachedTaskInfo previousTaskInfo = previousGestureState.getRunningTask();
+ // previousTaskInfo can be null iff previousGestureState == GestureState.DEFAULT_STATE
+ taskInfo = previousTaskInfo != null
+ ? previousTaskInfo
+ : TopTaskTracker.INSTANCE.get(this).getCachedTopTask(false);
gestureState.updateRunningTask(taskInfo);
gestureState.updateLastStartedTaskIds(previousGestureState.getLastStartedTaskIds());
gestureState.updatePreviouslyAppearedTaskIds(
@@ -869,7 +873,7 @@
// Log initial state for the gesture.
ActiveGestureLog.INSTANCE.addLog(new CompoundString("Current running task package name=")
- .append(taskInfo == null ? "no running task" : taskInfo.getPackageName()));
+ .append(taskInfo.getPackageName()));
ActiveGestureLog.INSTANCE.addLog(new CompoundString("Current SystemUi state flags=")
.append(mDeviceState.getSystemUiStateString()));
return gestureState;
@@ -1078,21 +1082,22 @@
reasonString.append(SUBSTRING_PREFIX).append("keyguard is not showing occluded");
+ TopTaskTracker.CachedTaskInfo runningTask = gestureState.getRunningTask();
// Use overview input consumer for sharesheets on top of home.
boolean forceOverviewInputConsumer = gestureState.getActivityInterface().isStarted()
- && gestureState.getRunningTask() != null
- && gestureState.getRunningTask().isRootChooseActivity();
+ && runningTask != null
+ && runningTask.isRootChooseActivity();
// In the case where we are in an excluded, translucent overlay, ignore it and treat the
// running activity as the task behind the overlay.
- TopTaskTracker.CachedTaskInfo otherVisibleTask = gestureState.getRunningTask() == null
+ TopTaskTracker.CachedTaskInfo otherVisibleTask = runningTask == null
? null
- : gestureState.getRunningTask().otherVisibleTaskThisIsExcludedOver();
+ : runningTask.otherVisibleTaskThisIsExcludedOver();
if (otherVisibleTask != null) {
ActiveGestureLog.INSTANCE.addLog(new CompoundString("Changing active task to ")
.append(otherVisibleTask.getPackageName())
.append(" because the previous task running on top of this one (")
- .append(gestureState.getRunningTask().getPackageName())
+ .append(runningTask.getPackageName())
.append(") was excluded from recents"));
gestureState.updateRunningTask(otherVisibleTask);
}
@@ -1112,7 +1117,7 @@
forceOverviewInputConsumer,
reasonString.append(SUBSTRING_PREFIX)
.append("is in live tile mode, trying to use overview input consumer"));
- } else if (gestureState.getRunningTask() == null) {
+ } else if (runningTask == null) {
return getDefaultInputConsumer(reasonString.append(SUBSTRING_PREFIX)
.append("running task == null"));
} else if (previousGestureAnimatedToLauncher
@@ -1130,7 +1135,7 @@
? "launcher resumed through a shell transition"
: "forceOverviewInputConsumer == true"))
.append(", trying to use overview input consumer"));
- } else if (mDeviceState.isGestureBlockedTask(gestureState.getRunningTask())) {
+ } else if (mDeviceState.isGestureBlockedTask(runningTask)) {
return getDefaultInputConsumer(reasonString.append(SUBSTRING_PREFIX)
.append("is gesture-blocked task, trying to use default input consumer"));
} else {
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index 1b3d759..f264364 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -208,7 +208,12 @@
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- if (ENABLE_SHELL_TRANSITIONS) {
+ if (dismissTask) {
+ // Just start the home intent so the user is prompted to unlock the device.
+ // This will come back and cancel the interaction.
+ startHomeIntentSafely(mContext, mGestureState.getHomeIntent(), null, TAG);
+ mHomeLaunched = true;
+ } else if (ENABLE_SHELL_TRANSITIONS) {
if (mTaskAnimationManager.getCurrentCallbacks() != null) {
if (mRecentsAnimationController != null) {
finishRecentsAnimationForShell(dismissTask);
@@ -218,11 +223,6 @@
mDismissTask = dismissTask;
}
}
- } else if (dismissTask) {
- // For now, just start the home intent so user is prompted to
- // unlock the device.
- startHomeIntentSafely(mContext, mGestureState.getHomeIntent(), null, TAG);
- mHomeLaunched = true;
}
mStateCallback.setState(STATE_HANDLER_INVALIDATED);
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
index 07c85bb..d38376c 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
@@ -120,7 +120,7 @@
if (longPressRunnable != null) {
OtherActivityInputConsumer oaic = getInputConsumerOfClass(
OtherActivityInputConsumer.class);
- if (oaic != null) {
+ if (oaic != null && oaic.hasStartedTouchTracking()) {
oaic.setForceFinishRecentsTransitionCallback(longPressRunnable);
setActive(mCurrentDownEvent);
} else {
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index e724547..eedd204 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -413,6 +413,14 @@
}
/**
+ * Returns whether this input consumer has started touch tracking (if touch tracking is not
+ * deferred).
+ */
+ public boolean hasStartedTouchTracking() {
+ return mInteractionHandler != null;
+ }
+
+ /**
* Called when the gesture has ended. Does not correlate to the completion of the interaction as
* the animation can still be running.
*/
diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
index d102502..a36f501 100644
--- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
@@ -19,6 +19,7 @@
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Color;
+import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Bundle;
import android.text.TextUtils;
@@ -26,6 +27,7 @@
import android.view.Display;
import android.view.View;
import android.view.Window;
+import android.view.WindowInsets;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -41,6 +43,7 @@
import com.android.quickstep.interaction.TutorialController.TutorialType;
import com.android.quickstep.util.TISBindHelper;
+import java.util.ArrayList;
import java.util.Arrays;
/** Shows the gesture interactive sandbox in full screen mode. */
@@ -101,8 +104,11 @@
correctUserOrientation();
}
mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
+
+ initWindowInsets();
}
+
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
@@ -113,6 +119,42 @@
}
}
+ private void initWindowInsets() {
+ View root = findViewById(android.R.id.content);
+ root.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ updateExclusionRects(root);
+ }
+ });
+
+ // Return CONSUMED if you don't want want the window insets to keep being
+ // passed down to descendant views.
+ root.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
+ @Override
+ public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
+ return WindowInsets.CONSUMED;
+ }
+ });
+ }
+
+ private void updateExclusionRects(View rootView) {
+ Insets gestureInsets = rootView.getRootWindowInsets()
+ .getInsets(WindowInsets.Type.systemGestures());
+ ArrayList<Rect> exclusionRects = new ArrayList<>();
+ // Add rect for left
+ exclusionRects.add(new Rect(0, 0, gestureInsets.left, rootView.getHeight()));
+ // Add rect for right
+ exclusionRects.add(new Rect(
+ rootView.getWidth() - gestureInsets.right,
+ 0,
+ rootView.getWidth(),
+ rootView.getHeight()
+ ));
+ rootView.setSystemGestureExclusionRects(exclusionRects);
+ }
+
/**
* Gesture animations are only in landscape for large screens and portrait for mobile. This
* method enforces the following flows:
diff --git a/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java b/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
index ee72144..4359294 100644
--- a/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
+++ b/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
@@ -147,24 +147,15 @@
break;
case TASK_APPEARED:
errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.SET_END_TARGET_NEW_TASK),
- prefix,
- /* errorMessage= */ "onTasksAppeared called "
- + "before/without setting end target to new task",
- writer);
- errorDetected |= printErrorIfTrue(
!encounteredEvents.contains(GestureEvent.EXPECTING_TASK_APPEARED),
prefix,
/* errorMessage= */ "onTasksAppeared was not expected to be called",
writer);
- break;
- case EXPECTING_TASK_APPEARED:
- errorDetected |= printErrorIfTrue(
- !encounteredEvents.contains(GestureEvent.SET_END_TARGET_NEW_TASK),
- prefix,
- /* errorMessage= */ "expecting onTasksAppeared to be called "
- + "before/without setting end target to new task",
- writer);
+ if (encounteredEvents.contains(GestureEvent.EXPECTING_TASK_APPEARED)) {
+ // Remove both events so that we can properly detect following errors.
+ encounteredEvents.remove(GestureEvent.EXPECTING_TASK_APPEARED);
+ encounteredEvents.remove(GestureEvent.TASK_APPEARED);
+ }
break;
case LAUNCHER_DESTROYED:
errorDetected |= printErrorIfTrue(
@@ -282,6 +273,7 @@
case START_RECENTS_ANIMATION:
lastStartRecentAnimationEventEntryTime = eventEntry.getTime();
break;
+ case EXPECTING_TASK_APPEARED:
case MOTION_DOWN:
case SET_END_TARGET:
case SET_END_TARGET_HOME:
diff --git a/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java b/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java
index 91b53c7..cb44a1a 100644
--- a/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java
+++ b/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java
@@ -25,6 +25,8 @@
import android.view.KeyEvent;
import android.view.MotionEvent;
+import androidx.annotation.Nullable;
+
import com.android.quickstep.InputConsumer;
import com.android.quickstep.SimpleOrientationTouchTransformer;
import com.android.systemui.shared.system.InputConsumerController;
@@ -42,7 +44,10 @@
private final Context mContext;
private final Supplier<Integer> mRotationSupplier;
private final InputConsumerController mInputConsumerController;
- private Runnable mCallback;
+
+ /** Called if a new InputConsumer is created via touch down event. */
+ private @Nullable Runnable mOnTouchDownCallback;
+
private Supplier<InputConsumer> mConsumerSupplier;
// The consumer is created lazily on demand.
@@ -54,11 +59,11 @@
public InputConsumerProxy(Context context, Supplier<Integer> rotationSupplier,
InputConsumerController inputConsumerController,
- Runnable callback, Supplier<InputConsumer> consumerSupplier) {
+ Runnable onTouchDownCallback, Supplier<InputConsumer> consumerSupplier) {
mContext = context;
mRotationSupplier = rotationSupplier;
mInputConsumerController = inputConsumerController;
- mCallback = callback;
+ mOnTouchDownCallback = onTouchDownCallback;
mConsumerSupplier = consumerSupplier;
}
@@ -82,7 +87,7 @@
onInputConsumerMotionEvent(event);
}
} else if (ev instanceof KeyEvent) {
- initInputConsumerIfNeeded();
+ initInputConsumerIfNeeded(/* isFromTouchDown= */ false);
mInputConsumer.onKeyEvent((KeyEvent) ev);
return true;
}
@@ -105,7 +110,7 @@
if (action == ACTION_DOWN) {
mTouchInProgress = true;
- initInputConsumerIfNeeded();
+ initInputConsumerIfNeeded(/* isFromTouchDown= */ true);
} else if (action == ACTION_CANCEL || action == ACTION_UP) {
// Finish any pending actions
mTouchInProgress = false;
@@ -123,7 +128,7 @@
}
private void onInputConsumerHoverEvent(MotionEvent ev) {
- initInputConsumerIfNeeded();
+ initInputConsumerIfNeeded(/* isFromTouchDown= */ false);
if (mInputConsumer != null) {
SimpleOrientationTouchTransformer.INSTANCE.get(mContext).transform(ev,
mRotationSupplier.get());
@@ -141,14 +146,15 @@
mInputConsumerController.setInputListener(null);
}
- public void unregisterCallback() {
- mCallback = null;
+ /** Sets mOnToudhCownCallback = null. */
+ public void unregisterOnTouchDownCallback() {
+ mOnTouchDownCallback = null;
}
- private void initInputConsumerIfNeeded() {
+ private void initInputConsumerIfNeeded(boolean isFromTouchDown) {
if (mInputConsumer == null) {
- if (mCallback != null) {
- mCallback.run();
+ if (isFromTouchDown && mOnTouchDownCallback != null) {
+ mOnTouchDownCallback.run();
}
mInputConsumer = mConsumerSupplier.get();
mConsumerSupplier = null;
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
index 3748a24..bdbdfd8 100644
--- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
@@ -16,7 +16,7 @@
package com.android.quickstep.util;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS;
+import static com.android.launcher3.config.FeatureFlags.enableSplitFromFullscreenWithKeyboardShortcuts;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
@@ -191,7 +191,7 @@
}
private boolean shouldIgnoreSecondSplitLaunch() {
- return (!ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS.get()
+ return (!enableSplitFromFullscreenWithKeyboardShortcuts()
&& !FeatureFlags.enableSplitContextually()
&& !isDesktopModeSupported())
|| !mController.isSplitSelectActive();
diff --git a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
index f3fa86a..8f719d0 100644
--- a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
@@ -16,7 +16,7 @@
package com.android.quickstep.util;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS;
+import static com.android.launcher3.config.FeatureFlags.enableSplitFromFullscreenWithKeyboardShortcuts;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_KEYBOARD_SHORTCUT_SPLIT_LEFT_TOP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_KEYBOARD_SHORTCUT_SPLIT_RIGHT_BOTTOM;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -75,7 +75,7 @@
@BinderThread
public void enterStageSplit(boolean leftOrTop) {
- if (!ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS.get()) {
+ if (!enableSplitFromFullscreenWithKeyboardShortcuts()) {
return;
}
RecentsAnimationCallbacks callbacks = new RecentsAnimationCallbacks(
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index fce38e1..fe6ce46 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -159,8 +159,8 @@
// to other classes like PipTaskOrganizer / RecentsAnimationController to complete
// the cleanup.
mPipContentOverlay = new PipContentOverlay.PipAppIconOverlay(view.getContext(),
- mAppBounds, new IconProvider(context).getIcon(mActivityInfo),
- appIconSizePx);
+ mAppBounds, mDestinationBounds,
+ new IconProvider(context).getIcon(mActivityInfo), appIconSizePx);
final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
mPipContentOverlay.attach(tx, mLeash);
} else {
diff --git a/quickstep/src/com/android/quickstep/util/TransformParams.java b/quickstep/src/com/android/quickstep/util/TransformParams.java
index ca680db..ebcef30 100644
--- a/quickstep/src/com/android/quickstep/util/TransformParams.java
+++ b/quickstep/src/com/android/quickstep/util/TransformParams.java
@@ -16,13 +16,10 @@
package com.android.quickstep.util;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import android.util.FloatProperty;
import android.view.RemoteAnimationTarget;
-import com.android.app.animation.Interpolators;
-import com.android.launcher3.Utilities;
import com.android.quickstep.RemoteAnimationTargets;
import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
@@ -152,19 +149,7 @@
if (activityType == ACTIVITY_TYPE_HOME) {
mHomeBuilderProxy.onBuildTargetParams(builder, app, this);
} else {
- // Fade out translucent overlay.
- // TODO(b/303351074): use app.isNotInRecents directly once it is fixed.
- boolean isNotInRecents = app.taskInfo != null
- && (app.taskInfo.baseIntent.getFlags()
- & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0;
- if (app.isTranslucent && isNotInRecents) {
- float progress = Utilities.boundToRange(getProgress(), 0, 1);
- builder.setAlpha(1 - Interpolators.DECELERATE_QUINT
- .getInterpolation(progress));
- } else {
- builder.setAlpha(getTargetAlpha());
- }
-
+ builder.setAlpha(getTargetAlpha());
proxy.onBuildTargetParams(builder, app, this);
}
} else {
diff --git a/quickstep/src/com/android/quickstep/views/ActionButton.kt b/quickstep/src/com/android/quickstep/views/ActionButton.kt
new file mode 100644
index 0000000..5c004cc
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/ActionButton.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.views
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.Button
+
+/**
+ * A button on the Overview Actions Bar. Custom logic for hiding/showing each button type is handled
+ * in the respective subclass.
+ */
+open class ActionButton : Button {
+ private var mHiddenFlags = 0
+
+ constructor(context: Context) : super(context)
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ defStyleAttr: Int
+ ) : super(context, attrs, defStyleAttr)
+
+ /**
+ * Updates the proper flags to indicate whether the button should be hidden.
+ *
+ * @param flag The flag to update.
+ * @param enable Whether to enable the hidden flag: True will cause view to be hidden.
+ */
+ protected fun updateHiddenFlags(flag: Int, enable: Boolean) {
+ if (enable) {
+ mHiddenFlags = mHiddenFlags or flag
+ } else {
+ mHiddenFlags = mHiddenFlags and flag.inv()
+ }
+ val shouldBeVisible = mHiddenFlags == 0
+ this.visibility = if (shouldBeVisible) VISIBLE else GONE
+ }
+
+ /** Show/hide the button when the focused task is a single/pair. */
+ open fun updateForMultipleTasks(hasMultipleTasks: Boolean) {
+ // overridden in subclass, or else don't do anything
+ }
+
+ /** Show/hide the button depending on if the device is a tablet. */
+ open fun updateForTablet(isTablet: Boolean) {
+ // overridden in subclass, or else don't do anything
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 7f1d619..8692e4e 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -22,7 +22,6 @@
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
-import android.widget.Button;
import android.widget.FrameLayout;
import androidx.annotation.IntDef;
@@ -41,6 +40,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
/**
* View for showing action buttons in Overview
@@ -89,14 +90,11 @@
private static final int INDEX_SCROLL_ALPHA = 5;
private static final int NUM_ALPHAS = 6;
- public @interface SplitButtonHiddenFlags { }
- public static final int FLAG_IS_NOT_TABLET = 1 << 0;
-
- public @interface SplitButtonDisabledFlags { }
- public static final int FLAG_SINGLE_TASK = 1 << 0;
-
private MultiValueAlpha mMultiValueAlpha;
- private Button mSplitButton;
+
+ private List<ActionButton> mActionButtons = new ArrayList<>();
+ private ScreenshotActionButton mScreenshotButton;
+ private SplitActionButton mSplitButton;
@ActionsHiddenFlags
private int mHiddenFlags;
@@ -104,12 +102,6 @@
@ActionsDisabledFlags
protected int mDisabledFlags;
- @SplitButtonHiddenFlags
- private int mSplitButtonHiddenFlags;
-
- @SplitButtonDisabledFlags
- private int mSplitButtonDisabledFlags;
-
@Nullable
protected T mCallbacks;
@@ -135,9 +127,12 @@
mMultiValueAlpha = new MultiValueAlpha(findViewById(R.id.action_buttons), NUM_ALPHAS);
mMultiValueAlpha.setUpdateVisibility(true);
- findViewById(R.id.action_screenshot).setOnClickListener(this);
+ mScreenshotButton = findViewById(R.id.action_screenshot);
+ mScreenshotButton.setOnClickListener(this);
+ mActionButtons.add(mScreenshotButton);
mSplitButton = findViewById(R.id.action_split);
mSplitButton.setOnClickListener(this);
+ mActionButtons.add(mSplitButton);
}
/**
@@ -201,40 +196,28 @@
}
boolean isEnabled = (mDisabledFlags & ~DISABLED_ROTATED) == 0;
LayoutUtils.setViewEnabled(this, isEnabled);
- updateSplitButtonEnabledState();
}
/**
- * Updates the proper flags to indicate whether the "Split screen" button should be hidden.
- *
- * @param flag The flag to update.
- * @param enable Whether to enable the hidden flag: True will cause view to be hidden.
+ * Updates flags to hide and show actions buttons when a grouped task (split screen) is focused.
+ * @param isGroupedTask True if the focused task is a grouped task.
*/
- public void updateSplitButtonHiddenFlags(@SplitButtonHiddenFlags int flag, boolean enable) {
- if (enable) {
- mSplitButtonHiddenFlags |= flag;
- } else {
- mSplitButtonHiddenFlags &= ~flag;
+ public void updateForGroupedTask(boolean isGroupedTask) {
+ for (ActionButton button : mActionButtons) {
+ // Update flags to show/hide buttons.
+ button.updateForMultipleTasks(isGroupedTask);
}
- if (mSplitButton == null) return;
- boolean shouldBeVisible = mSplitButtonHiddenFlags == 0;
- mSplitButton.setVisibility(shouldBeVisible ? VISIBLE : GONE);
- findViewById(R.id.action_split_space).setVisibility(shouldBeVisible ? VISIBLE : GONE);
}
/**
- * Updates the proper flags to indicate whether the "Split screen" button should be disabled.
- *
- * @param flag The flag to update.
- * @param enable Whether to enable the disable flag: True will cause view to be disabled.
+ * Updates flags to hide and show actions buttons depending on if the device is a tablet.
+ * @param isTablet True if the current device is a tablet.
*/
- public void updateSplitButtonDisabledFlags(@SplitButtonDisabledFlags int flag, boolean enable) {
- if (enable) {
- mSplitButtonDisabledFlags |= flag;
- } else {
- mSplitButtonDisabledFlags &= ~flag;
+ public void updateForTablet(boolean isTablet) {
+ for (ActionButton button : mActionButtons) {
+ // Update flags to show/hide buttons.
+ button.updateForTablet(isTablet);
}
- updateSplitButtonEnabledState();
}
public MultiProperty getContentAlpha() {
@@ -312,18 +295,4 @@
(dp.isLandscape ? R.drawable.ic_split_horizontal : R.drawable.ic_split_vertical),
0, 0, 0);
}
-
- /**
- * Enables/disables the "Split" button based on the status of mSplitButtonDisabledFlags and
- * mDisabledFlags.
- */
- private void updateSplitButtonEnabledState() {
- if (mSplitButton == null) {
- return;
- }
- boolean isParentEnabled = (mDisabledFlags & ~DISABLED_ROTATED) == 0;
- boolean shouldBeEnabled = mSplitButtonDisabledFlags == 0 && isParentEnabled;
- mSplitButton.setEnabled(shouldBeEnabled);
- }
-
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 7972999..6a275e6 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -20,7 +20,6 @@
import static android.view.Surface.ROTATION_0;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.makeMeasureSpec;
-
import static com.android.app.animation.Interpolators.ACCELERATE;
import static com.android.app.animation.Interpolators.ACCELERATE_0_75;
import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE;
@@ -34,6 +33,7 @@
import static com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU;
import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
+import static com.android.launcher3.Flags.enableGridOnlyOverview;
import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
@@ -42,7 +42,6 @@
import static com.android.launcher3.Utilities.mapToRange;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.Utilities.squaredTouchSlop;
-import static com.android.launcher3.Flags.enableGridOnlyOverview;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_ACTIONS_SPLIT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_CLEAR_ALL;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP;
@@ -57,8 +56,6 @@
import static com.android.quickstep.util.LogUtils.splitFailureMessage;
import static com.android.quickstep.views.ClearAllButton.DISMISS_ALPHA;
import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
-import static com.android.quickstep.views.OverviewActionsView.FLAG_IS_NOT_TABLET;
-import static com.android.quickstep.views.OverviewActionsView.FLAG_SINGLE_TASK;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_ACTIONS_IN_MENU;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_DESKTOP;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NON_ZERO_ROTATION;
@@ -3927,18 +3924,23 @@
}
/**
- * Hides all overview actions if current page is for split apps, shows otherwise
- * If actions are showing, we only show split option if
+ * Hides all overview actions if user is halfway through split selection, shows otherwise.
+ * We only show split option if:
+ * * Focused view is a single app
* * Device is large screen
- * * There are at least 2 tasks to invoke split
*/
private void updateCurrentTaskActionsVisibility() {
- boolean isCurrentSplit = getCurrentPageTaskView() instanceof GroupedTaskView;
- mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SCREEN, isCurrentSplit);
+ boolean isGroupedTask = getCurrentPageTaskView() != null
+ && getCurrentPageTaskView().containsMultipleTasks();
+ // Update flags to see if entire actions bar should be hidden.
+ mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SCREEN, isGroupedTask);
mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SELECT_ACTIVE, isSplitSelectionActive());
- mActionsView.updateSplitButtonHiddenFlags(FLAG_IS_NOT_TABLET,
- !mActivity.getDeviceProfile().isTablet);
- mActionsView.updateSplitButtonDisabledFlags(FLAG_SINGLE_TASK, /*enable=*/ false);
+ // Update flags to see if actions bar should show buttons for a single task or a pair of
+ // tasks.
+ mActionsView.updateForGroupedTask(isGroupedTask);
+ // Update flags to see if split button should be hidden.
+ mActionsView.updateForTablet(mActivity.getDeviceProfile().isTablet);
+
if (isDesktopModeSupported()) {
boolean isCurrentDesktop = getCurrentPageTaskView() instanceof DesktopTaskView;
mActionsView.updateHiddenFlags(HIDDEN_DESKTOP, isCurrentDesktop);
diff --git a/quickstep/src/com/android/quickstep/views/ScreenshotActionButton.kt b/quickstep/src/com/android/quickstep/views/ScreenshotActionButton.kt
new file mode 100644
index 0000000..9cb48b8
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/ScreenshotActionButton.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.views
+
+import android.content.Context
+import android.util.AttributeSet
+
+/** A button on the Overview Actions Bar for screenshotting the focused app. */
+class ScreenshotActionButton : ActionButton {
+ companion object {
+ const val FLAG_MULTIPLE_TASKS_HIDE_SCREENSHOT = 1 shl 0
+ }
+
+ constructor(context: Context) : super(context)
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ defStyleAttr: Int
+ ) : super(context, attrs, defStyleAttr)
+
+ /** Show/hide the button when the focused task is a single/pair. */
+ override fun updateForMultipleTasks(hasMultipleTasks: Boolean) {
+ // Hidden for multiple tasks
+ updateHiddenFlags(FLAG_MULTIPLE_TASKS_HIDE_SCREENSHOT, hasMultipleTasks)
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/SplitActionButton.kt b/quickstep/src/com/android/quickstep/views/SplitActionButton.kt
new file mode 100644
index 0000000..88d1a77
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/SplitActionButton.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.views
+
+import android.content.Context
+import android.util.AttributeSet
+
+/** A button on the Overview Actions Bar for initiating split screen. */
+class SplitActionButton : ActionButton {
+ companion object {
+ const val FLAG_IS_NOT_TABLET_HIDE_SPLIT = 1 shl 0
+ const val FLAG_MULTIPLE_TASKS_HIDE_SPLIT = 1 shl 1
+ }
+
+ constructor(context: Context) : super(context)
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ defStyleAttr: Int
+ ) : super(context, attrs, defStyleAttr)
+
+ /** Show/hide the button when the focused task is a single/pair. */
+ override fun updateForMultipleTasks(hasMultipleTasks: Boolean) {
+ // Hidden for multiple tasks
+ updateHiddenFlags(FLAG_MULTIPLE_TASKS_HIDE_SPLIT, hasMultipleTasks)
+ }
+
+ /** Show/hide the button depending on if the device is a tablet. */
+ override fun updateForTablet(isTablet: Boolean) {
+ // Hidden for non-tablets
+ updateHiddenFlags(FLAG_IS_NOT_TABLET_HIDE_SPLIT, !isTablet)
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 94183c4..ab51a70 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -35,6 +35,7 @@
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition;
import static com.android.quickstep.TaskOverlayFactory.getEnabledShortcuts;
+import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.EXPECTING_TASK_APPEARED;
import static com.android.quickstep.util.BorderAnimator.DEFAULT_BORDER_COLOR;
import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
@@ -106,6 +107,7 @@
import com.android.quickstep.TaskThumbnailCache;
import com.android.quickstep.TaskUtils;
import com.android.quickstep.TaskViewUtils;
+import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.BorderAnimator;
import com.android.quickstep.util.CancellableTask;
import com.android.quickstep.util.RecentsOrientedState;
@@ -859,6 +861,7 @@
getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
if (ActivityManagerWrapper.getInstance()
.startActivityFromRecents(mTask.key, opts.options)) {
+ ActiveGestureLog.INSTANCE.trackEvent(EXPECTING_TASK_APPEARED);
RecentsView recentsView = getRecentsView();
if (recentsView.getRunningTaskViewId() != -1) {
recentsView.onTaskLaunchedInLiveTileMode();
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
index 37fcf43..9c7f014 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
@@ -12,6 +12,7 @@
import androidx.test.runner.AndroidJUnit4
import com.android.launcher3.DeviceProfile
import com.android.launcher3.R
+import com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION
import com.android.launcher3.taskbar.TaskbarManager
import com.android.systemui.shared.rotation.RotationButton
import java.lang.IllegalStateException
@@ -59,7 +60,7 @@
@Test
fun getKidsLayoutter() {
- assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
+ assumeTrue(ENABLE_TASKBAR_NAVBAR_UNIFICATION)
mockDeviceProfile.isTaskbarPresent = true
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
getLayoutter(
@@ -74,7 +75,7 @@
@Test
fun getSetupLayoutter() {
- assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
+ assumeTrue(ENABLE_TASKBAR_NAVBAR_UNIFICATION)
mockDeviceProfile.isTaskbarPresent = true
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
getLayoutter(
@@ -89,7 +90,7 @@
@Test
fun getTaskbarNavLayoutter() {
- assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
+ assumeTrue(ENABLE_TASKBAR_NAVBAR_UNIFICATION)
mockDeviceProfile.isTaskbarPresent = true
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
getLayoutter(
@@ -104,7 +105,7 @@
@Test(expected = IllegalStateException::class)
fun noValidLayoutForLargeScreenTaskbarNotPresent() {
- assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
+ assumeTrue(ENABLE_TASKBAR_NAVBAR_UNIFICATION)
mockDeviceProfile.isTaskbarPresent = false
getLayoutter(
isKidsMode = false,
@@ -117,7 +118,7 @@
@Test
fun getTaskbarPortraitLayoutter() {
- assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
+ assumeTrue(ENABLE_TASKBAR_NAVBAR_UNIFICATION)
mockDeviceProfile.isTaskbarPresent = false
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
getLayoutter(
@@ -132,7 +133,7 @@
@Test
fun getTaskbarLandscapeLayoutter() {
- assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
+ assumeTrue(ENABLE_TASKBAR_NAVBAR_UNIFICATION)
mockDeviceProfile.isTaskbarPresent = false
setDeviceProfileLandscape()
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
@@ -148,7 +149,7 @@
@Test
fun getTaskbarSeascapeLayoutter() {
- assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
+ assumeTrue(ENABLE_TASKBAR_NAVBAR_UNIFICATION)
mockDeviceProfile.isTaskbarPresent = false
setDeviceProfileLandscape()
val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
@@ -164,7 +165,7 @@
@Test(expected = IllegalStateException::class)
fun noValidLayoutForPhoneGestureNav() {
- assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
+ assumeTrue(ENABLE_TASKBAR_NAVBAR_UNIFICATION)
mockDeviceProfile.isTaskbarPresent = false
getLayoutter(
isKidsMode = false,
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 12568ea..17fa253 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -162,8 +162,7 @@
@Before
public void setUp() {
mLauncher.onTestStart();
- AbstractLauncherUiTest.waitForSetupWizardDismissal();
- AbstractLauncherUiTest.verifyKeyguardInvisible();
+ AbstractLauncherUiTest.onTestStart();
}
@After
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index a5d7724..df88726 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -185,7 +185,7 @@
+ launcher.getNavigationModeMismatchError(false),
() -> launcher.getNavigationModeMismatchError(false) == null,
WAIT_TIME_MS, launcher);
- AbstractLauncherUiTest.checkDetectedLeaks(launcher, true);
+ AbstractLauncherUiTest.checkDetectedLeaks(launcher, false);
return true;
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
index f51f286..c4c95bc 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
@@ -16,6 +16,8 @@
package com.android.quickstep;
import static com.android.launcher3.ui.TaplTestsLauncher3.initialize;
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -25,6 +27,7 @@
import com.android.launcher3.tapl.OverviewTaskMenu;
import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.util.rule.TestStabilityRule;
import org.junit.Before;
import org.junit.Test;
@@ -72,6 +75,7 @@
}
@Test
+ @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/288939273
public void testSplitTaskTapBothIconMenus() {
createAndLaunchASplitPair();
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 0ee0b67..ff8537b 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -16,6 +16,8 @@
package com.android.quickstep;
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT;
import static com.android.quickstep.TaskbarModeSwitchRule.Mode.TRANSIENT;
@@ -46,6 +48,7 @@
import com.android.launcher3.ui.TaplTestsLauncher3;
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
+import com.android.launcher3.util.rule.TestStabilityRule;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
import com.android.quickstep.views.RecentsView;
@@ -348,7 +351,7 @@
@PortraitLandscape
@TaskbarModeSwitch(mode = PERSISTENT)
@PlatinumTest(focusArea = "launcher")
- @ScreenRecord
+ @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/309820115
public void testOverviewForTablet() throws Exception {
assumeTrue(mLauncher.isTablet());
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index ee0fbb8..d3bf56f 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -108,7 +108,6 @@
}
@Test
- @Ignore("Enable once App Pairs flagged on. These cause memory leaks b/297135374")
public void testSaveAppPairMenuItemExistsOnSplitPair() throws Exception {
assumeTrue("App pairs feature is currently not enabled, no test needed",
Flags.enableAppPairs());
@@ -124,7 +123,6 @@
}
@Test
- @Ignore("Enable once App Pairs flagged on. These cause memory leaks b/297135374")
public void testSaveAppPairMenuItemDoesNotExistOnSingleTask() throws Exception {
assumeTrue("App pairs feature is currently not enabled, no test needed",
Flags.enableAppPairs());
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index dc57332..dd966cc 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Deursoek jou tablet"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Misluk: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privaat ruimte"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 4bfea99..bc2cc86 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"ጡባዊዎን ይፈልጉ"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"አልተሳካም፦ <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"የግል ቦታ"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 9cbfbfa..a3e5889 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"البحث في جهازك اللوحي"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"تعذَّر <xliff:g id="WHAT">%1$s</xliff:g>."</string>
<string name="private_space_label" msgid="2359721649407947001">"مساحة خاصة"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 6368312..f7c1b40 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"আপোনাৰ টেবলেটৰ বস্তু সন্ধান কৰক"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"বিফল: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"ব্যক্তিগত স্পে’চ"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 2ec448d..3b20be8 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Planşetinizi axtarın"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Alınmadı: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Şəxsi yer"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 81da8a8..4b7b663 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Pretražite tablet"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nije uspelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privatni prostor"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 5bbac0f..4616b8e 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Пошук на планшэце"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Не ўдалося: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Прыватная вобласць"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index bdae209..c4be1f4 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Търсене в таблета ви"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Неуспешно: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Лично пространство"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 3a57581..a4dce63 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"আপনার ট্যাবলেটে সার্চ করুন"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"কাজটি করা যায়নি: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"ব্যক্তিগত স্পেস"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index e453982..9d7419f 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Pretražite tablet"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nije uspjelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privatan prostor"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index b03b4ec..fedea5d 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Cerca a la tauleta"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Error: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espai privat"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index a39a1d5..c721f56 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Vyhledávání na tabletu"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Selhalo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Soukromý prostor"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index faebb41..5c0423a 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Søg på din tablet"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Mislykket: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privat rum"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 61e4859..40f1c74 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Auf dem Tablet suchen"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Fehler: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privater Bereich"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index b98ae4f..cc5d0bd 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Αναζήτηση στο tablet σας"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Αποτυχία: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Ιδιωτικός χώρος"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 8e55910..9b0cde6 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Search your tablet"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index c5e5caf..c78355a 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Search your tablet"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 8e55910..9b0cde6 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Search your tablet"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 8e55910..9b0cde6 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Search your tablet"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 1ad2059..9aaf4d2 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Search your tablet"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index b8d213b..3d830c4 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Busca en tu tablet"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Error: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espacio privado"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index c13ce1a..cb35617 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Buscar en tu tablet"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Se ha producido un error: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espacio privado"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 76bd494..60a0a04 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Otsimine tahvelarvutist"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nurjus: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privaatne ruum"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index d73c885..4f4645f 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Bilatu tabletan"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Huts egin du: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Eremu pribatua"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index fc42f54..3129c10 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"جستجوی رایانه لوحی"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"ناموفق بود: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"فضای خصوصی"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index a567eba..9147b36 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Hae tabletilta"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Epäonnistui: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Yksityinen tila"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index a6f5053..b739c95 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Rechercher sur votre tablette"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Échec : <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espace privé"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 9e09a5c..eca5f51 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Rechercher sur votre tablette"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Échec : <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espace privé"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 41c30c2..82edb6d 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Facer buscas na tableta"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Erro: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espazo privado"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 71aebc4..ca79a3f 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"તમારું ટૅબ્લેટ શોધો"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"નિષ્ફળ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"ખાનગી સ્પેસ"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index a9f9ecd..d1ea837 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"अपने टैबलेट में खोजें"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"पूरा नहीं हुआ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"प्राइवेट स्पेस"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 757f335..90f36b9 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Pretraživanje tableta"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nije uspjelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privatni prostor"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 6c43388..bae2c81 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Keresés a táblagépen"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Sikertelen: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privát terület"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 6eae2b6..76857db 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Որոնում պլանշետում"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Չհաջողվեց կատարել գործողությունը (<xliff:g id="WHAT">%1$s</xliff:g>)"</string>
<string name="private_space_label" msgid="2359721649407947001">"Անձնական տարածք"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index a47ec3b..8301a5d 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Telusuri di tablet"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Gagal: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Ruang pribadi"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 9e9be03..5bd6356 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Leita í spjaldtölvunni"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Mistókst: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Einkarými"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 407a492..dd385c3 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Ricerche sul tablet"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Operazione non riuscita: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Spazio privato"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index e87cfaf..1eb4f4e 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"חיפוש בטאבלט"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"הפעולה נכשלה: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"מרחב פרטי"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index e8a72eb..35d97a9 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"タブレットを探す"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"失敗: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"プライベート スペース"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index ab6e962..b4af601 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"ძიება თქვენს ტაბლეტში"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"ვერ მოხერხდა: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"პირადი სივრცე"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index c18a43f..9c15ca4 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Планшеттен іздеу"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Қате шықты: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Жеке бөлме"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 4aa1878..363690c 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"ស្វែងរកក្នុងថេប្លេតរបស់អ្នក"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"បានបរាជ័យ៖ <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"បន្ទប់ឯកជន"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 138e1b3..88aeab5 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಹುಡುಕಿ"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"ವಿಫಲವಾಗಿದೆ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"ಖಾಸಗಿ ಸ್ಪೇಸ್"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 7803d09..1f92b4d 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"태블릿 속 항목 검색"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"실패: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"비공개 스페이스"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index a9da5b8..aa24cdd 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Планшетте издөө"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Аткарылган жок: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Жеке чөйрө"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 1dc9a91..dfa4d48 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"ຊອກຫາແທັບເລັດຂອງທ່ານ"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"ບໍ່ສຳເລັດ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"ພື້ນທີ່ສ່ວນຕົວ"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 1666f47..d8e4b0c 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Paieška planšetiniame kompiuteryje"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nepavyko: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privati erdvė"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 420d3d6..f2b63c2 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Meklēšana planšetdatorā"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Neizdevās: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privātā telpa"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 841aba7..5b7973a 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Пребарување низ таблетот"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Не успеа: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Приватен простор"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index df39e74..5507eb7 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"നിങ്ങളുടെ ടാബ്ലെറ്റിലുള്ളവ തിരയുക"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"പരാജയപ്പെട്ടു: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"സ്വകാര്യ സ്പേസ്"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index ad89209..2cc2ae3 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Таблетнаасаа хайх"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Амжилтгүй болсон: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Хувийн орон зай"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index a14459c..c0beed2 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"तुमच्या टॅबलेटमध्ये शोधा"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"हे करता आले नाही: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"खाजगी स्पेस"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 75a50b0..8ec5ba0 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Cari pada tablet anda"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Gagal: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Ruang peribadi"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index a4d2417..1463620 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"သင့်တက်ဘလက်ကို ရှာခြင်း"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"မအောင်မြင်ပါ− <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"သီးသန့်ချတ်ခန်း"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index aea53fa..90ff503 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Søk på nettbrettet"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Mislyktes: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privat område"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index b5760d7..e02bf66 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"आफ्नो ट्याबलेटमा खोज्नुहोस्"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"कार्य पूरा गर्न सकिएन: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"निजी स्पेस"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 7f362ec..f143c1e 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Zoeken op je tablet"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Mislukt: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privéruimte"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 406b176..4bf50fa 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"ଆପଣଙ୍କ ଟାବଲେଟରେ ସନ୍ଧାନ କରନ୍ତୁ"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"ବିଫଳ ହୋଇଛି: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"ପ୍ରାଇଭେଟ ସ୍ପେସ"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 837eba0..0d9848e 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"ਆਪਣਾ ਟੈਬਲੈੱਟ ਖੋਜੋ"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"ਇਹ ਕਾਰਵਾਈ ਅਸਫਲ ਹੋਈ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"ਨਿੱਜੀ ਸਪੇਸ"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 24f09f9..faf5dfa 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Przeszukuj tablet"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Niepowodzenie: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Obszar prywatny"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 0febbd1..1b3a8de 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Pesquise no tablet"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Falhou: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espaço privado"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index ad8e0c0..ec0c02c 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Pesquisar no tablet"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Falha: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espaço particular"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 46f5b40..648f7e9 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Caută pe tabletă"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Eșuare: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Spațiu privat"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 79e1781..5918868 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Поиск на планшете"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Не удалось выполнить действие (<xliff:g id="WHAT">%1$s</xliff:g>)."</string>
<string name="private_space_label" msgid="2359721649407947001">"Личное пространство"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 72c0491..f7cd68b 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"ඔබගේ ටැබ්ලටය සොයන්න"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"අසාර්ථකයි: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"පෞද්ගලික ඉඩ"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index bf01b32..b519127 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Vyhľadávanie v tablete"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Zlyhalo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Súkromný priestor"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 52d8584..78c8b55 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Iskanje po tabličnem računalniku"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Ni uspelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Zasebni prostor"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 2c072ee..95ec874 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Kërko në tabletin tënd"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Dështoi: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Hapësira private"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index ee66f12..d58af08 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Претражите таблет"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Није успело: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Приватни простор"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 57fb8be..9cf1001 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Sök på surfplattan"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Misslyckades: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privat rum"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index b735318..1797dd3 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Tafuta kwenye kompyuta kibao yako"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Hitilafu: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Nafasi ya faragha"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 85a7a66..c81f62a 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"உங்கள் டேப்லெட்டில் தேடுதல்"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"தோல்வி: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"தனிப்பட்ட சேமிப்பிடம்"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index ee4d7ca..6cfdd0b 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"మీ టాబ్లెట్లో సెర్చ్ చేయండి"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"విఫలమైంది: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"ప్రైవేట్ స్పేస్"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 047e2b1..4bfccaa 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"ค้นหาในแท็บเล็ต"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"ไม่สำเร็จ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"พื้นที่ส่วนตัว"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index e17abc8..05af221 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Maghanap sa iyong tablet"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Hindi nagawa: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Pribadong space"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 9994adf..ec24a9d 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Tabletinizde arama yapma"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Başarısız: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Gizli alan"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index a638609..c7b2f7f 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Пошук на планшеті"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Не вдалося <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Приватний простір"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 92b8b41..857cf5b 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"اپنے ٹیبلیٹ پر تلاش کریں"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"ناکام ہو گيا: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"نجی اسپیس"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 2e3bfed..972a246 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Planshetingizni qidiring"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Xato: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Shaxsiy xona"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 85f48a6..f720c8d 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Tìm kiếm trong máy tính bảng của bạn"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Không thực hiện được thao tác: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Không gian riêng tư"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 69f6bcf..8c5bac0 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"平板电脑内搜索"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"失败:<xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"私密空间"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 1af7766..02225a7 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"搜尋平板電腦內容"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"操作失敗:<xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"私人空間"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 47d6f14..4483de4 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"搜尋平板電腦內容"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"失敗:<xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"私人空間"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 4871d8f..580a3be 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -176,4 +176,6 @@
<string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Sesha ithebulethi yakho"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Yehlulekile: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Isikhala esiyimfihlo"</string>
+ <!-- no translation found for bubble_bar_overflow_description (7410995531938041192) -->
+ <skip />
</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index f046eca..3682830 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -261,30 +261,34 @@
<!-- Responsive grids attributes -->
<declare-styleable name="ResponsiveSpec">
- <attr name="specType" format="integer">
+ <attr name="dimensionType" format="integer">
<enum name="height" value="0" />
<enum name="width" value="1" />
</attr>
<attr name="maxAvailableSize" format="dimension" />
</declare-styleable>
+ <declare-styleable name="ResponsiveSpecGroup">
+ <attr name="maxAspectRatio" format="float" />
+ </declare-styleable>
+
<declare-styleable name="WorkspaceSpec">
- <attr name="specType" />
+ <attr name="dimensionType" />
<attr name="maxAvailableSize" />
</declare-styleable>
<declare-styleable name="FolderSpec">
- <attr name="specType" />
+ <attr name="dimensionType" />
<attr name="maxAvailableSize" />
</declare-styleable>
<declare-styleable name="AllAppsSpec">
- <attr name="specType" />
+ <attr name="dimensionType" />
<attr name="maxAvailableSize" />
</declare-styleable>
<declare-styleable name="HotseatSpec">
- <attr name="specType" />
+ <attr name="dimensionType" />
<attr name="maxAvailableSize" />
</declare-styleable>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 81c2337..c0a1e0a 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -284,7 +284,8 @@
<dimen name="pre_drag_view_scale">6dp</dimen>
<!-- an icon with shortcuts must be dragged this far before the container is removed. -->
<dimen name="deep_shortcuts_start_drag_threshold">16dp</dimen>
- <dimen name="deep_shortcut_icon_size">32dp</dimen>
+ <!-- Possibly related to b/235886078, icon needs to be scaled up to match expected visual size of 32 dp -->
+ <dimen name="deep_shortcut_icon_size">35dp</dimen>
<dimen name="popup_margin">2dp</dimen>
<dimen name="popup_single_item_radius">100dp</dimen>
<dimen name="popup_smaller_radius">4dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4e865d0..f08f8f0 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -456,4 +456,8 @@
<!-- Private space label -->
<string name="private_space_label">Private space</string>
+
+ <!-- Strings for bubble bar -->
+ <!-- content description for the overflow bubble [CHAR_LIMIT=none] -->
+ <string name="bubble_bar_overflow_description">Overflow</string>
</resources>
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 189db21..79b831e 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -32,6 +32,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.Px;
+import com.android.launcher3.LauncherConstants.ActivityCodes;
import com.android.launcher3.accessibility.DragViewStateAnnouncer;
import com.android.launcher3.celllayout.CellLayoutLayoutParams;
import com.android.launcher3.celllayout.CellPosMapper.CellPos;
@@ -270,7 +271,7 @@
.startConfigActivity(
mLauncher,
mWidgetView.getAppWidgetId(),
- Launcher.REQUEST_RECONFIGURE_APPWIDGET);
+ ActivityCodes.REQUEST_RECONFIGURE_APPWIDGET);
});
if (!hasSeenReconfigurableWidgetEducationTip()) {
post(() -> {
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 73cd8c4..fed031b 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -17,6 +17,7 @@
package com.android.launcher3;
import static com.android.app.animation.Interpolators.LINEAR;
+import static com.android.launcher3.Flags.enableOverviewIconMenu;
import static com.android.launcher3.InvariantDeviceProfile.INDEX_DEFAULT;
import static com.android.launcher3.InvariantDeviceProfile.INDEX_LANDSCAPE;
import static com.android.launcher3.InvariantDeviceProfile.INDEX_TWO_PANEL_LANDSCAPE;
@@ -24,7 +25,6 @@
import static com.android.launcher3.Utilities.dpiFromPx;
import static com.android.launcher3.Utilities.pxFromSp;
import static com.android.launcher3.config.FeatureFlags.ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH;
-import static com.android.launcher3.Flags.enableOverviewIconMenu;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR;
import static com.android.launcher3.icons.GraphicsUtils.getShapePath;
import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
@@ -54,14 +54,12 @@
import com.android.launcher3.icons.DotRenderer;
import com.android.launcher3.icons.IconNormalizer;
import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.responsive.AllAppsSpecs;
-import com.android.launcher3.responsive.CalculatedAllAppsSpec;
-import com.android.launcher3.responsive.CalculatedFolderSpec;
import com.android.launcher3.responsive.CalculatedHotseatSpec;
-import com.android.launcher3.responsive.CalculatedWorkspaceSpec;
-import com.android.launcher3.responsive.FolderSpecs;
-import com.android.launcher3.responsive.HotseatSpecs;
-import com.android.launcher3.responsive.WorkspaceSpecs;
+import com.android.launcher3.responsive.CalculatedResponsiveSpec;
+import com.android.launcher3.responsive.HotseatSpecsProvider;
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType;
+import com.android.launcher3.responsive.ResponsiveSpec.DimensionType;
+import com.android.launcher3.responsive.ResponsiveSpecsProvider;
import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.CellContentDimensions;
import com.android.launcher3.util.DisplayController;
@@ -84,7 +82,8 @@
public static final PointF DEFAULT_SCALE = new PointF(1.0f, 1.0f);
public static final ViewScaleProvider DEFAULT_PROVIDER = itemInfo -> DEFAULT_SCALE;
- public static final Consumer<DeviceProfile> DEFAULT_DIMENSION_PROVIDER = dp -> {};
+ public static final Consumer<DeviceProfile> DEFAULT_DIMENSION_PROVIDER = dp -> {
+ };
public final InvariantDeviceProfile inv;
private final Info mInfo;
@@ -119,12 +118,12 @@
// Responsive grid
private final boolean mIsResponsiveGrid;
- private CalculatedWorkspaceSpec mResponsiveWidthSpec;
- private CalculatedWorkspaceSpec mResponsiveHeightSpec;
- private CalculatedAllAppsSpec mAllAppsResponsiveWidthSpec;
- private CalculatedAllAppsSpec mAllAppsResponsiveHeightSpec;
- private CalculatedFolderSpec mResponsiveFolderWidthSpec;
- private CalculatedFolderSpec mResponsiveFolderHeightSpec;
+ private CalculatedResponsiveSpec mResponsiveWorkspaceWidthSpec;
+ private CalculatedResponsiveSpec mResponsiveWorkspaceHeightSpec;
+ private CalculatedResponsiveSpec mResponsiveAllAppsWidthSpec;
+ private CalculatedResponsiveSpec mResponsiveAllAppsHeightSpec;
+ private CalculatedResponsiveSpec mResponsiveFolderWidthSpec;
+ private CalculatedResponsiveSpec mResponsiveFolderHeightSpec;
private CalculatedHotseatSpec mResponsiveHotseatSpec;
/**
@@ -376,7 +375,7 @@
res.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin);
int transientTaskbarHeight =
Math.round((transientTaskbarIconSize * ICON_VISIBLE_AREA_FACTOR)
- + (2 * res.getDimensionPixelSize(R.dimen.transient_taskbar_padding)));
+ + (2 * res.getDimensionPixelSize(R.dimen.transient_taskbar_padding)));
mTransientTaskbarClaimedSpace = transientTaskbarHeight + 2 * transientTaskbarBottomMargin;
if (!isTaskbarPresent) {
@@ -519,12 +518,15 @@
int minQsbMargin = res.getDimensionPixelSize(R.dimen.min_qsb_margin);
if (mIsResponsiveGrid) {
- HotseatSpecs hotseatSpecs =
- HotseatSpecs.create(new ResourceHelper(context,
+ float responsiveAspectRatio = (float) widthPx / heightPx;
+ HotseatSpecsProvider hotseatSpecsProvider =
+ HotseatSpecsProvider.create(new ResourceHelper(context,
isTwoPanels ? inv.hotseatSpecsTwoPanelId : inv.hotseatSpecsId));
mResponsiveHotseatSpec =
- isVerticalBarLayout() ? hotseatSpecs.getCalculatedWidthSpec(widthPx)
- : hotseatSpecs.getCalculatedHeightSpec(heightPx);
+ isVerticalBarLayout() ? hotseatSpecsProvider.getCalculatedSpec(
+ responsiveAspectRatio, DimensionType.WIDTH, widthPx)
+ : hotseatSpecsProvider.getCalculatedSpec(responsiveAspectRatio,
+ DimensionType.HEIGHT, heightPx);
hotseatQsbSpace = mResponsiveHotseatSpec.getHotseatQsbSpace();
hotseatBarBottomSpace =
isVerticalBarLayout() ? 0 : mResponsiveHotseatSpec.getEdgePadding();
@@ -587,35 +589,47 @@
// Needs to be calculated after hotseatBarSizePx is correct,
// for the available height to be correct
if (mIsResponsiveGrid) {
- WorkspaceSpecs workspaceSpecs = WorkspaceSpecs.create(
- new ResourceHelper(context,
- isTwoPanels ? inv.workspaceSpecsTwoPanelId : inv.workspaceSpecsId));
int availableResponsiveWidth =
availableWidthPx - (isVerticalBarLayout() ? hotseatBarSizePx : 0);
- int numColumns = getPanelCount() * inv.numColumns;
+ int numWorkspaceColumns = getPanelCount() * inv.numColumns;
+ int numAllAppsColumns = getPanelCount() * inv.numAllAppsColumns;
// don't use availableHeightPx because it subtracts mInsets.bottom
int availableResponsiveHeight = heightPx - mInsets.top
- - (isVerticalBarLayout() ? 0 : hotseatBarSizePx);
- mResponsiveWidthSpec = workspaceSpecs.getCalculatedWidthSpec(numColumns,
- availableResponsiveWidth);
- mResponsiveHeightSpec = workspaceSpecs.getCalculatedHeightSpec(inv.numRows,
- availableResponsiveHeight);
+ - (isVerticalBarLayout() ? 0 : hotseatBarSizePx);
+ float responsiveAspectRatio = (float) widthPx / heightPx;
- AllAppsSpecs allAppsSpecs = AllAppsSpecs.create(
+ ResponsiveSpecsProvider workspaceSpecs = ResponsiveSpecsProvider.create(
new ResourceHelper(context,
- isTwoPanels ? inv.allAppsSpecsTwoPanelId : inv.allAppsSpecsId));
- mAllAppsResponsiveWidthSpec = allAppsSpecs.getCalculatedWidthSpec(numColumns,
- mResponsiveWidthSpec.getAvailableSpace(), mResponsiveWidthSpec);
- mAllAppsResponsiveHeightSpec = allAppsSpecs.getCalculatedHeightSpec(inv.numRows,
- mResponsiveHeightSpec.getAvailableSpace(), mResponsiveHeightSpec);
+ isTwoPanels ? inv.workspaceSpecsTwoPanelId : inv.workspaceSpecsId),
+ ResponsiveSpecType.Workspace);
+ mResponsiveWorkspaceWidthSpec = workspaceSpecs.getCalculatedSpec(responsiveAspectRatio,
+ DimensionType.WIDTH, numWorkspaceColumns, availableResponsiveWidth);
+ mResponsiveWorkspaceHeightSpec = workspaceSpecs.getCalculatedSpec(responsiveAspectRatio,
+ DimensionType.HEIGHT, inv.numRows, availableResponsiveHeight);
- FolderSpecs folderSpecs = FolderSpecs.create(
+ ResponsiveSpecsProvider allAppsSpecs = ResponsiveSpecsProvider.create(
new ResourceHelper(context,
- isTwoPanels ? inv.folderSpecsTwoPanelId : inv.folderSpecsId));
- mResponsiveFolderWidthSpec = folderSpecs.getCalculatedWidthSpec(inv.numFolderColumns,
- mResponsiveWidthSpec.getAvailableSpace(), mResponsiveWidthSpec);
- mResponsiveFolderHeightSpec = folderSpecs.getCalculatedHeightSpec(inv.numFolderRows,
- mResponsiveHeightSpec.getAvailableSpace(), mResponsiveHeightSpec);
+ isTwoPanels ? inv.allAppsSpecsTwoPanelId : inv.allAppsSpecsId),
+ ResponsiveSpecType.AllApps);
+ mResponsiveAllAppsWidthSpec = allAppsSpecs.getCalculatedSpec(responsiveAspectRatio,
+ DimensionType.WIDTH, numAllAppsColumns, availableWidthPx,
+ mResponsiveWorkspaceWidthSpec);
+ mResponsiveAllAppsHeightSpec = allAppsSpecs.getCalculatedSpec(responsiveAspectRatio,
+ DimensionType.HEIGHT, inv.numRows, heightPx - mInsets.top,
+ mResponsiveWorkspaceHeightSpec);
+
+ ResponsiveSpecsProvider folderSpecs = ResponsiveSpecsProvider.create(
+ new ResourceHelper(context,
+ isTwoPanels ? inv.folderSpecsTwoPanelId : inv.folderSpecsId),
+ ResponsiveSpecType.Folder);
+ mResponsiveFolderWidthSpec = folderSpecs.getCalculatedSpec(responsiveAspectRatio,
+ DimensionType.WIDTH, inv.numFolderColumns,
+ mResponsiveWorkspaceWidthSpec.getAvailableSpace(),
+ mResponsiveWorkspaceWidthSpec);
+ mResponsiveFolderHeightSpec = folderSpecs.getCalculatedSpec(responsiveAspectRatio,
+ DimensionType.HEIGHT, inv.numFolderRows,
+ mResponsiveWorkspaceHeightSpec.getAvailableSpace(),
+ mResponsiveWorkspaceHeightSpec);
}
desiredWorkspaceHorizontalMarginPx = getHorizontalMarginPx(inv, res);
@@ -745,7 +759,7 @@
private int getHorizontalMarginPx(InvariantDeviceProfile idp, Resources res) {
if (mIsResponsiveGrid) {
- return mResponsiveWidthSpec.getStartPaddingPx();
+ return mResponsiveWorkspaceWidthSpec.getStartPaddingPx();
}
if (isVerticalBarLayout()) {
@@ -761,8 +775,8 @@
InvariantDeviceProfile inv,
int extraSpace) {
if (mIsResponsiveGrid) {
- workspaceTopPadding = mResponsiveHeightSpec.getStartPaddingPx();
- workspaceBottomPadding = mResponsiveHeightSpec.getEndPaddingPx();
+ workspaceTopPadding = mResponsiveWorkspaceHeightSpec.getStartPaddingPx();
+ workspaceBottomPadding = mResponsiveWorkspaceHeightSpec.getEndPaddingPx();
} else if (mIsScalableGrid && inv.devicePaddingId != INVALID_RESOURCE_HANDLE) {
// Paddings were created assuming no scaling, so we first unscale the extra space.
int unscaledExtraSpace = (int) (extraSpace / cellScaleToFit);
@@ -858,8 +872,8 @@
int verticalSpacePx = 0;
if (mIsResponsiveGrid) {
- horizontalSpacePx = mResponsiveWidthSpec.getGutterPx();
- verticalSpacePx = mResponsiveHeightSpec.getGutterPx();
+ horizontalSpacePx = mResponsiveWorkspaceWidthSpec.getGutterPx();
+ verticalSpacePx = mResponsiveWorkspaceHeightSpec.getGutterPx();
} else if (mIsScalableGrid) {
horizontalSpacePx = pxFromDp(idp.borderSpaces[mTypeIndex].x, mMetrics, scale);
verticalSpacePx = pxFromDp(idp.borderSpaces[mTypeIndex].y, mMetrics, scale);
@@ -1004,12 +1018,16 @@
+ cellLayoutPaddingPx.left + cellLayoutPaddingPx.right;
}
- private int getNormalizedIconDrawablePadding() {
+ private int getNormalizedIconDrawablePadding(int iconSizePx, int iconDrawablePadding) {
// TODO(b/235886078): workaround needed because of this bug
// Icons are 10% larger on XML than their visual size,
// so remove that extra space to get labels closer to the correct padding
int iconVisibleSizePx = (int) Math.round(ICON_VISIBLE_AREA_FACTOR * iconSizePx);
- return Math.max(0, mIconDrawablePaddingOriginalPx - ((iconSizePx - iconVisibleSizePx) / 2));
+ return Math.max(0, iconDrawablePadding - ((iconSizePx - iconVisibleSizePx) / 2));
+ }
+
+ private int getNormalizedIconDrawablePadding() {
+ return getNormalizedIconDrawablePadding(iconSizePx, mIconDrawablePaddingOriginalPx);
}
private int getNormalizedFolderChildDrawablePaddingPx(int textHeight) {
@@ -1042,8 +1060,8 @@
cellLayoutBorderSpacePx = getCellLayoutBorderSpace(inv, scale);
if (mIsResponsiveGrid) {
- cellWidthPx = mResponsiveWidthSpec.getCellSizePx();
- cellHeightPx = mResponsiveHeightSpec.getCellSizePx();
+ cellWidthPx = mResponsiveWorkspaceWidthSpec.getCellSizePx();
+ cellHeightPx = mResponsiveWorkspaceHeightSpec.getCellSizePx();
if (cellWidthPx < iconSizePx) {
// get a smaller icon size
@@ -1147,7 +1165,7 @@
// All apps
if (mIsResponsiveGrid) {
- updateAllAppsWithResponsiveMeasures();
+ updateAllAppsWithResponsiveMeasures(res);
} else {
updateAllAppsIconSize(scale, res);
}
@@ -1246,20 +1264,61 @@
}
}
- private void updateAllAppsWithResponsiveMeasures() {
- allAppsIconSizePx = iconSizePx;
- allAppsIconTextSizePx = iconTextSizePx;
- allAppsIconDrawablePaddingPx = iconDrawablePaddingPx;
-
+ private void updateAllAppsWithResponsiveMeasures(Resources res) {
allAppsBorderSpacePx = new Point(
- mAllAppsResponsiveWidthSpec.getGutterPx(),
- mAllAppsResponsiveHeightSpec.getGutterPx()
+ mResponsiveAllAppsWidthSpec.getGutterPx(),
+ mResponsiveAllAppsHeightSpec.getGutterPx()
);
- allAppsCellHeightPx = mAllAppsResponsiveHeightSpec.getCellSizePx()
- + mAllAppsResponsiveHeightSpec.getGutterPx();
- allAppsCellWidthPx = mAllAppsResponsiveWidthSpec.getCellSizePx();
- allAppsPadding.left = mAllAppsResponsiveWidthSpec.getStartPaddingPx();
- allAppsPadding.right = mAllAppsResponsiveWidthSpec.getEndPaddingPx();
+ allAppsCellHeightPx = mResponsiveAllAppsHeightSpec.getCellSizePx()
+ + mResponsiveAllAppsHeightSpec.getGutterPx();
+ allAppsCellWidthPx = mResponsiveAllAppsWidthSpec.getCellSizePx();
+
+ // This workaround is needed to align AllApps icons with Workspace icons
+ // since AllApps doesn't have borders between cells
+ int halfBorder = allAppsBorderSpacePx.x / 2;
+ allAppsPadding.left = mResponsiveAllAppsWidthSpec.getStartPaddingPx() - halfBorder;
+ allAppsPadding.right = mResponsiveAllAppsWidthSpec.getEndPaddingPx() - halfBorder;
+
+ // TODO(b/287975993): Remove this after icon size is extracted to responsive grid
+ // Copy icon size from the workspace when spec is matchWorkspace or
+ // use the default all apps icon size
+ if (mResponsiveAllAppsHeightSpec.isCellSizeMatchWorkspace()
+ || mResponsiveAllAppsWidthSpec.isCellSizeMatchWorkspace()) {
+ allAppsIconSizePx = iconSizePx;
+ allAppsIconTextSizePx = iconTextSizePx;
+ allAppsIconDrawablePaddingPx = iconDrawablePaddingPx;
+ } else {
+ allAppsIconSizePx = pxFromDp(inv.allAppsIconSize[mTypeIndex], mMetrics);
+ allAppsIconTextSizePx = pxFromSp(inv.allAppsIconTextSize[mTypeIndex], mMetrics);
+ allAppsIconDrawablePaddingPx = res.getDimensionPixelSize(
+ R.dimen.all_apps_icon_drawable_padding);
+ allAppsIconDrawablePaddingPx = getNormalizedIconDrawablePadding(allAppsIconSizePx,
+ allAppsIconDrawablePaddingPx);
+ }
+
+ // Reduce the size of the app icon if it doesn't fit
+ if (allAppsCellWidthPx < allAppsIconSizePx) {
+ // get a smaller icon size
+ allAppsIconSizePx = mIconSizeSteps.getIconSmallerThan(allAppsCellWidthPx);
+ }
+
+ CellContentDimensions cellContentDimensions = new CellContentDimensions(
+ allAppsIconSizePx, allAppsIconDrawablePaddingPx, (int) allAppsIconTextSizePx);
+
+ if (allAppsCellHeightPx < cellContentDimensions.getCellContentHeight()) {
+ if (isVerticalBarLayout()) {
+ if (allAppsCellHeightPx < iconSizePx) {
+ cellContentDimensions.setIconSizePx(
+ mIconSizeSteps.getIconSmallerThan(allAppsCellHeightPx));
+ }
+ } else {
+ cellContentDimensions.resizeToFitCellHeight(allAppsCellHeightPx,
+ mIconSizeSteps);
+ }
+ allAppsIconSizePx = cellContentDimensions.getIconSizePx();
+ allAppsIconDrawablePaddingPx = cellContentDimensions.getIconDrawablePaddingPx();
+ allAppsIconTextSizePx = cellContentDimensions.getIconTextSizePx();
+ }
}
/**
@@ -1280,7 +1339,7 @@
+ (allAppsBorderSpacePx.x * (numShownAllAppsColumns - 1))
+ allAppsPadding.left + allAppsPadding.right;
allAppsLeftRightMargin = Math.max(1, (availableWidthPx - usedWidth) / 2);
- } else {
+ } else if (!mIsResponsiveGrid) {
allAppsPadding.left = allAppsPadding.right =
Math.max(0, desiredWorkspaceHorizontalMarginPx + cellLayoutHorizontalPadding
- (allAppsBorderSpacePx.x / 2));
@@ -1338,8 +1397,6 @@
if (mIsResponsiveGrid) {
folderCellWidthPx = mResponsiveFolderWidthSpec.getCellSizePx();
-
- // Height
folderCellHeightPx = mResponsiveFolderHeightSpec.getCellSizePx();
folderContentPaddingTop = mResponsiveFolderHeightSpec.getStartPaddingPx();
folderFooterHeightPx = mResponsiveFolderHeightSpec.getEndPaddingPx();
@@ -1356,24 +1413,15 @@
// Recalculating padding and cell height
folderChildDrawablePaddingPx = getNormalizedFolderChildDrawablePaddingPx(textHeight);
- int folderCellContentHeight = folderChildIconSizePx + folderChildDrawablePaddingPx
- + textHeight;
- // Reduce the icon in height when it's taller than the expected cell height
- while (folderChildIconSizePx > mIconSizeSteps.minimumIconSize()
- && folderCellContentHeight > folderCellHeightPx) {
- folderChildDrawablePaddingPx -= folderCellContentHeight - folderCellHeightPx;
- if (folderChildDrawablePaddingPx < 0) {
- // get a smaller icon size
- folderChildIconSizePx = mIconSizeSteps.getNextLowerIconSize(
- folderChildIconSizePx);
- folderChildDrawablePaddingPx =
- getNormalizedFolderChildDrawablePaddingPx(textHeight);
- }
- // calculate new cellContentHeight
- folderCellContentHeight = folderChildIconSizePx + folderChildDrawablePaddingPx
- + textHeight;
- }
+ CellContentDimensions cellContentDimensions = new CellContentDimensions(
+ folderChildIconSizePx,
+ folderChildDrawablePaddingPx,
+ folderChildTextSizePx);
+ cellContentDimensions.resizeToFitCellHeight(folderCellHeightPx, mIconSizeSteps);
+ folderChildIconSizePx = cellContentDimensions.getIconSizePx();
+ folderChildDrawablePaddingPx = cellContentDimensions.getIconDrawablePaddingPx();
+ folderChildTextSizePx = cellContentDimensions.getIconTextSizePx();
} else if (mIsScalableGrid) {
if (inv.folderStyle == INVALID_RESOURCE_HANDLE) {
folderCellWidthPx = roundPxValueFromFloat(getCellSize().x * scale);
@@ -1540,15 +1588,17 @@
Rect padding = workspacePadding;
if (isVerticalBarLayout()) {
if (mIsResponsiveGrid) {
- padding.top = mResponsiveHeightSpec.getStartPaddingPx();
+ padding.top = mResponsiveWorkspaceHeightSpec.getStartPaddingPx();
padding.bottom = Math.max(0,
- mResponsiveHeightSpec.getEndPaddingPx() - mInsets.bottom);
+ mResponsiveWorkspaceHeightSpec.getEndPaddingPx() - mInsets.bottom);
if (isSeascape()) {
- padding.left = hotseatBarSizePx + mResponsiveWidthSpec.getEndPaddingPx();
- padding.right = mResponsiveWidthSpec.getStartPaddingPx();
+ padding.left =
+ hotseatBarSizePx + mResponsiveWorkspaceWidthSpec.getEndPaddingPx();
+ padding.right = mResponsiveWorkspaceWidthSpec.getStartPaddingPx();
} else {
- padding.left = mResponsiveWidthSpec.getStartPaddingPx();
- padding.right = hotseatBarSizePx + mResponsiveWidthSpec.getEndPaddingPx();
+ padding.left = mResponsiveWorkspaceWidthSpec.getStartPaddingPx();
+ padding.right =
+ hotseatBarSizePx + mResponsiveWorkspaceWidthSpec.getEndPaddingPx();
}
} else {
padding.top = 0;
@@ -2070,12 +2120,14 @@
writer.println(prefix + pxToDpStr("getCellLayoutHeight()", getCellLayoutHeight()));
writer.println(prefix + pxToDpStr("getCellLayoutWidth()", getCellLayoutWidth()));
if (mIsResponsiveGrid) {
- writer.println(prefix + "\tmResponsiveHeightSpec:" + mResponsiveHeightSpec.toString());
- writer.println(prefix + "\tmResponsiveWidthSpec:" + mResponsiveWidthSpec.toString());
- writer.println(prefix + "\tmAllAppsResponsiveHeightSpec:"
- + mAllAppsResponsiveHeightSpec.toString());
- writer.println(prefix + "\tmAllAppsResponsiveWidthSpec:"
- + mAllAppsResponsiveWidthSpec.toString());
+ writer.println(prefix + "\tmResponsiveWorkspaceHeightSpec:"
+ + mResponsiveWorkspaceHeightSpec.toString());
+ writer.println(prefix + "\tmResponsiveWorkspaceWidthSpec:"
+ + mResponsiveWorkspaceWidthSpec.toString());
+ writer.println(prefix + "\tmResponsiveAllAppsHeightSpec:"
+ + mResponsiveAllAppsHeightSpec.toString());
+ writer.println(prefix + "\tmResponsiveAllAppsWidthSpec:"
+ + mResponsiveAllAppsWidthSpec.toString());
writer.println(prefix + "\tmResponsiveFolderHeightSpec:" + mResponsiveFolderHeightSpec);
writer.println(prefix + "\tmResponsiveFolderWidthSpec:" + mResponsiveFolderWidthSpec);
writer.println(prefix + "\tmResponsiveHotseatSpec:" + mResponsiveHotseatSpec);
diff --git a/src/com/android/launcher3/DropTargetHandler.kt b/src/com/android/launcher3/DropTargetHandler.kt
index 78f2862..e022159 100644
--- a/src/com/android/launcher3/DropTargetHandler.kt
+++ b/src/com/android/launcher3/DropTargetHandler.kt
@@ -4,6 +4,7 @@
import android.view.View
import com.android.launcher3.BaseDraggingActivity.EVENT_RESUMED
import com.android.launcher3.DropTarget.DragObject
+import com.android.launcher3.LauncherConstants.ActivityCodes
import com.android.launcher3.SecondaryDropTarget.DeferredOnComplete
import com.android.launcher3.dragndrop.DragLayer
import com.android.launcher3.logging.StatsLogManager.LauncherEvent
@@ -46,7 +47,7 @@
mLauncher.appWidgetHolder.startConfigActivity(
mLauncher,
widgetId,
- Launcher.REQUEST_RECONFIGURE_APPWIDGET
+ ActivityCodes.REQUEST_RECONFIGURE_APPWIDGET
)
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index ec2816b..5a0cf9d 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -33,6 +33,28 @@
import static com.android.launcher3.LauncherAnimUtils.SCALE_INDEX_WIDGET_TRANSITION;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherAnimUtils.WORKSPACE_SCALE_PROPERTY_FACTORY;
+import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_BIND_APPWIDGET;
+import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_BIND_PENDING_APPWIDGET;
+import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_CREATE_APPWIDGET;
+import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_CREATE_SHORTCUT;
+import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_PICK_APPWIDGET;
+import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_RECONFIGURE_APPWIDGET;
+import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE;
+import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE_CURRENT_SCREEN_IDS;
+import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE_PENDING_ACTIVITY_RESULT;
+import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE_PENDING_REQUEST_ARGS;
+import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE_PENDING_REQUEST_CODE;
+import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE_WIDGET_PANEL;
+import static com.android.launcher3.LauncherConstants.TraceEvents.COLD_STARTUP_TRACE_COOKIE;
+import static com.android.launcher3.LauncherConstants.TraceEvents.COLD_STARTUP_TRACE_METHOD_NAME;
+import static com.android.launcher3.LauncherConstants.TraceEvents.DISPLAY_ALL_APPS_TRACE_COOKIE;
+import static com.android.launcher3.LauncherConstants.TraceEvents.DISPLAY_ALL_APPS_TRACE_METHOD_NAME;
+import static com.android.launcher3.LauncherConstants.TraceEvents.DISPLAY_WORKSPACE_TRACE_METHOD_NAME;
+import static com.android.launcher3.LauncherConstants.TraceEvents.DISPLAY_WORKSPACE_TRACE_COOKIE;
+import static com.android.launcher3.LauncherConstants.TraceEvents.ON_CREATE_EVT;
+import static com.android.launcher3.LauncherConstants.TraceEvents.ON_NEW_INTENT_EVT;
+import static com.android.launcher3.LauncherConstants.TraceEvents.ON_RESUME_EVT;
+import static com.android.launcher3.LauncherConstants.TraceEvents.ON_START_EVT;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherState.ALL_APPS;
@@ -267,15 +289,6 @@
static final boolean DEBUG_STRICT_MODE = false;
- private static final int REQUEST_CREATE_SHORTCUT = 1;
- private static final int REQUEST_CREATE_APPWIDGET = 5;
-
- private static final int REQUEST_PICK_APPWIDGET = 9;
-
- private static final int REQUEST_BIND_APPWIDGET = 11;
- public static final int REQUEST_BIND_PENDING_APPWIDGET = 12;
- public static final int REQUEST_RECONFIGURE_APPWIDGET = 13;
-
private static final float BOUNCE_ANIMATION_TENSION = 1.3f;
/**
@@ -284,30 +297,9 @@
*/
protected static final int REQUEST_LAST = 100;
- // Type: int
- protected static final String RUNTIME_STATE = "launcher.state";
- // Type: PendingRequestArgs
- private static final String RUNTIME_STATE_PENDING_REQUEST_ARGS = "launcher.request_args";
- // Type: int
- private static final String RUNTIME_STATE_PENDING_REQUEST_CODE = "launcher.request_code";
- // Type: ActivityResultInfo
- private static final String RUNTIME_STATE_PENDING_ACTIVITY_RESULT = "launcher.activity_result";
- // Type: SparseArray<Parcelable>
- private static final String RUNTIME_STATE_WIDGET_PANEL = "launcher.widget_panel";
- // Type int[]
- private static final String RUNTIME_STATE_CURRENT_SCREEN_IDS = "launcher.current_screen_ids";
-
- // Type PendingSplitSelectInfo<Parcelable>
- protected static final String PENDING_SPLIT_SELECT_INFO = "launcher.pending_split_select_info";
-
public static final String INTENT_ACTION_ALL_APPS_TOGGLE =
"launcher.intent_action_all_apps_toggle";
- public static final String ON_CREATE_EVT = "Launcher.onCreate";
- public static final String ON_START_EVT = "Launcher.onStart";
- public static final String ON_RESUME_EVT = "Launcher.onResume";
- public static final String ON_NEW_INTENT_EVT = "Launcher.onNewIntent";
-
private static boolean sIsNewProcess = true;
private StateManager<LauncherState> mStateManager;
@@ -319,13 +311,6 @@
private static final int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5;
@Thunk @VisibleForTesting public static final int NEW_APPS_ANIMATION_DELAY = 500;
- private static final String DISPLAY_WORKSPACE_TRACE_METHOD_NAME = "DisplayWorkspaceFirstFrame";
- public static final String DISPLAY_ALL_APPS_TRACE_METHOD_NAME = "DisplayAllApps";
- public static final int DISPLAY_WORKSPACE_TRACE_COOKIE = 0;
- public static final int DISPLAY_ALL_APPS_TRACE_COOKIE = 1;
- private static final String COLD_STARTUP_TRACE_METHOD_NAME = "LauncherColdStartup";
- public static final int COLD_STARTUP_TRACE_COOKIE = 2;
-
private static final FloatProperty<Workspace<?>> WORKSPACE_WIDGET_SCALE =
WORKSPACE_SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_WIDGET_TRANSITION);
private static final FloatProperty<Hotseat> HOTSEAT_WIDGET_SCALE =
@@ -1605,6 +1590,9 @@
if (getStateManager().isInStableState(ALL_APPS)) {
getStateManager().goToState(NORMAL, alreadyOnHome);
} else {
+ if (mWorkspace.isOverlayShown()) {
+ mOverlayManager.hideOverlay(/* animate */true);
+ }
AbstractFloatingView.closeAllOpenViews(this);
getStateManager().goToState(ALL_APPS, true /* animated */,
new AnimationSuccessListener() {
@@ -2803,10 +2791,8 @@
Map<PackageUserKey, Integer> packageUserKeytoUidMap) {
mModelCallbacks.bindAllApplications(apps, flags, packageUserKeytoUidMap);
if (Utilities.ATLEAST_S) {
- Trace.endAsyncSection(
- Launcher.DISPLAY_ALL_APPS_TRACE_METHOD_NAME,
- Launcher.DISPLAY_ALL_APPS_TRACE_COOKIE
- );
+ Trace.endAsyncSection(DISPLAY_ALL_APPS_TRACE_METHOD_NAME,
+ DISPLAY_ALL_APPS_TRACE_COOKIE);
}
}
diff --git a/src/com/android/launcher3/LauncherConstants.java b/src/com/android/launcher3/LauncherConstants.java
new file mode 100644
index 0000000..1abfeb9
--- /dev/null
+++ b/src/com/android/launcher3/LauncherConstants.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3;
+
+public class LauncherConstants {
+
+ /**
+ * Trace events to visualize using Systrace tool.
+ */
+ public static class TraceEvents {
+
+ public static final String DISPLAY_ALL_APPS_TRACE_METHOD_NAME = "DisplayAllApps";
+ public static final int DISPLAY_WORKSPACE_TRACE_COOKIE = 0;
+ public static final int DISPLAY_ALL_APPS_TRACE_COOKIE = 1;
+ public static final int COLD_STARTUP_TRACE_COOKIE = 2;
+ public static final String ON_CREATE_EVT = "Launcher.onCreate";
+ public static final String ON_START_EVT = "Launcher.onStart";
+ public static final String ON_RESUME_EVT = "Launcher.onResume";
+ public static final String ON_NEW_INTENT_EVT = "Launcher.onNewIntent";
+ static final String DISPLAY_WORKSPACE_TRACE_METHOD_NAME = "DisplayWorkspaceFirstFrame";
+ static final String COLD_STARTUP_TRACE_METHOD_NAME = "LauncherColdStartup";
+ }
+
+ /**
+ * This are the different codes the Launcher can receive when a new Launcher Intent is created.
+ */
+ public static class ActivityCodes {
+
+ public static final int REQUEST_BIND_PENDING_APPWIDGET = 12;
+ public static final int REQUEST_RECONFIGURE_APPWIDGET = 13;
+ static final int REQUEST_CREATE_SHORTCUT = 1;
+ static final int REQUEST_CREATE_APPWIDGET = 5;
+ static final int REQUEST_PICK_APPWIDGET = 9;
+ static final int REQUEST_BIND_APPWIDGET = 11;
+ }
+
+ /**
+ * Keys used to get the saved values of the previous Activity instance.
+ */
+ public static class SavedInstanceKeys {
+
+ // Type: int
+ public static final String RUNTIME_STATE = "launcher.state";
+ // Type PendingSplitSelectInfo<Parcelable>
+ public static final String PENDING_SPLIT_SELECT_INFO = "launcher.pending_split_select_info";
+ // Type: PendingRequestArgs
+ static final String RUNTIME_STATE_PENDING_REQUEST_ARGS = "launcher.request_args";
+ // Type: int
+ static final String RUNTIME_STATE_PENDING_REQUEST_CODE = "launcher.request_code";
+ // Type: ActivityResultInfo
+ static final String RUNTIME_STATE_PENDING_ACTIVITY_RESULT = "launcher.activity_result";
+ // Type: SparseArray<Parcelable>
+ static final String RUNTIME_STATE_WIDGET_PANEL = "launcher.widget_panel";
+ // Type int[]
+ static final String RUNTIME_STATE_CURRENT_SCREEN_IDS = "launcher.current_screen_ids";
+ }
+}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index fd8f668..551735e 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -20,6 +20,8 @@
import static com.android.launcher3.LauncherAppState.ACTION_FORCE_ROLOAD;
import static com.android.launcher3.config.FeatureFlags.IS_STUDIO_BUILD;
+import static com.android.launcher3.pm.UserCache.ACTION_PROFILE_AVAILABLE;
+import static com.android.launcher3.pm.UserCache.ACTION_PROFILE_UNAVAILABLE;
import static com.android.launcher3.testing.shared.TestProtocol.sDebugTracing;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -326,6 +328,16 @@
} else if (UserCache.ACTION_PROFILE_ADDED.equals(action)
|| UserCache.ACTION_PROFILE_REMOVED.equals(action)) {
forceReload();
+ } else if (ACTION_PROFILE_AVAILABLE.equals(action)
+ || ACTION_PROFILE_UNAVAILABLE.equals(action)) {
+ /*
+ * This broadcast is only available when android.os.Flags.allowPrivateProfile() is set.
+ * For Work-profile this broadcast will be sent in addition to
+ * ACTION_MANAGED_PROFILE_AVAILABLE/UNAVAILABLE.
+ * So effectively, this if block only handles the non-work profile case.
+ */
+ enqueueModelUpdateTask(new PackageUpdatedTask(
+ PackageUpdatedTask.OP_USER_AVAILABILITY_CHANGE, user));
}
}
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 72c6cb8..095cfa9 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -80,6 +80,7 @@
import com.android.launcher3.keyboard.FocusedItemDecorator;
import com.android.launcher3.model.StringCache;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.pm.UserCache;
import com.android.launcher3.recyclerview.AllAppsRecyclerViewPool;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.Themes;
@@ -203,7 +204,9 @@
mWorkManager = new WorkProfileManager(
mActivityContext.getSystemService(UserManager.class),
- this, mActivityContext.getStatsLogManager());
+ this,
+ mActivityContext.getStatsLogManager(),
+ UserCache.INSTANCE.get(mActivityContext));
mAH = Arrays.asList(null, null, null);
mNavBarScrimPaint = new Paint();
mNavBarScrimPaint.setColor(Themes.getNavBarScrimColor(mActivityContext));
@@ -1043,6 +1046,11 @@
return getActiveAppsRecyclerView();
}
+ /** The current focus change listener in the search container. */
+ public OnFocusChangeListener getSearchFocusChangeListener() {
+ return mAH.get(AdapterHolder.SEARCH).mOnFocusChangeListener;
+ }
+
/** The current apps recycler view in the container. */
private AllAppsRecyclerView getActiveAppsRecyclerView() {
if (!mUsingTabs || isPersonalTab()) {
@@ -1098,7 +1106,7 @@
mlp.rightMargin = insets.right;
setLayoutParams(mlp);
- if (grid.isVerticalBarLayout()) {
+ if (grid.isVerticalBarLayout() && !FeatureFlags.enableResponsiveWorkspace()) {
setPadding(grid.workspacePadding.left, 0, grid.workspacePadding.right, 0);
} else {
int topPadding = grid.allAppsPadding.top;
@@ -1108,7 +1116,6 @@
}
setPadding(grid.allAppsLeftRightMargin, topPadding, grid.allAppsLeftRightMargin, 0);
}
-
InsettableFrameLayout.dispatchInsets(this, insets);
}
@@ -1440,6 +1447,7 @@
final AlphabeticalAppsList<T> mAppsList;
final Rect mPadding = new Rect();
AllAppsRecyclerView mRecyclerView;
+ private OnFocusChangeListener mOnFocusChangeListener;
AdapterHolder(int type, AlphabeticalAppsList<T> appsList) {
mType = type;
@@ -1463,7 +1471,8 @@
onInitializeRecyclerView(mRecyclerView);
FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(mRecyclerView);
mRecyclerView.addItemDecoration(focusedItemDecorator);
- mAdapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
+ mOnFocusChangeListener = focusedItemDecorator.getFocusListener();
+ mAdapter.setIconFocusListener(mOnFocusChangeListener);
applyPadding();
}
diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java
index 9f6e0fc..051cf50 100644
--- a/src/com/android/launcher3/allapps/AllAppsStore.java
+++ b/src/com/android/launcher3/allapps/AllAppsStore.java
@@ -124,6 +124,9 @@
* @see com.android.launcher3.model.BgDataModel.Callbacks#FLAG_QUIET_MODE_ENABLED
* @see com.android.launcher3.model.BgDataModel.Callbacks#FLAG_HAS_SHORTCUT_PERMISSION
* @see com.android.launcher3.model.BgDataModel.Callbacks#FLAG_QUIET_MODE_CHANGE_PERMISSION
+ * @see com.android.launcher3.model.BgDataModel.Callbacks#FLAG_WORK_PROFILE_QUIET_MODE_ENABLED
+ * @see
+ * com.android.launcher3.model.BgDataModel.Callbacks#FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED
*/
public boolean hasModelFlag(int mask) {
return (mModelFlags & mask) != 0;
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
index ac0e5a4..61c3d3f 100644
--- a/src/com/android/launcher3/allapps/WorkProfileManager.java
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -25,10 +25,10 @@
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED;
+import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_WORK_PROFILE_QUIET_MODE_ENABLED;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.os.Build;
-import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
@@ -40,12 +40,14 @@
import androidx.annotation.RequiresApi;
import androidx.recyclerview.widget.RecyclerView;
+import com.android.launcher3.Flags;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.pm.UserCache;
import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip;
import java.lang.annotation.Retention;
@@ -84,16 +86,19 @@
private WorkModeSwitch mWorkModeSwitch;
+ private final UserCache mUserCache;
+
@WorkProfileState
private int mCurrentState;
public WorkProfileManager(
UserManager userManager, ActivityAllAppsContainerView allApps,
- StatsLogManager statsLogManager) {
+ StatsLogManager statsLogManager, UserCache userCache) {
mUserManager = userManager;
mAllApps = allApps;
- mMatcher = mAllApps.mPersonalMatcher.negate();
mStatsLogManager = statsLogManager;
+ mUserCache = userCache;
+ mMatcher = info -> info != null && mUserCache.getUserInfo(info.user).isWork();
}
/**
@@ -103,11 +108,11 @@
public void setWorkProfileEnabled(boolean enabled) {
updateCurrentState(STATE_TRANSITION);
UI_HELPER_EXECUTOR.post(() -> {
- for (UserHandle userProfile : mUserManager.getUserProfiles()) {
- if (Process.myUserHandle().equals(userProfile)) {
- continue;
+ for (UserHandle userProfile : mUserCache.getUserProfiles()) {
+ if (mUserCache.getUserInfo(userProfile).isWork()) {
+ mUserManager.requestQuietModeEnabled(!enabled, userProfile);
+ break;
}
- mUserManager.requestQuietModeEnabled(!enabled, userProfile);
}
});
}
@@ -131,7 +136,13 @@
* Requests work profile state from {@link AllAppsStore} and updates work profile related views
*/
public void reset() {
- boolean isEnabled = !mAllApps.getAppsStore().hasModelFlag(FLAG_QUIET_MODE_ENABLED);
+ int quietModeFlag;
+ if (Flags.enablePrivateSpace()) {
+ quietModeFlag = FLAG_WORK_PROFILE_QUIET_MODE_ENABLED;
+ } else {
+ quietModeFlag = FLAG_QUIET_MODE_ENABLED;
+ }
+ boolean isEnabled = !mAllApps.getAppsStore().hasModelFlag(quietModeFlag);
updateCurrentState(isEnabled ? STATE_ENABLED : STATE_DISABLED);
if (mWorkModeSwitch != null) {
// reset the position of the button and clear IME insets.
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 73861c1..51eb363 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -23,6 +23,7 @@
import static com.android.launcher3.uioverrides.flags.FlagsFactory.getDebugFlag;
import static com.android.launcher3.uioverrides.flags.FlagsFactory.getIntFlag;
import static com.android.launcher3.uioverrides.flags.FlagsFactory.getReleaseFlag;
+import static com.android.wm.shell.Flags.enableTaskbarNavbarUnification;
import android.view.ViewConfiguration;
@@ -217,12 +218,19 @@
public static final BooleanFlag ENABLE_TRANSIENT_TASKBAR = getDebugFlag(270395798,
"ENABLE_TRANSIENT_TASKBAR", ENABLED, "Enables transient taskbar.");
+ public static final boolean ENABLE_TASKBAR_NAVBAR_UNIFICATION =
+ enableTaskbarNavbarUnification();
+
// Aconfig migration complete for ENABLE_TASKBAR_NO_RECREATION.
public static final BooleanFlag ENABLE_TASKBAR_NO_RECREATION = getDebugFlag(299193589,
"ENABLE_TASKBAR_NO_RECREATION", DISABLED,
"Enables taskbar with no recreation from lifecycle changes of TaskbarActivityContext.");
public static boolean enableTaskbarNoRecreate() {
- return ENABLE_TASKBAR_NO_RECREATION.get() || Flags.enableTaskbarNoRecreate();
+ return ENABLE_TASKBAR_NO_RECREATION.get() || Flags.enableTaskbarNoRecreate()
+ // Task bar pinning and task bar nav bar unification are both dependent on
+ // ENABLE_TASKBAR_NO_RECREATION. We want to turn ENABLE_TASKBAR_NO_RECREATION on
+ // when either of the dependent features is turned on.
+ || ENABLE_TASKBAR_PINNING.get() || ENABLE_TASKBAR_NAVBAR_UNIFICATION;
}
// TODO(Block 16): Clean up flags
@@ -279,11 +287,16 @@
"Enables haptic hint when long pressing on the bottom bar nav handle.");
// TODO(Block 17): Clean up flags
- public static final BooleanFlag ENABLE_TASKBAR_PINNING = getDebugFlag(270396583,
+ // Aconfig migration complete for ENABLE_TASKBAR_PINNING.
+ private static final BooleanFlag ENABLE_TASKBAR_PINNING = getDebugFlag(270396583,
"ENABLE_TASKBAR_PINNING", TEAMFOOD,
"Enables taskbar pinning to allow user to switch between transient and persistent "
+ "taskbar flavors");
+ public static boolean enableTaskbarPinning() {
+ return ENABLE_TASKBAR_PINNING.get() || Flags.enableTaskbarPinning();
+ }
+
public static final BooleanFlag MOVE_STARTUP_DATA_TO_DEVICE_PROTECTED_STORAGE = getDebugFlag(
251502424, "ENABLE_BOOT_AWARE_STARTUP_DATA", DISABLED,
"Marks LauncherPref data as (and allows it to) available while the device is"
@@ -395,11 +408,16 @@
"USE_LOCAL_ICON_OVERRIDES", ENABLED,
"Use inbuilt monochrome icons if app doesn't provide one");
- // TODO(Block 28): Clean up flags
+ // Aconfig migration complete for ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS.
public static final BooleanFlag ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS =
getDebugFlag(270394122, "ENABLE_SPLIT_FROM_FULLSCREEN_SHORTCUT", DISABLED,
"Enable splitting from fullscreen app with keyboard shortcuts");
+ public static boolean enableSplitFromFullscreenWithKeyboardShortcuts() {
+ return ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS.get()
+ || Flags.enableSplitFromFullscreenWithKeyboardShortcuts();
+ }
+ // Aconfig migration complete for ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.
public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE = getDebugFlag(
270393453, "ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE", DISABLED,
"Enable initiating split screen from workspace to workspace.");
diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java
index 2e5f2e5..b39e968e 100644
--- a/src/com/android/launcher3/folder/PreviewItemManager.java
+++ b/src/com/android/launcher3/folder/PreviewItemManager.java
@@ -43,6 +43,7 @@
import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
import java.util.ArrayList;
@@ -434,7 +435,8 @@
drawable.setLevel(item.getProgressLevel());
p.drawable = drawable;
} else {
- p.drawable = item.newIcon(mContext, FLAG_THEMED);
+ p.drawable = item.newIcon(mContext,
+ Themes.isThemedIconEnabled(mContext) ? FLAG_THEMED : 0);
}
p.drawable.setBounds(0, 0, mIconSize, mIconSize);
p.item = item;
diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java
index 8f85bfb..190eb78 100644
--- a/src/com/android/launcher3/model/AllAppsList.java
+++ b/src/com/android/launcher3/model/AllAppsList.java
@@ -79,6 +79,8 @@
* @see Callbacks#FLAG_HAS_SHORTCUT_PERMISSION
* @see Callbacks#FLAG_QUIET_MODE_ENABLED
* @see Callbacks#FLAG_QUIET_MODE_CHANGE_PERMISSION
+ * @see Callbacks#FLAG_WORK_PROFILE_QUIET_MODE_ENABLED
+ * @see Callbacks#FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED
*/
private int mFlags;
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index 54ecc00..7f0f683 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -477,6 +477,10 @@
int FLAG_QUIET_MODE_ENABLED = 1 << 1;
// If launcher can change quiet mode
int FLAG_QUIET_MODE_CHANGE_PERMISSION = 1 << 2;
+ // If quiet mode is enabled for work profile user
+ int FLAG_WORK_PROFILE_QUIET_MODE_ENABLED = 1 << 3;
+ // If quiet mode is enabled for private profile user
+ int FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED = 1 << 4;
/**
* Returns an IntSet of page ids to bind first, synchronously if possible
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 1ab0355..f4ce360 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -23,8 +23,10 @@
import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
import static com.android.launcher3.config.FeatureFlags.SMARTSPACE_AS_A_WIDGET;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
+import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED;
+import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_WORK_PROFILE_QUIET_MODE_ENABLED;
import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE;
@@ -57,8 +59,10 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
@@ -143,7 +147,7 @@
private final InstallSessionHelper mSessionHelper;
private final IconCache mIconCache;
- private final UserManagerState mUserManagerState = new UserManagerState();
+ private final UserManagerState mUserManagerState;
protected final Map<ComponentKey, AppWidgetProviderInfo> mWidgetProvidersMap = new ArrayMap<>();
private Map<ShortcutKey, ShortcutInfo> mShortcutKeyToPinnedShortcuts;
@@ -156,6 +160,13 @@
public LoaderTask(@NonNull LauncherAppState app, AllAppsList bgAllAppsList, BgDataModel bgModel,
ModelDelegate modelDelegate, @NonNull LauncherBinder launcherBinder) {
+ this(app, bgAllAppsList, bgModel, modelDelegate, launcherBinder, new UserManagerState());
+ }
+
+ @VisibleForTesting
+ LoaderTask(@NonNull LauncherAppState app, AllAppsList bgAllAppsList, BgDataModel bgModel,
+ ModelDelegate modelDelegate, @NonNull LauncherBinder launcherBinder,
+ UserManagerState userManagerState) {
mApp = app;
mBgAllAppsList = bgAllAppsList;
mBgDataModel = bgModel;
@@ -164,9 +175,10 @@
mLauncherApps = mApp.getContext().getSystemService(LauncherApps.class);
mUserManager = mApp.getContext().getSystemService(UserManager.class);
- mUserCache = UserCache.INSTANCE.get(mApp.getContext());
+ mUserCache = UserCache.getInstance(mApp.getContext());
mSessionHelper = InstallSessionHelper.INSTANCE.get(mApp.getContext());
mIconCache = mApp.getIconCache();
+ mUserManagerState = userManagerState;
}
protected synchronized void waitForIdle() {
@@ -973,6 +985,8 @@
mBgAllAppsList.clear();
List<IconRequestInfo<AppInfo>> iconRequestInfos = new ArrayList<>();
+ boolean isWorkProfileQuiet = false;
+ boolean isPrivateProfileQuiet = false;
for (UserHandle user : profiles) {
// Query for the set of apps
final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
@@ -982,6 +996,14 @@
return allActivityList;
}
boolean quietMode = mUserManagerState.isUserQuiet(user);
+
+ if (Flags.enablePrivateSpace()) {
+ if (mUserCache.getUserInfo(user).isWork()) {
+ isWorkProfileQuiet = quietMode;
+ } else if (mUserCache.getUserInfo(user).isPrivate()) {
+ isPrivateProfileQuiet = quietMode;
+ }
+ }
// Create the ApplicationInfos
for (int i = 0; i < apps.size(); i++) {
LauncherActivityInfo app = apps.get(i);
@@ -1023,8 +1045,13 @@
Trace.endSection();
}
- mBgAllAppsList.setFlags(FLAG_QUIET_MODE_ENABLED,
- mUserManagerState.isAnyProfileQuietModeEnabled());
+ if (Flags.enablePrivateSpace()) {
+ mBgAllAppsList.setFlags(FLAG_WORK_PROFILE_QUIET_MODE_ENABLED, isWorkProfileQuiet);
+ mBgAllAppsList.setFlags(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED, isPrivateProfileQuiet);
+ } else {
+ mBgAllAppsList.setFlags(FLAG_QUIET_MODE_ENABLED,
+ mUserManagerState.isAnyProfileQuietModeEnabled());
+ }
mBgAllAppsList.setFlags(FLAG_HAS_SHORTCUT_PERMISSION,
hasShortcutsPermission(mApp.getContext()));
mBgAllAppsList.setFlags(FLAG_QUIET_MODE_CHANGE_PERMISSION,
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 37a7171..9a0a6eb 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -15,7 +15,9 @@
*/
package com.android.launcher3.model;
+import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED;
+import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_WORK_PROFILE_QUIET_MODE_ENABLED;
import static com.android.launcher3.model.data.WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON;
import static com.android.launcher3.model.data.WorkspaceItemInfo.FLAG_RESTORED_ICON;
@@ -31,6 +33,7 @@
import androidx.annotation.NonNull;
+import com.android.launcher3.Flags;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
@@ -169,14 +172,24 @@
break;
case OP_USER_AVAILABILITY_CHANGE: {
UserManagerState ums = new UserManagerState();
- ums.init(UserCache.INSTANCE.get(context),
- context.getSystemService(UserManager.class));
+ UserManager userManager = context.getSystemService(UserManager.class);
+ ums.init(UserCache.INSTANCE.get(context), userManager);
+ boolean isUserQuiet = ums.isUserQuiet(mUser);
flagOp = FlagOp.NO_OP.setFlag(
- WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER, ums.isUserQuiet(mUser));
+ WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER, isUserQuiet);
appsList.updateDisabledFlags(matcher, flagOp);
- // We are not synchronizing here, as int operations are atomic
- appsList.setFlags(FLAG_QUIET_MODE_ENABLED, ums.isAnyProfileQuietModeEnabled());
+ if (Flags.enablePrivateSpace()) {
+ UserCache userCache = UserCache.INSTANCE.get(context);
+ if (userCache.getUserInfo(mUser).isWork()) {
+ appsList.setFlags(FLAG_WORK_PROFILE_QUIET_MODE_ENABLED, isUserQuiet);
+ } else if (userCache.getUserInfo(mUser).isPrivate()) {
+ appsList.setFlags(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED, isUserQuiet);
+ }
+ } else {
+ // We are not synchronizing here, as int operations are atomic
+ appsList.setFlags(FLAG_QUIET_MODE_ENABLED, ums.isAnyProfileQuietModeEnabled());
+ }
break;
}
default:
diff --git a/src/com/android/launcher3/model/UserManagerState.java b/src/com/android/launcher3/model/UserManagerState.java
index 97a5905..720f08e 100644
--- a/src/com/android/launcher3/model/UserManagerState.java
+++ b/src/com/android/launcher3/model/UserManagerState.java
@@ -61,6 +61,9 @@
/**
* Returns true if any user profile has quiet mode enabled.
+ * <p>
+ * Do not use this for determining if a specific profile has quiet mode enabled, as their can
+ * be more than one profile in quiet mode.
*/
public boolean isAnyProfileQuietModeEnabled() {
for (int i = mQuietUsersHashCodeMap.size() - 1; i >= 0; i--) {
diff --git a/src/com/android/launcher3/pm/UserCache.java b/src/com/android/launcher3/pm/UserCache.java
index e2b1286..4661fd4 100644
--- a/src/com/android/launcher3/pm/UserCache.java
+++ b/src/com/android/launcher3/pm/UserCache.java
@@ -55,10 +55,18 @@
? Intent.ACTION_PROFILE_ACCESSIBLE : Intent.ACTION_MANAGED_PROFILE_UNLOCKED;
public static final String ACTION_PROFILE_LOCKED = ATLEAST_U
? Intent.ACTION_PROFILE_INACCESSIBLE : Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE;
+ public static final String ACTION_PROFILE_AVAILABLE = "android.intent.action.PROFILE_AVAILABLE";
+ public static final String ACTION_PROFILE_UNAVAILABLE =
+ "android.intent.action.PROFILE_UNAVAILABLE";
public static final MainThreadInitializedObject<UserCache> INSTANCE =
new MainThreadInitializedObject<>(UserCache::new);
+ /** Returns an instance of UserCache bound to the context provided. */
+ public static UserCache getInstance(Context context) {
+ return INSTANCE.get(context);
+ }
+
private final List<BiConsumer<UserHandle, String>> mUserEventListeners = new ArrayList<>();
private final SimpleBroadcastReceiver mUserChangeReceiver =
new SimpleBroadcastReceiver(this::onUsersChanged);
@@ -87,7 +95,9 @@
ACTION_PROFILE_ADDED,
ACTION_PROFILE_REMOVED,
ACTION_PROFILE_UNLOCKED,
- ACTION_PROFILE_LOCKED);
+ ACTION_PROFILE_LOCKED,
+ ACTION_PROFILE_AVAILABLE,
+ ACTION_PROFILE_UNAVAILABLE);
updateCache();
}
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 685e4f1..e3314d4 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -127,6 +127,7 @@
protected final float mElevation;
+ // Tag for Views that have children that will need to be iterated to add styling.
private final String mIterateChildrenTag;
protected final int[] mColorIds;
@@ -244,7 +245,7 @@
for (int i = 0; i < count; i++) {
View view = viewGroup.getChildAt(i);
if (view.getVisibility() == VISIBLE) {
- if (lastView != null) {
+ if (lastView != null && (isShortcutContainer(lastView))) {
MarginLayoutParams mlp = (MarginLayoutParams) lastView.getLayoutParams();
mlp.bottomMargin = mChildContainerMargin;
}
diff --git a/src/com/android/launcher3/responsive/AllAppsSpecs.kt b/src/com/android/launcher3/responsive/AllAppsSpecs.kt
deleted file mode 100644
index 8ed3ffc..0000000
--- a/src/com/android/launcher3/responsive/AllAppsSpecs.kt
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.responsive
-
-import android.content.res.TypedArray
-import com.android.launcher3.R
-import com.android.launcher3.responsive.ResponsiveSpec.SpecType
-import com.android.launcher3.util.ResourceHelper
-
-class AllAppsSpecs(widthSpecs: List<AllAppsSpec>, heightSpecs: List<AllAppsSpec>) :
- ResponsiveSpecs<AllAppsSpec>(widthSpecs, heightSpecs) {
-
- fun getCalculatedWidthSpec(
- columns: Int,
- availableWidth: Int,
- calculatedWorkspaceSpec: CalculatedWorkspaceSpec
- ): CalculatedAllAppsSpec {
- check(calculatedWorkspaceSpec.spec.specType == SpecType.WIDTH) {
- "Invalid specType for CalculatedWorkspaceSpec. " +
- "Expected: ${SpecType.WIDTH} - " +
- "Found: ${calculatedWorkspaceSpec.spec.specType}}"
- }
-
- val spec = getWidthSpec(availableWidth)
- return CalculatedAllAppsSpec(availableWidth, columns, spec, calculatedWorkspaceSpec)
- }
-
- fun getCalculatedHeightSpec(
- rows: Int,
- availableHeight: Int,
- calculatedWorkspaceSpec: CalculatedWorkspaceSpec
- ): CalculatedAllAppsSpec {
- check(calculatedWorkspaceSpec.spec.specType == SpecType.HEIGHT) {
- "Invalid specType for CalculatedWorkspaceSpec. " +
- "Expected: ${SpecType.HEIGHT} - " +
- "Found: ${calculatedWorkspaceSpec.spec.specType}}"
- }
-
- val spec = getHeightSpec(availableHeight)
- return CalculatedAllAppsSpec(availableHeight, rows, spec, calculatedWorkspaceSpec)
- }
-
- companion object {
- private const val XML_ALL_APPS_SPEC = "allAppsSpec"
-
- @JvmStatic
- fun create(resourceHelper: ResourceHelper): AllAppsSpecs {
- val parser = ResponsiveSpecsParser(resourceHelper)
- val specs = parser.parseXML(XML_ALL_APPS_SPEC, ::AllAppsSpec)
- val (widthSpecs, heightSpecs) = specs.partition { it.specType == SpecType.WIDTH }
- return AllAppsSpecs(widthSpecs, heightSpecs)
- }
- }
-}
-
-data class AllAppsSpec(
- override val maxAvailableSize: Int,
- override val specType: SpecType,
- override val startPadding: SizeSpec,
- override val endPadding: SizeSpec,
- override val gutter: SizeSpec,
- override val cellSize: SizeSpec
-) : ResponsiveSpec(maxAvailableSize, specType, startPadding, endPadding, gutter, cellSize) {
-
- init {
- check(isValid()) { "Invalid AllAppsSpec found." }
- }
-
- constructor(
- attrs: TypedArray,
- specs: Map<String, SizeSpec>
- ) : this(
- maxAvailableSize =
- attrs.getDimensionPixelSize(R.styleable.ResponsiveSpec_maxAvailableSize, 0),
- specType =
- SpecType.values()[
- attrs.getInt(R.styleable.ResponsiveSpec_specType, SpecType.HEIGHT.ordinal)],
- startPadding = specs.getOrError(SizeSpec.XmlTags.START_PADDING),
- endPadding = specs.getOrError(SizeSpec.XmlTags.END_PADDING),
- gutter = specs.getOrError(SizeSpec.XmlTags.GUTTER),
- cellSize = specs.getOrError(SizeSpec.XmlTags.CELL_SIZE)
- )
-}
-
-class CalculatedAllAppsSpec(
- availableSpace: Int,
- cells: Int,
- spec: AllAppsSpec,
- calculatedWorkspaceSpec: CalculatedWorkspaceSpec
-) : CalculatedResponsiveSpec(availableSpace, cells, spec, calculatedWorkspaceSpec)
diff --git a/src/com/android/launcher3/responsive/FolderSpecs.kt b/src/com/android/launcher3/responsive/FolderSpecs.kt
deleted file mode 100644
index bc2db28..0000000
--- a/src/com/android/launcher3/responsive/FolderSpecs.kt
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.responsive
-
-import android.content.res.TypedArray
-import com.android.launcher3.R
-import com.android.launcher3.responsive.ResponsiveSpec.SpecType
-import com.android.launcher3.util.ResourceHelper
-
-class FolderSpecs(widthSpecs: List<FolderSpec>, heightSpecs: List<FolderSpec>) :
- ResponsiveSpecs<FolderSpec>(widthSpecs, heightSpecs) {
-
- fun getCalculatedWidthSpec(
- columns: Int,
- availableWidth: Int,
- calculatedWorkspaceSpec: CalculatedWorkspaceSpec
- ): CalculatedFolderSpec {
- check(calculatedWorkspaceSpec.spec.specType == SpecType.WIDTH) {
- "Invalid specType for CalculatedWorkspaceSpec. " +
- "Expected: ${SpecType.WIDTH} - " +
- "Found: ${calculatedWorkspaceSpec.spec.specType}}"
- }
-
- val spec = getWidthSpec(availableWidth)
- return CalculatedFolderSpec(availableWidth, columns, spec, calculatedWorkspaceSpec)
- }
-
- fun getCalculatedHeightSpec(
- rows: Int,
- availableHeight: Int,
- calculatedWorkspaceSpec: CalculatedWorkspaceSpec
- ): CalculatedFolderSpec {
- check(calculatedWorkspaceSpec.spec.specType == SpecType.HEIGHT) {
- "Invalid specType for CalculatedWorkspaceSpec. " +
- "Expected: ${SpecType.HEIGHT} - " +
- "Found: ${calculatedWorkspaceSpec.spec.specType}}"
- }
-
- val spec = getHeightSpec(availableHeight)
- return CalculatedFolderSpec(availableHeight, rows, spec, calculatedWorkspaceSpec)
- }
-
- companion object {
-
- private const val XML_FOLDER_SPEC = "folderSpec"
-
- @JvmStatic
- fun create(resourceHelper: ResourceHelper): FolderSpecs {
- val parser = ResponsiveSpecsParser(resourceHelper)
- val specs = parser.parseXML(XML_FOLDER_SPEC, ::FolderSpec)
- val (widthSpecs, heightSpecs) = specs.partition { it.specType == SpecType.WIDTH }
- return FolderSpecs(widthSpecs, heightSpecs)
- }
- }
-}
-
-data class FolderSpec(
- override val maxAvailableSize: Int,
- override val specType: SpecType,
- override val startPadding: SizeSpec,
- override val endPadding: SizeSpec,
- override val gutter: SizeSpec,
- override val cellSize: SizeSpec
-) : ResponsiveSpec(maxAvailableSize, specType, startPadding, endPadding, gutter, cellSize) {
-
- init {
- check(isValid()) { "Invalid FolderSpec found." }
- }
-
- constructor(
- attrs: TypedArray,
- specs: Map<String, SizeSpec>
- ) : this(
- maxAvailableSize =
- attrs.getDimensionPixelSize(R.styleable.ResponsiveSpec_maxAvailableSize, 0),
- specType =
- SpecType.values()[
- attrs.getInt(R.styleable.ResponsiveSpec_specType, SpecType.HEIGHT.ordinal)],
- startPadding = specs.getOrError(SizeSpec.XmlTags.START_PADDING),
- endPadding = specs.getOrError(SizeSpec.XmlTags.END_PADDING),
- gutter = specs.getOrError(SizeSpec.XmlTags.GUTTER),
- cellSize = specs.getOrError(SizeSpec.XmlTags.CELL_SIZE)
- )
-}
-
-class CalculatedFolderSpec(
- availableSpace: Int,
- cells: Int,
- spec: FolderSpec,
- calculatedWorkspaceSpec: CalculatedWorkspaceSpec
-) : CalculatedResponsiveSpec(availableSpace, cells, spec, calculatedWorkspaceSpec)
diff --git a/src/com/android/launcher3/responsive/HotseatSpecs.kt b/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt
similarity index 69%
rename from src/com/android/launcher3/responsive/HotseatSpecs.kt
rename to src/com/android/launcher3/responsive/HotseatSpecsProvider.kt
index 37a682f..8710303 100644
--- a/src/com/android/launcher3/responsive/HotseatSpecs.kt
+++ b/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt
@@ -19,67 +19,65 @@
import android.content.res.TypedArray
import android.util.Log
import com.android.launcher3.R
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
+import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
import com.android.launcher3.util.ResourceHelper
-class HotseatSpecs(widthSpecs: List<HotseatSpec>, heightSpecs: List<HotseatSpec>) {
+class HotseatSpecsProvider(private val groupOfSpecs: List<ResponsiveSpecGroup<HotseatSpec>>) {
+ fun getSpecsByAspectRatio(aspectRatio: Float): ResponsiveSpecGroup<HotseatSpec> {
+ check(aspectRatio > 0f) { "Invalid aspect ratio! The value should be bigger than 0." }
- val widthSpecs: List<HotseatSpec>
- val heightSpecs: List<HotseatSpec>
+ val specsGroup = groupOfSpecs.firstOrNull { aspectRatio <= it.aspectRatio }
+ check(specsGroup != null) { "No available spec with aspectRatio within $aspectRatio." }
- init {
- this.widthSpecs = widthSpecs.sortedBy { it.maxAvailableSize }
- this.heightSpecs = heightSpecs.sortedBy { it.maxAvailableSize }
+ return specsGroup
}
- fun getCalculatedHeightSpec(availableHeight: Int): CalculatedHotseatSpec {
- val spec = heightSpecs.firstOrNull { availableHeight <= it.maxAvailableSize }
- check(spec != null) { "No available height spec found within $availableHeight." }
- return CalculatedHotseatSpec(availableHeight, spec)
- }
-
- fun getCalculatedWidthSpec(availableWidth: Int): CalculatedHotseatSpec {
- val spec = widthSpecs.firstOrNull { availableWidth <= it.maxAvailableSize }
- check(spec != null) { "No available width spec found within $availableWidth." }
- return CalculatedHotseatSpec(availableWidth, spec)
+ fun getCalculatedSpec(
+ aspectRatio: Float,
+ dimensionType: DimensionType,
+ availableSpace: Int
+ ): CalculatedHotseatSpec {
+ val specsGroup = getSpecsByAspectRatio(aspectRatio)
+ val spec = specsGroup.getSpec(dimensionType, availableSpace)
+ return CalculatedHotseatSpec(availableSpace, spec)
}
companion object {
- private const val XML_HOTSEAT_SPEC = "hotseatSpec"
-
@JvmStatic
- fun create(resourceHelper: ResourceHelper): HotseatSpecs {
+ fun create(resourceHelper: ResourceHelper): HotseatSpecsProvider {
val parser = ResponsiveSpecsParser(resourceHelper)
- val specs = parser.parseXML(XML_HOTSEAT_SPEC, ::HotseatSpec)
- val (widthSpecs, heightSpecs) =
- specs.partition { it.specType == ResponsiveSpec.SpecType.WIDTH }
- return HotseatSpecs(widthSpecs, heightSpecs)
+ val specs = parser.parseXML(ResponsiveSpecType.Hotseat, ::HotseatSpec)
+ return HotseatSpecsProvider(specs)
}
}
}
data class HotseatSpec(
- val maxAvailableSize: Int,
- val specType: ResponsiveSpec.SpecType,
+ override val maxAvailableSize: Int,
+ override val dimensionType: DimensionType,
+ override val specType: ResponsiveSpecType,
val hotseatQsbSpace: SizeSpec,
val edgePadding: SizeSpec
-) {
-
+) : IResponsiveSpec {
init {
check(isValid()) { "Invalid HotseatSpec found." }
}
constructor(
+ responsiveSpecType: ResponsiveSpecType,
attrs: TypedArray,
specs: Map<String, SizeSpec>
) : this(
maxAvailableSize =
attrs.getDimensionPixelSize(R.styleable.ResponsiveSpec_maxAvailableSize, 0),
- specType =
- ResponsiveSpec.SpecType.values()[
+ dimensionType =
+ DimensionType.entries[
attrs.getInt(
- R.styleable.ResponsiveSpec_specType,
- ResponsiveSpec.SpecType.HEIGHT.ordinal
+ R.styleable.ResponsiveSpec_dimensionType,
+ DimensionType.HEIGHT.ordinal
)],
+ specType = responsiveSpecType,
hotseatQsbSpace = specs.getOrError(SizeSpec.XmlTags.HOTSEAT_QSB_SPACE),
edgePadding = specs.getOrError(SizeSpec.XmlTags.EDGE_PADDING)
)
diff --git a/src/com/android/launcher3/responsive/ResponsiveSpecs.kt b/src/com/android/launcher3/responsive/ResponsiveSpec.kt
similarity index 60%
rename from src/com/android/launcher3/responsive/ResponsiveSpecs.kt
rename to src/com/android/launcher3/responsive/ResponsiveSpec.kt
index a43c44a..413e2dc 100644
--- a/src/com/android/launcher3/responsive/ResponsiveSpecs.kt
+++ b/src/com/android/launcher3/responsive/ResponsiveSpec.kt
@@ -16,75 +16,84 @@
package com.android.launcher3.responsive
+import android.content.res.TypedArray
import android.util.Log
+import com.android.launcher3.R
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
/**
- * Base class for responsive specs that holds a list of width and height specs.
+ * Interface for responsive grid specs
*
- * @param widthSpecs List of width responsive specifications
- * @param heightSpecs List of height responsive specifications
+ * @property maxAvailableSize indicates the breakpoint to use this specification.
+ * @property dimensionType indicates whether the paddings and gutters will be applied vertically or
+ * horizontally.
+ * @property specType a [ResponsiveSpecType] that indicates the type of the spec.
*/
-abstract class ResponsiveSpecs<T : ResponsiveSpec>(widthSpecs: List<T>, heightSpecs: List<T>) {
- val widthSpecs: List<T>
- val heightSpecs: List<T>
-
- init {
- check(widthSpecs.isNotEmpty() && heightSpecs.isNotEmpty()) {
- "${this::class.simpleName} is incomplete - " +
- "width list size = ${widthSpecs.size}; " +
- "height list size = ${heightSpecs.size}."
- }
-
- this.widthSpecs = widthSpecs.sortedBy { it.maxAvailableSize }
- this.heightSpecs = heightSpecs.sortedBy { it.maxAvailableSize }
- }
-
- /**
- * Get a [ResponsiveSpec] for width within the breakpoint.
- *
- * @param availableWidth The width breakpoint for the spec
- * @return A [ResponsiveSpec] for width.
- */
- fun getWidthSpec(availableWidth: Int): T {
- val spec = widthSpecs.firstOrNull { availableWidth <= it.maxAvailableSize }
- check(spec != null) { "No available width spec found within $availableWidth." }
- return spec
- }
-
- /**
- * Get a [ResponsiveSpec] for height within the breakpoint.
- *
- * @param availableHeight The height breakpoint for the spec
- * @return A [ResponsiveSpec] for height.
- */
- fun getHeightSpec(availableHeight: Int): T {
- val spec = heightSpecs.firstOrNull { availableHeight <= it.maxAvailableSize }
- check(spec != null) { "No available height spec found within $availableHeight." }
- return spec
- }
+interface IResponsiveSpec {
+ val maxAvailableSize: Int
+ val dimensionType: ResponsiveSpec.DimensionType
+ val specType: ResponsiveSpecType
}
/**
- * Base class for a responsive specification that is used to calculate the paddings, gutter and cell
+ * Class for a responsive specification that is used to calculate the paddings, gutter and cell
* size.
*
* @param maxAvailableSize indicates the breakpoint to use this specification.
- * @param specType indicates whether the paddings and gutters will be applied vertically or
+ * @param dimensionType indicates whether the paddings and gutters will be applied vertically or
* horizontally.
+ * @param specType a [ResponsiveSpecType] that indicates the type of the spec.
* @param startPadding padding used at the top or left (right in RTL) in the workspace folder.
* @param endPadding padding used at the bottom or right (left in RTL) in the workspace folder.
- * @param gutter the space between the cells vertically or horizontally depending on the [specType].
- * @param cellSize height or width of the cell depending on the [specType].
+ * @param gutter the space between the cells vertically or horizontally depending on the
+ * [dimensionType].
+ * @param cellSize height or width of the cell depending on the [dimensionType].
*/
-abstract class ResponsiveSpec(
- open val maxAvailableSize: Int,
- open val specType: SpecType,
- open val startPadding: SizeSpec,
- open val endPadding: SizeSpec,
- open val gutter: SizeSpec,
- open val cellSize: SizeSpec
-) {
- open fun isValid(): Boolean {
+data class ResponsiveSpec(
+ override val maxAvailableSize: Int,
+ override val dimensionType: DimensionType,
+ override val specType: ResponsiveSpecType,
+ val startPadding: SizeSpec,
+ val endPadding: SizeSpec,
+ val gutter: SizeSpec,
+ val cellSize: SizeSpec,
+) : IResponsiveSpec {
+ init {
+ check(isValid()) { "Invalid ResponsiveSpec found." }
+ }
+
+ constructor(
+ responsiveSpecType: ResponsiveSpecType,
+ attrs: TypedArray,
+ specs: Map<String, SizeSpec>
+ ) : this(
+ maxAvailableSize =
+ attrs.getDimensionPixelSize(R.styleable.ResponsiveSpec_maxAvailableSize, 0),
+ dimensionType =
+ DimensionType.entries[
+ attrs.getInt(
+ R.styleable.ResponsiveSpec_dimensionType,
+ DimensionType.HEIGHT.ordinal
+ )],
+ specType = responsiveSpecType,
+ startPadding = specs.getOrError(SizeSpec.XmlTags.START_PADDING),
+ endPadding = specs.getOrError(SizeSpec.XmlTags.END_PADDING),
+ gutter = specs.getOrError(SizeSpec.XmlTags.GUTTER),
+ cellSize = specs.getOrError(SizeSpec.XmlTags.CELL_SIZE)
+ )
+
+ fun isValid(): Boolean {
+ if (
+ (specType == ResponsiveSpecType.Workspace) &&
+ (startPadding.matchWorkspace ||
+ endPadding.matchWorkspace ||
+ gutter.matchWorkspace ||
+ cellSize.matchWorkspace)
+ ) {
+ Log.e(LOG_TAG, "WorkspaceSpec#isValid - workspace shouldn't contain matchWorkspace!")
+ return false
+ }
+
if (maxAvailableSize <= 0) {
Log.e(LOG_TAG, "${this::class.simpleName}#isValid - maxAvailableSize <= 0")
return false
@@ -106,13 +115,20 @@
cellSize.isValid()
}
- enum class SpecType {
+ enum class DimensionType {
HEIGHT,
WIDTH
}
companion object {
private const val LOG_TAG = "ResponsiveSpec"
+
+ enum class ResponsiveSpecType(val xmlTag: String) {
+ AllApps("allAppsSpec"),
+ Folder("folderSpec"),
+ Workspace("workspaceSpec"),
+ Hotseat("hotseatSpec")
+ }
}
}
@@ -120,7 +136,10 @@
* Calculated responsive specs contains the final paddings, gutter and cell size in pixels after
* they are calculated from the available space, cells and workspace specs.
*/
-sealed class CalculatedResponsiveSpec {
+class CalculatedResponsiveSpec {
+ var aspectRatio: Float = Float.NaN
+ private set
+
var availableSpace: Int = 0
private set
@@ -143,11 +162,13 @@
private set
constructor(
+ aspectRatio: Float,
availableSpace: Int,
cells: Int,
spec: ResponsiveSpec,
- calculatedWorkspaceSpec: CalculatedWorkspaceSpec
+ calculatedWorkspaceSpec: CalculatedResponsiveSpec
) {
+ this.aspectRatio = aspectRatio
this.availableSpace = availableSpace
this.cells = cells
this.spec = spec
@@ -167,7 +188,8 @@
updateRemainderSpaces(availableSpace, cells, spec)
}
- constructor(availableSpace: Int, cells: Int, spec: ResponsiveSpec) {
+ constructor(aspectRatio: Float, availableSpace: Int, cells: Int, spec: ResponsiveSpec) {
+ this.aspectRatio = aspectRatio
this.availableSpace = availableSpace
this.cells = cells
this.spec = spec
@@ -181,6 +203,11 @@
updateRemainderSpaces(availableSpace, cells, spec)
}
+ fun isResponsiveSpecType(type: ResponsiveSpecType) = spec.specType == type
+
+ // TODO(b/287975993): Remove this after icon size is extracted to responsive grid
+ fun isCellSizeMatchWorkspace(): Boolean = spec.cellSize.matchWorkspace
+
private fun updateRemainderSpaces(availableSpace: Int, cells: Int, spec: ResponsiveSpec) {
val gutters = cells - 1
val usedSpace = startPaddingPx + endPaddingPx + (gutterPx * gutters) + (cellSizePx * cells)
@@ -215,10 +242,11 @@
}
override fun toString(): String {
- return "${this::class.simpleName}(" +
+ return "Calculated${spec.specType}Spec(" +
"availableSpace=$availableSpace, cells=$cells, startPaddingPx=$startPaddingPx, " +
"endPaddingPx=$endPaddingPx, gutterPx=$gutterPx, cellSizePx=$cellSizePx, " +
- "${spec::class.simpleName}.maxAvailableSize=${spec.maxAvailableSize}" +
+ "aspectRatio=${aspectRatio}, " +
+ "${spec.specType}Spec.maxAvailableSize=${spec.maxAvailableSize}" +
")"
}
}
diff --git a/src/com/android/launcher3/responsive/ResponsiveSpecGroup.kt b/src/com/android/launcher3/responsive/ResponsiveSpecGroup.kt
new file mode 100644
index 0000000..b233d7c
--- /dev/null
+++ b/src/com/android/launcher3/responsive/ResponsiveSpecGroup.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.responsive
+
+import android.content.res.TypedArray
+import com.android.launcher3.R
+import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
+
+/**
+ * Base class for responsive specs that holds a list of width and height specs.
+ *
+ * @param widthSpecs List of width responsive specifications
+ * @param heightSpecs List of height responsive specifications
+ */
+class ResponsiveSpecGroup<T : IResponsiveSpec>(
+ val aspectRatio: Float,
+ widthSpecs: List<T>,
+ heightSpecs: List<T>
+) {
+ val widthSpecs: List<T>
+ val heightSpecs: List<T>
+
+ init {
+ check(aspectRatio > 0f) { "Invalid aspect ratio! Aspect ratio should be bigger than zero." }
+ this.widthSpecs = widthSpecs.sortedBy { it.maxAvailableSize }
+ this.heightSpecs = heightSpecs.sortedBy { it.maxAvailableSize }
+ }
+
+ /**
+ * Get a [ResponsiveSpec] within the breakpoint.
+ *
+ * @param type Type of the spec to be retrieved (width or height)
+ * @param availableSize The breakpoint for the spec
+ * @return A [ResponsiveSpec].
+ */
+ fun getSpec(type: DimensionType, availableSize: Int): T {
+ val spec =
+ if (type == DimensionType.WIDTH) {
+ widthSpecs.firstOrNull { availableSize <= it.maxAvailableSize }
+ } else {
+ heightSpecs.firstOrNull { availableSize <= it.maxAvailableSize }
+ }
+ check(spec != null) { "No available $type spec found within $availableSize." }
+ return spec
+ }
+
+ companion object {
+ const val XML_GROUP_NAME = "specs"
+
+ fun <T : IResponsiveSpec> create(
+ attrs: TypedArray,
+ specs: List<T>
+ ): ResponsiveSpecGroup<T> {
+ val (widthSpecs, heightSpecs) =
+ specs.partition { it.dimensionType == DimensionType.WIDTH }
+ val aspectRatio = attrs.getFloat(R.styleable.ResponsiveSpecGroup_maxAspectRatio, 0f)
+ return ResponsiveSpecGroup(aspectRatio, widthSpecs, heightSpecs)
+ }
+ }
+}
diff --git a/src/com/android/launcher3/responsive/ResponsiveSpecsParser.kt b/src/com/android/launcher3/responsive/ResponsiveSpecsParser.kt
index a89b619..d782cd5 100644
--- a/src/com/android/launcher3/responsive/ResponsiveSpecsParser.kt
+++ b/src/com/android/launcher3/responsive/ResponsiveSpecsParser.kt
@@ -20,6 +20,7 @@
import android.content.res.XmlResourceParser
import android.util.Xml
import com.android.launcher3.R
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
import com.android.launcher3.util.ResourceHelper
import java.io.IOException
import org.xmlpull.v1.XmlPullParser
@@ -27,6 +28,80 @@
class ResponsiveSpecsParser(private val resourceHelper: ResourceHelper) {
+ fun <T : IResponsiveSpec> parseXML(
+ responsiveSpecType: ResponsiveSpecType,
+ map:
+ (
+ responsiveSpecType: ResponsiveSpecType,
+ attributes: TypedArray,
+ sizeSpecs: Map<String, SizeSpec>
+ ) -> T
+ ): List<ResponsiveSpecGroup<T>> {
+ val parser: XmlResourceParser = resourceHelper.getXml()
+
+ try {
+ val groups = mutableListOf<ResponsiveSpecGroup<T>>()
+ val specs = mutableListOf<T>()
+ var groupAttrs: TypedArray? = null
+
+ var eventType = parser.eventType
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ // Parsing Group
+ when {
+ parser starts ResponsiveSpecGroup.XML_GROUP_NAME -> {
+ groupAttrs =
+ resourceHelper.obtainStyledAttributes(
+ Xml.asAttributeSet(parser),
+ R.styleable.ResponsiveSpecGroup
+ )
+ }
+ parser ends ResponsiveSpecGroup.XML_GROUP_NAME -> {
+ checkNotNull(groupAttrs)
+ groups += ResponsiveSpecGroup.create(groupAttrs, specs)
+ specs.clear()
+ groupAttrs.recycle()
+ groupAttrs = null
+ }
+ // Mapping Spec to WorkspaceSpec, AllAppsSpec, FolderSpecs, HotseatSpec
+ parser starts responsiveSpecType.xmlTag -> {
+ val attrs =
+ resourceHelper.obtainStyledAttributes(
+ Xml.asAttributeSet(parser),
+ R.styleable.ResponsiveSpec
+ )
+
+ val sizeSpecs = parseSizeSpecs(parser)
+ specs += map(responsiveSpecType, attrs, sizeSpecs)
+ attrs.recycle()
+ }
+ }
+
+ eventType = parser.next()
+ }
+
+ parser.close()
+
+ // All the specs should have been linked to a group, otherwise the XML is invalid
+ check(specs.isEmpty()) {
+ throw InvalidResponsiveGridSpec(
+ "Invalid XML. ${specs.size} specs not linked to a group."
+ )
+ }
+
+ return groups
+ } catch (e: Exception) {
+ when (e) {
+ is NoSuchFieldException,
+ is IOException,
+ is XmlPullParserException ->
+ throw RuntimeException("Failure parsing specs file.", e)
+ else -> throw e
+ }
+ } finally {
+ parser.close()
+ }
+ }
+
private fun parseSizeSpecs(parser: XmlResourceParser): Map<String, SizeSpec> {
val parentName = parser.name
parser.next()
@@ -42,49 +117,15 @@
return result
}
- fun <T> parseXML(
- tagName: String,
- map: (attributes: TypedArray, sizeSpecs: Map<String, SizeSpec>) -> T
- ): List<T> {
- val parser: XmlResourceParser = resourceHelper.getXml()
+ private infix fun XmlResourceParser.starts(tag: String): Boolean =
+ name == tag && eventType == XmlPullParser.START_TAG
- try {
- val list = mutableListOf<T>()
-
- var eventType = parser.eventType
- while (eventType != XmlPullParser.END_DOCUMENT) {
- if (eventType == XmlResourceParser.START_TAG && parser.name == tagName) {
- val attrs =
- resourceHelper.obtainStyledAttributes(
- Xml.asAttributeSet(parser),
- R.styleable.ResponsiveSpec
- )
-
- val sizeSpecs = parseSizeSpecs(parser)
- list += map(attrs, sizeSpecs)
- attrs.recycle()
- }
-
- eventType = parser.next()
- }
-
- parser.close()
-
- return list
- } catch (e: Exception) {
- when (e) {
- is NoSuchFieldException,
- is IOException,
- is XmlPullParserException ->
- throw RuntimeException("Failure parsing specs file.", e)
- else -> throw e
- }
- } finally {
- parser.close()
- }
- }
+ private infix fun XmlResourceParser.ends(tag: String): Boolean =
+ name == tag && eventType == XmlPullParser.END_TAG
}
fun Map<String, SizeSpec>.getOrError(key: String): SizeSpec {
return this.getOrElse(key) { error("Attr '$key' must be defined.") }
}
+
+class InvalidResponsiveGridSpec(message: String) : Exception(message)
diff --git a/src/com/android/launcher3/responsive/ResponsiveSpecsProvider.kt b/src/com/android/launcher3/responsive/ResponsiveSpecsProvider.kt
new file mode 100644
index 0000000..67eaac0
--- /dev/null
+++ b/src/com/android/launcher3/responsive/ResponsiveSpecsProvider.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.responsive
+
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
+import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
+import com.android.launcher3.util.ResourceHelper
+
+/**
+ * A class to provide responsive grid specs for workspace, folder and all apps.
+ *
+ * This class is responsible for provide width and height [CalculatedResponsiveSpec] to be used for
+ * the correct placement of the workspace, all apps and folders.
+ *
+ * @param type A [ResponsiveSpecType] to indicates the type of the spec.
+ * @param groupOfSpecs Groups of responsive specifications
+ */
+class ResponsiveSpecsProvider(
+ val type: ResponsiveSpecType,
+ groupOfSpecs: List<ResponsiveSpecGroup<ResponsiveSpec>>
+) {
+ private val groupOfSpecs: List<ResponsiveSpecGroup<ResponsiveSpec>>
+
+ init {
+ this.groupOfSpecs =
+ groupOfSpecs
+ .onEach { group ->
+ check(group.widthSpecs.isNotEmpty() && group.heightSpecs.isNotEmpty()) {
+ "${this::class.simpleName} is incomplete - " +
+ "width list size = ${group.widthSpecs.size}; " +
+ "height list size = ${group.heightSpecs.size}."
+ }
+ }
+ .sortedBy { it.aspectRatio }
+ }
+
+ fun getSpecsByAspectRatio(aspectRatio: Float): ResponsiveSpecGroup<ResponsiveSpec> {
+ check(aspectRatio > 0f) { "Invalid aspect ratio! The value should be bigger than 0." }
+
+ val specsGroup = groupOfSpecs.firstOrNull { aspectRatio <= it.aspectRatio }
+ checkNotNull(specsGroup) { "No available spec with aspectRatio within $aspectRatio." }
+
+ return specsGroup
+ }
+
+ /**
+ * Retrieves a responsive grid specification that matches the number of [numCells],
+ * * [availableSpace] and [aspectRatio].
+ *
+ * @param aspectRatio the device width divided by device height (aspect ratio) to filter the
+ * specifications
+ * @param dimensionType the grid axis of the spec width is x axis, height is y axis.
+ * @param numCells number of rows/columns in the grid
+ * @param availableSpace available width to filter the specifications
+ * @return A [CalculatedResponsiveSpec] that matches the parameters provided.
+ */
+ fun getCalculatedSpec(
+ aspectRatio: Float,
+ dimensionType: DimensionType,
+ numCells: Int,
+ availableSpace: Int,
+ ): CalculatedResponsiveSpec {
+ val specsGroup = getSpecsByAspectRatio(aspectRatio)
+ val spec = specsGroup.getSpec(dimensionType, availableSpace)
+ return CalculatedResponsiveSpec(aspectRatio, availableSpace, numCells, spec)
+ }
+
+ /**
+ * Retrieves a responsive grid specification that matches the number of [numCells],
+ * * [availableSpace] and [aspectRatio]. This function uses a [CalculatedResponsiveSpec] to
+ * match workspace when its true.
+ *
+ * @param aspectRatio the device width divided by device height (aspect ratio) to filter the
+ * specifications
+ * @param dimensionType the grid axis of the spec width is x axis, height is y axis.
+ * @param numCells number of rows/columns in the grid
+ * @param availableSpace available width to filter the specifications
+ * @param calculatedWorkspaceSpec the calculated workspace specification to use its values as
+ * base when matchWorkspace is true.
+ * @return A [CalculatedResponsiveSpec] that matches the parameters provided.
+ */
+ fun getCalculatedSpec(
+ aspectRatio: Float,
+ dimensionType: DimensionType,
+ numCells: Int,
+ availableSpace: Int,
+ calculatedWorkspaceSpec: CalculatedResponsiveSpec
+ ): CalculatedResponsiveSpec {
+ check(calculatedWorkspaceSpec.spec.dimensionType == dimensionType) {
+ "Invalid specType for CalculatedWorkspaceSpec. " +
+ "Expected: $dimensionType - " +
+ "Found: ${calculatedWorkspaceSpec.spec.dimensionType}}"
+ }
+
+ check(calculatedWorkspaceSpec.isResponsiveSpecType(ResponsiveSpecType.Workspace)) {
+ "Invalid specType for CalculatedWorkspaceSpec. " +
+ "Expected: ${ResponsiveSpecType.Workspace} - " +
+ "Found: ${calculatedWorkspaceSpec.spec.specType}}"
+ }
+
+ val specsGroup = getSpecsByAspectRatio(aspectRatio)
+ val spec = specsGroup.getSpec(dimensionType, availableSpace)
+ return CalculatedResponsiveSpec(
+ aspectRatio,
+ availableSpace,
+ numCells,
+ spec,
+ calculatedWorkspaceSpec
+ )
+ }
+
+ companion object {
+ @JvmStatic
+ fun create(
+ resourceHelper: ResourceHelper,
+ type: ResponsiveSpecType
+ ): ResponsiveSpecsProvider {
+ val parser = ResponsiveSpecsParser(resourceHelper)
+ val specs = parser.parseXML(type, ::ResponsiveSpec)
+ return ResponsiveSpecsProvider(type, specs)
+ }
+ }
+}
diff --git a/src/com/android/launcher3/responsive/WorkspaceSpecs.kt b/src/com/android/launcher3/responsive/WorkspaceSpecs.kt
deleted file mode 100644
index 0da7026..0000000
--- a/src/com/android/launcher3/responsive/WorkspaceSpecs.kt
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.responsive
-
-import android.content.res.TypedArray
-import android.util.Log
-import com.android.launcher3.R
-import com.android.launcher3.responsive.ResponsiveSpec.SpecType
-import com.android.launcher3.util.ResourceHelper
-
-private const val TAG = "WorkspaceSpecs"
-
-class WorkspaceSpecs(widthSpecs: List<WorkspaceSpec>, heightSpecs: List<WorkspaceSpec>) :
- ResponsiveSpecs<WorkspaceSpec>(widthSpecs, heightSpecs) {
-
- fun getCalculatedWidthSpec(columns: Int, availableWidth: Int): CalculatedWorkspaceSpec {
- val spec = getWidthSpec(availableWidth)
- return CalculatedWorkspaceSpec(availableWidth, columns, spec)
- }
-
- fun getCalculatedHeightSpec(rows: Int, availableHeight: Int): CalculatedWorkspaceSpec {
- val spec = getHeightSpec(availableHeight)
- return CalculatedWorkspaceSpec(availableHeight, rows, spec)
- }
-
- companion object {
- private const val XML_WORKSPACE_SPEC = "workspaceSpec"
-
- @JvmStatic
- fun create(resourceHelper: ResourceHelper): WorkspaceSpecs {
- val parser = ResponsiveSpecsParser(resourceHelper)
- val specs = parser.parseXML(XML_WORKSPACE_SPEC, ::WorkspaceSpec)
- val (widthSpecs, heightSpecs) = specs.partition { it.specType == SpecType.WIDTH }
- return WorkspaceSpecs(widthSpecs, heightSpecs)
- }
- }
-}
-
-data class WorkspaceSpec(
- override val maxAvailableSize: Int,
- override val specType: SpecType,
- override val startPadding: SizeSpec,
- override val endPadding: SizeSpec,
- override val gutter: SizeSpec,
- override val cellSize: SizeSpec
-) : ResponsiveSpec(maxAvailableSize, specType, startPadding, endPadding, gutter, cellSize) {
-
- init {
- check(isValid()) { "Invalid WorkspaceSpec found." }
- }
-
- constructor(
- attrs: TypedArray,
- specs: Map<String, SizeSpec>
- ) : this(
- maxAvailableSize =
- attrs.getDimensionPixelSize(R.styleable.ResponsiveSpec_maxAvailableSize, 0),
- specType =
- SpecType.values()[
- attrs.getInt(R.styleable.ResponsiveSpec_specType, SpecType.HEIGHT.ordinal)],
- startPadding = specs.getOrError(SizeSpec.XmlTags.START_PADDING),
- endPadding = specs.getOrError(SizeSpec.XmlTags.END_PADDING),
- gutter = specs.getOrError(SizeSpec.XmlTags.GUTTER),
- cellSize = specs.getOrError(SizeSpec.XmlTags.CELL_SIZE)
- )
-
- override fun isValid(): Boolean {
- // Workspace spec should not match workspace
- if (
- startPadding.matchWorkspace ||
- endPadding.matchWorkspace ||
- gutter.matchWorkspace ||
- cellSize.matchWorkspace
- ) {
- Log.e(TAG, "WorkspaceSpec#isValid - workspace shouldn't contain matchWorkspace!")
- return false
- }
-
- return super.isValid()
- }
-}
-
-class CalculatedWorkspaceSpec(availableSpace: Int, cells: Int, spec: WorkspaceSpec) :
- CalculatedResponsiveSpec(availableSpace, cells, spec)
diff --git a/src/com/android/launcher3/testing/TestLogging.java b/src/com/android/launcher3/testing/TestLogging.java
index 70691f8..60d0e95 100644
--- a/src/com/android/launcher3/testing/TestLogging.java
+++ b/src/com/android/launcher3/testing/TestLogging.java
@@ -76,7 +76,7 @@
// be more useful.
// That's why we pass false as the value for the 'reportToTapl' parameter.
recordEventSlow(sequence, message + ": " + event, false);
- registerEventNotFromTest(event);
+ if (action != MotionEvent.ACTION_CANCEL) registerEventNotFromTest(event);
}
}
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 8c12547..db32829 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -15,8 +15,8 @@
*/
package com.android.launcher3.touch;
-import static com.android.launcher3.Launcher.REQUEST_BIND_PENDING_APPWIDGET;
-import static com.android.launcher3.Launcher.REQUEST_RECONFIGURE_APPWIDGET;
+import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_BIND_PENDING_APPWIDGET;
+import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_RECONFIGURE_APPWIDGET;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_BY_PUBLISHER;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 26ab5b4..0470971 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -22,8 +22,8 @@
import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING;
import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING_KEY;
import static com.android.launcher3.Utilities.dpiFromPx;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_PINNING;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TRANSIENT_TASKBAR;
+import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.FlagDebugUtils.appendFlag;
import static com.android.launcher3.util.window.WindowManagerProxy.MIN_TABLET_WIDTH;
@@ -116,7 +116,7 @@
mContext = context;
mDM = context.getSystemService(DisplayManager.class);
- if (ENABLE_TASKBAR_PINNING.get()) {
+ if (enableTaskbarPinning()) {
attachTaskbarPinningSharedPreferenceChangeListener(mContext);
}
@@ -179,7 +179,7 @@
@Override
public void close() {
mDestroyed = true;
- if (ENABLE_TASKBAR_PINNING.get()) {
+ if (enableTaskbarPinning()) {
LauncherPrefs.get(mContext).removeListener(
mTaskbarPinningPreferenceChangeListener, TASKBAR_PINNING);
}
@@ -414,7 +414,7 @@
// sTransientTaskbarStatusForTests and update test to directly
// toggle shred preference to switch transient taskbar on/of
if (!Utilities.isRunningInTestHarness()
- && ENABLE_TASKBAR_PINNING.get()
+ && enableTaskbarPinning()
&& mIsTaskbarPinned) {
return false;
}
diff --git a/src/com/android/launcher3/util/IconSizeSteps.kt b/src/com/android/launcher3/util/IconSizeSteps.kt
index aa644b0..6128eb4 100644
--- a/src/com/android/launcher3/util/IconSizeSteps.kt
+++ b/src/com/android/launcher3/util/IconSizeSteps.kt
@@ -39,8 +39,8 @@
return steps[max(0, getIndexForIconSize(iconSizePx) - 1)]
}
- fun getIconSmallerThan(cellWidth: Int): Int {
- return steps.lastOrNull { it <= cellWidth } ?: steps[0]
+ fun getIconSmallerThan(cellSize: Int): Int {
+ return steps.lastOrNull { it <= cellSize } ?: steps[0]
}
private fun getIndexForIconSize(iconSizePx: Int): Int {
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index cf59085..cbc85b6 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -149,6 +149,13 @@
public void assignMarginsAndBackgrounds(ViewGroup viewGroup) {
assignMarginsAndBackgrounds(viewGroup,
getColorStateList(getContext(), mColorIds[0]).getDefaultColor());
+ // last shortcut doesn't need bottom margin
+ final int count = viewGroup.getChildCount() - 1;
+ for (int i = 0; i < count; i++) {
+ // These are shortcuts and not shortcut containers, but they still need bottom margin
+ MarginLayoutParams mlp = (MarginLayoutParams) viewGroup.getChildAt(i).getLayoutParams();
+ mlp.bottomMargin = mChildContainerMargin;
+ }
}
public static <T extends Context & ActivityContext> OptionsPopupView<T> show(
diff --git a/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java b/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
index 6f74fd9..99485be 100644
--- a/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
+++ b/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
@@ -257,8 +257,6 @@
throw new RuntimeException("Max size is too small for preview");
}
return BitmapRenderer.createHardwareBitmap(size, size, c -> {
- drawBoxWithShadow(c, size, size);
-
LauncherIcons li = LauncherIcons.obtain(mContext);
Drawable icon = li.createBadgedIconBitmap(
mutateOnMainThread(info.getFullResIcon(
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 78116ae..af77d03 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -101,6 +101,7 @@
// the table can display.
private static final float RECOMMENDATION_TABLE_HEIGHT_RATIO = 0.75f;
+ private final UserCache mUserCache;
private final UserManagerState mUserManagerState = new UserManagerState();
private final UserHandle mCurrentUser = Process.myUserHandle();
private final Predicate<WidgetsListBaseEntry> mPrimaryWidgetsFilter =
@@ -192,6 +193,7 @@
? resources.getDimensionPixelSize(R.dimen.all_apps_header_pill_height)
: 0;
+ mUserCache = UserCache.INSTANCE.get(context);
mUserManagerState.init(UserCache.INSTANCE.get(context),
context.getSystemService(UserManager.class));
}
@@ -311,7 +313,9 @@
if (adapterHolder.mAdapterType == AdapterHolder.SEARCH) {
mNoWidgetsView.setText(R.string.no_search_results);
} else if (adapterHolder.mAdapterType == AdapterHolder.WORK
- && mUserManagerState.isAnyProfileQuietModeEnabled()
+ && mUserCache.getUserProfiles().stream()
+ .filter(userHandle -> mUserCache.getUserInfo(userHandle).isWork())
+ .anyMatch(mUserManagerState::isUserQuiet)
&& mActivityContext.getStringCache() != null) {
mNoWidgetsView.setText(mActivityContext.getStringCache().workProfilePausedTitle);
} else {
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index ee151bb..bd9da0a 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -42,18 +42,7 @@
</receiver>
<receiver
- android:name="com.android.launcher3.testcomponent.AppWidgetNoConfigLarge"
- android:exported="true"
- android:label="No Config Large">
- <intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
- </intent-filter>
- <meta-data android:name="android.appwidget.provider"
- android:resource="@xml/appwidget_no_config_large"/>
- </receiver>
-
- <receiver
- android:name="com.android.launcher3.testcomponent.AppWdigetHidden"
+ android:name="com.android.launcher3.testcomponent.AppWidgetHidden"
android:exported="true"
android:label="Hidden widget">
<intent-filter>
@@ -84,7 +73,7 @@
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider"
- android:resource="@xml/appwidget_no_config"/>
+ android:resource="@xml/appwidget_no_config_large"/>
</receiver>
<receiver
diff --git a/tests/Launcher3Tests.xml b/tests/Launcher3Tests.xml
index 3fff622..0aed1e1 100644
--- a/tests/Launcher3Tests.xml
+++ b/tests/Launcher3Tests.xml
@@ -46,5 +46,6 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.launcher3.tests" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="instrumentation-arg" key="waitForActivitiesToComplete" value="false" />
</test>
</configuration>
diff --git a/tests/res/values/attrs.xml b/tests/res/values/attrs.xml
index e5ee064..2a7a346 100644
--- a/tests/res/values/attrs.xml
+++ b/tests/res/values/attrs.xml
@@ -19,25 +19,29 @@
<resources>
<!-- Responsive grids attributes -->
<declare-styleable name="ResponsiveSpec">
- <attr name="specType" format="integer">
+ <attr name="dimensionType" format="integer">
<enum name="height" value="0" />
<enum name="width" value="1" />
</attr>
<attr name="maxAvailableSize" format="dimension" />
</declare-styleable>
+ <declare-styleable name="ResponsiveSpecGroup">
+ <attr name="maxAspectRatio" format="float" />
+ </declare-styleable>
+
<declare-styleable name="WorkspaceSpec">
- <attr name="specType" />
+ <attr name="dimensionType" />
<attr name="maxAvailableSize" />
</declare-styleable>
<declare-styleable name="FolderSpec">
- <attr name="specType" />
+ <attr name="dimensionType" />
<attr name="maxAvailableSize" />
</declare-styleable>
<declare-styleable name="AllAppsSpec">
- <attr name="specType" />
+ <attr name="dimensionType" />
<attr name="maxAvailableSize" />
</declare-styleable>
diff --git a/tests/res/xml/invalid_all_apps_file_case_1.xml b/tests/res/xml/invalid_all_apps_file_case_1.xml
index 6fd35b1..d89e675 100644
--- a/tests/res/xml/invalid_all_apps_file_case_1.xml
+++ b/tests/res/xml/invalid_all_apps_file_case_1.xml
@@ -14,23 +14,24 @@
~ limitations under the License.
-->
<allAppsSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
- <allAppsSpec
- launcher:specType="height"
- launcher:maxAvailableSize="9999dp">
- <!-- missing startPadding -->
- <endPadding launcher:fixedSize="0dp" />
- <gutter launcher:matchWorkspace="true" />
- <cellSize launcher:matchWorkspace="true" />
- </allAppsSpec>
+ <specs launcher:maxAspectRatio="10">
+ <allAppsSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="9999dp">
+ <!-- missing startPadding -->
+ <endPadding launcher:fixedSize="0dp" />
+ <gutter launcher:matchWorkspace="true" />
+ <cellSize launcher:matchWorkspace="true" />
+ </allAppsSpec>
- <allAppsSpec
- launcher:specType="width"
- launcher:maxAvailableSize="9999dp">
- <startPadding launcher:matchWorkspace="true" />
- <endPadding launcher:matchWorkspace="true" />
- <gutter launcher:matchWorkspace="true" />
- <cellSize launcher:matchWorkspace="true" />
- </allAppsSpec>
-
+ <allAppsSpec
+ launcher:dimensionType="width"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:matchWorkspace="true" />
+ <endPadding launcher:matchWorkspace="true" />
+ <gutter launcher:matchWorkspace="true" />
+ <cellSize launcher:matchWorkspace="true" />
+ </allAppsSpec>
+ </specs>
</allAppsSpecs>
diff --git a/tests/res/xml/invalid_all_apps_file_case_2.xml b/tests/res/xml/invalid_all_apps_file_case_2.xml
index de9c1ac..d5540f2 100644
--- a/tests/res/xml/invalid_all_apps_file_case_2.xml
+++ b/tests/res/xml/invalid_all_apps_file_case_2.xml
@@ -14,25 +14,26 @@
~ limitations under the License.
-->
<allAppsSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
- <allAppsSpec
- launcher:specType="height"
- launcher:maxAvailableSize="9999dp">
- <startPadding launcher:fixedSize="0dp" />
- <endPadding launcher:fixedSize="0dp" />
- <!-- more than 1 value in one tag -->
- <gutter
- launcher:matchWorkspace="true"
- launcher:fixedSize="16dp" />
- <cellSize launcher:matchWorkspace="true" />
- </allAppsSpec>
+ <specs launcher:maxAspectRatio="10">
+ <allAppsSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="0dp" />
+ <endPadding launcher:fixedSize="0dp" />
+ <!-- more than 1 value in one tag -->
+ <gutter
+ launcher:matchWorkspace="true"
+ launcher:fixedSize="16dp" />
+ <cellSize launcher:matchWorkspace="true" />
+ </allAppsSpec>
- <allAppsSpec
- launcher:specType="width"
- launcher:maxAvailableSize="9999dp">
- <startPadding launcher:matchWorkspace="true" />
- <endPadding launcher:matchWorkspace="true" />
- <gutter launcher:matchWorkspace="true" />
- <cellSize launcher:matchWorkspace="true" />
- </allAppsSpec>
-
+ <allAppsSpec
+ launcher:dimensionType="width"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:matchWorkspace="true" />
+ <endPadding launcher:matchWorkspace="true" />
+ <gutter launcher:matchWorkspace="true" />
+ <cellSize launcher:matchWorkspace="true" />
+ </allAppsSpec>
+ </specs>
</allAppsSpecs>
\ No newline at end of file
diff --git a/tests/res/xml/invalid_all_apps_file_case_3.xml b/tests/res/xml/invalid_all_apps_file_case_3.xml
index 7af0af4..75c2172 100644
--- a/tests/res/xml/invalid_all_apps_file_case_3.xml
+++ b/tests/res/xml/invalid_all_apps_file_case_3.xml
@@ -14,24 +14,25 @@
~ limitations under the License.
-->
<allAppsSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
- <allAppsSpec
- launcher:specType="height"
- launcher:maxAvailableSize="9999dp">
- <startPadding launcher:fixedSize="0dp" />
- <endPadding launcher:fixedSize="0dp" />
- <gutter launcher:matchWorkspace="true" />
- <!-- value bigger than 1 -->
- <cellSize launcher:ofRemainderSpace="1.001" />
- </allAppsSpec>
+ <specs launcher:maxAspectRatio="10">
+ <allAppsSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="0dp" />
+ <endPadding launcher:fixedSize="0dp" />
+ <gutter launcher:matchWorkspace="true" />
+ <!-- value bigger than 1 -->
+ <cellSize launcher:ofRemainderSpace="1.001" />
+ </allAppsSpec>
- <allAppsSpec
- launcher:specType="width"
- launcher:maxAvailableSize="9999dp">
- <startPadding launcher:matchWorkspace="true" />
- <endPadding launcher:matchWorkspace="true" />
- <gutter launcher:matchWorkspace="true" />
- <cellSize launcher:matchWorkspace="true" />
- </allAppsSpec>
-
+ <allAppsSpec
+ launcher:dimensionType="width"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:matchWorkspace="true" />
+ <endPadding launcher:matchWorkspace="true" />
+ <gutter launcher:matchWorkspace="true" />
+ <cellSize launcher:matchWorkspace="true" />
+ </allAppsSpec>
+ </specs>
</allAppsSpecs>
diff --git a/tests/res/xml/invalid_folders_specs_1.xml b/tests/res/xml/invalid_folders_specs_1.xml
index 0864249..6583d62 100644
--- a/tests/res/xml/invalid_folders_specs_1.xml
+++ b/tests/res/xml/invalid_folders_specs_1.xml
@@ -16,25 +16,27 @@
<!-- Tablet - 6x5 portrait -->
<folderSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
- <folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
- <!-- missing startPadding -->
- <endPadding launcher:fixedSize="16dp" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:matchWorkspace="true" />
- </folderSpec>
- <folderSpec launcher:specType="width" launcher:maxAvailableSize="9999dp">
- <startPadding launcher:fixedSize="16dp" />
- <endPadding launcher:fixedSize="16dp" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:fixedSize="102dp" />
- </folderSpec>
+ <specs launcher:maxAspectRatio="10">
+ <folderSpec launcher:dimensionType="width" launcher:maxAvailableSize="800dp">
+ <!-- missing startPadding -->
+ <endPadding launcher:fixedSize="16dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:matchWorkspace="true" />
+ </folderSpec>
+ <folderSpec launcher:dimensionType="width" launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="16dp" />
+ <endPadding launcher:fixedSize="16dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:fixedSize="102dp" />
+ </folderSpec>
- <!-- Height spec is fixed -->
- <folderSpec launcher:specType="height" launcher:maxAvailableSize="9999dp">
- <startPadding launcher:fixedSize="24dp" />
- <!-- mapped to footer height size -->
- <endPadding launcher:fixedSize="64dp" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:fixedSize="104dp" />
- </folderSpec>
+ <!-- Height spec is fixed -->
+ <folderSpec launcher:dimensionType="height" launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="24dp" />
+ <!-- mapped to footer height size -->
+ <endPadding launcher:fixedSize="64dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:fixedSize="104dp" />
+ </folderSpec>
+ </specs>
</folderSpecs>
diff --git a/tests/res/xml/invalid_folders_specs_2.xml b/tests/res/xml/invalid_folders_specs_2.xml
index 0b7dd62..95ac856 100644
--- a/tests/res/xml/invalid_folders_specs_2.xml
+++ b/tests/res/xml/invalid_folders_specs_2.xml
@@ -16,28 +16,30 @@
<!-- Tablet - 6x5 portrait -->
<folderSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
- <folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
- <startPadding launcher:fixedSize="16dp" />
- <endPadding launcher:fixedSize="16dp" />
- <!-- more than 1 value in one tag -->
- <gutter
- launcher:ofAvailableSpace="0.0125"
- launcher:fixedSize="16dp" />
- <cellSize launcher:matchWorkspace="true" />
- </folderSpec>
- <folderSpec launcher:specType="width" launcher:maxAvailableSize="9999dp">
- <startPadding launcher:fixedSize="16dp" />
- <endPadding launcher:fixedSize="16dp" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:fixedSize="102dp" />
- </folderSpec>
+ <specs launcher:maxAspectRatio="10">
+ <folderSpec launcher:dimensionType="width" launcher:maxAvailableSize="800dp">
+ <startPadding launcher:fixedSize="16dp" />
+ <endPadding launcher:fixedSize="16dp" />
+ <!-- more than 1 value in one tag -->
+ <gutter
+ launcher:ofAvailableSpace="0.0125"
+ launcher:fixedSize="16dp" />
+ <cellSize launcher:matchWorkspace="true" />
+ </folderSpec>
+ <folderSpec launcher:dimensionType="width" launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="16dp" />
+ <endPadding launcher:fixedSize="16dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:fixedSize="102dp" />
+ </folderSpec>
- <!-- Height spec is fixed -->
- <folderSpec launcher:specType="height" launcher:maxAvailableSize="9999dp">
- <startPadding launcher:fixedSize="24dp" />
- <!-- mapped to footer height size -->
- <endPadding launcher:fixedSize="64dp" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:fixedSize="104dp" />
- </folderSpec>
+ <!-- Height spec is fixed -->
+ <folderSpec launcher:dimensionType="height" launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="24dp" />
+ <!-- mapped to footer height size -->
+ <endPadding launcher:fixedSize="64dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:fixedSize="104dp" />
+ </folderSpec>
+ </specs>
</folderSpecs>
diff --git a/tests/res/xml/invalid_folders_specs_3.xml b/tests/res/xml/invalid_folders_specs_3.xml
index 83fd3e1..f71040d 100644
--- a/tests/res/xml/invalid_folders_specs_3.xml
+++ b/tests/res/xml/invalid_folders_specs_3.xml
@@ -16,26 +16,28 @@
<!-- Tablet - 6x5 portrait - More the one value first gutter -->
<folderSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
- <folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
- <startPadding launcher:fixedSize="16dp" />
- <endPadding launcher:fixedSize="16dp" />
- <gutter launcher:fixedSize="16dp" />
- <!-- value bigger than 1 -->
- <cellSize launcher:ofRemainderSpace="1.001" />
- </folderSpec>
- <folderSpec launcher:specType="width" launcher:maxAvailableSize="9999dp">
- <startPadding launcher:fixedSize="16dp" />
- <endPadding launcher:fixedSize="16dp" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:fixedSize="102dp" />
- </folderSpec>
+ <specs launcher:maxAspectRatio="10">
+ <folderSpec launcher:dimensionType="width" launcher:maxAvailableSize="800dp">
+ <startPadding launcher:fixedSize="16dp" />
+ <endPadding launcher:fixedSize="16dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <!-- value bigger than 1 -->
+ <cellSize launcher:ofRemainderSpace="1.001" />
+ </folderSpec>
+ <folderSpec launcher:dimensionType="width" launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="16dp" />
+ <endPadding launcher:fixedSize="16dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:fixedSize="102dp" />
+ </folderSpec>
- <!-- Height spec is fixed -->
- <folderSpec launcher:specType="height" launcher:maxAvailableSize="9999dp">
- <startPadding launcher:fixedSize="24dp" />
- <!-- mapped to footer height size -->
- <endPadding launcher:fixedSize="64dp" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:fixedSize="104dp" />
- </folderSpec>
+ <!-- Height spec is fixed -->
+ <folderSpec launcher:dimensionType="height" launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="24dp" />
+ <!-- mapped to footer height size -->
+ <endPadding launcher:fixedSize="64dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:fixedSize="104dp" />
+ </folderSpec>
+ </specs>
</folderSpecs>
diff --git a/tests/res/xml/invalid_folders_specs_4.xml b/tests/res/xml/invalid_folders_specs_4.xml
index 2d8c730..24b8ef6 100644
--- a/tests/res/xml/invalid_folders_specs_4.xml
+++ b/tests/res/xml/invalid_folders_specs_4.xml
@@ -15,10 +15,12 @@
-->
<!-- missing height spec -->
<folderSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
- <folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
- <startPadding launcher:fixedSize="16dp" />
- <endPadding launcher:fixedSize="16dp" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:matchWorkspace="true" />
- </folderSpec>
+ <specs launcher:maxAspectRatio="10">
+ <folderSpec launcher:dimensionType="width" launcher:maxAvailableSize="800dp">
+ <startPadding launcher:fixedSize="16dp" />
+ <endPadding launcher:fixedSize="16dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:matchWorkspace="true" />
+ </folderSpec>
+ </specs>
</folderSpecs>
diff --git a/tests/res/xml/invalid_folders_specs_5.xml b/tests/res/xml/invalid_folders_specs_5.xml
index b4f1f4d..6d6f577 100644
--- a/tests/res/xml/invalid_folders_specs_5.xml
+++ b/tests/res/xml/invalid_folders_specs_5.xml
@@ -15,19 +15,21 @@
-->
<!-- missing breakpoints > 800dp -->
<folderSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
- <folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
- <startPadding launcher:fixedSize="16dp" />
- <endPadding launcher:fixedSize="16dp" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:matchWorkspace="true" />
- </folderSpec>
+ <specs launcher:maxAspectRatio="10">
+ <folderSpec launcher:dimensionType="width" launcher:maxAvailableSize="800dp">
+ <startPadding launcher:fixedSize="16dp" />
+ <endPadding launcher:fixedSize="16dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:matchWorkspace="true" />
+ </folderSpec>
- <!-- Height spec is fixed -->
- <folderSpec launcher:specType="height" launcher:maxAvailableSize="800dp">
- <startPadding launcher:fixedSize="24dp" />
- <!-- mapped to footer height size -->
- <endPadding launcher:fixedSize="64dp" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:fixedSize="104dp" />
- </folderSpec>
+ <!-- Height spec is fixed -->
+ <folderSpec launcher:dimensionType="height" launcher:maxAvailableSize="800dp">
+ <startPadding launcher:fixedSize="24dp" />
+ <!-- mapped to footer height size -->
+ <endPadding launcher:fixedSize="64dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:fixedSize="104dp" />
+ </folderSpec>
+ </specs>
</folderSpecs>
diff --git a/tests/res/xml/invalid_hotseat_file_case_1.xml b/tests/res/xml/invalid_hotseat_file_case_1.xml
index aaaf8bb..8e0ce2c 100644
--- a/tests/res/xml/invalid_hotseat_file_case_1.xml
+++ b/tests/res/xml/invalid_hotseat_file_case_1.xml
@@ -14,19 +14,19 @@
~ limitations under the License.
-->
<hotseatSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+ <specs launcher:maxAspectRatio="10">
+ <hotseatSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="847dp">
+ <hotseatQsbSpace launcher:ofAvailableSpace="1" />
+ <edgePadding launcher:fixedSize="36dp" />
+ </hotseatSpec>
- <hotseatSpec
- launcher:specType="height"
- launcher:maxAvailableSize="847dp">
- <hotseatQsbSpace launcher:ofAvailableSpace="1" />
- <edgePadding launcher:fixedSize="36dp" />
- </hotseatSpec>
-
- <hotseatSpec
- launcher:specType="height"
- launcher:maxAvailableSize="9999dp">
- <hotseatQsbSpace launcher:fixedSize="36dp" />
- <edgePadding launcher:fixedSize="36dp" />
- </hotseatSpec>
-
+ <hotseatSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="9999dp">
+ <hotseatQsbSpace launcher:fixedSize="36dp" />
+ <edgePadding launcher:fixedSize="36dp" />
+ </hotseatSpec>
+ </specs>
</hotseatSpecs>
\ No newline at end of file
diff --git a/tests/res/xml/invalid_responsive_spec_1.xml b/tests/res/xml/invalid_responsive_spec_1.xml
new file mode 100644
index 0000000..d1bcf65
--- /dev/null
+++ b/tests/res/xml/invalid_responsive_spec_1.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<!-- invalid file - missing groups (specs) with aspect ratio -->
+<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+ <workspaceSpec
+ launcher:maxAvailableSize="9999dp"
+ launcher:dimensionType="height">
+ <cellSize launcher:fixedSize="104dp" />
+ <endPadding launcher:ofRemainderSpace="1" />
+ <gutter launcher:fixedSize="16dp" />
+ <startPadding launcher:fixedSize="8dp" />
+ </workspaceSpec>
+
+ <workspaceSpec
+ launcher:maxAvailableSize="9999dp"
+ launcher:dimensionType="width">
+ <cellSize launcher:ofRemainderSpace="0.25" />
+ <endPadding launcher:fixedSize="22dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <startPadding launcher:fixedSize="22dp" />
+ </workspaceSpec>
+</workspaceSpecs>
diff --git a/tests/res/xml/invalid_responsive_spec_2.xml b/tests/res/xml/invalid_responsive_spec_2.xml
new file mode 100644
index 0000000..49e1f93
--- /dev/null
+++ b/tests/res/xml/invalid_responsive_spec_2.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<!-- invalid file - groups (specs) applied only for half of the specs -->
+<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+ <specs launcher:maxAspectRatio="10">
+ <workspaceSpec
+ launcher:maxAvailableSize="9999dp"
+ launcher:dimensionType="height">
+ <cellSize launcher:fixedSize="104dp" />
+ <endPadding launcher:ofRemainderSpace="1" />
+ <gutter launcher:fixedSize="16dp" />
+ <startPadding launcher:fixedSize="8dp" />
+ </workspaceSpec>
+
+ <workspaceSpec
+ launcher:maxAvailableSize="9999dp"
+ launcher:dimensionType="width">
+ <cellSize launcher:ofRemainderSpace="0.25" />
+ <endPadding launcher:fixedSize="22dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <startPadding launcher:fixedSize="22dp" />
+ </workspaceSpec>
+ </specs>
+
+ <workspaceSpec
+ launcher:maxAvailableSize="9999dp"
+ launcher:dimensionType="width">
+ <cellSize launcher:ofRemainderSpace="0.25" />
+ <endPadding launcher:fixedSize="22dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <startPadding launcher:fixedSize="22dp" />
+ </workspaceSpec>
+ <workspaceSpec
+ launcher:maxAvailableSize="9999dp"
+ launcher:dimensionType="height">
+ <cellSize launcher:fixedSize="104dp" />
+ <endPadding launcher:ofRemainderSpace="1" />
+ <gutter launcher:fixedSize="16dp" />
+ <startPadding launcher:fixedSize="8dp" />
+ </workspaceSpec>
+</workspaceSpecs>
diff --git a/tests/res/xml/invalid_responsive_spec_3.xml b/tests/res/xml/invalid_responsive_spec_3.xml
new file mode 100644
index 0000000..37fee06
--- /dev/null
+++ b/tests/res/xml/invalid_responsive_spec_3.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<!-- invalid file - aspect ratio = 0 (it must be bigger than zero) -->
+<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+ <specs launcher:maxAspectRatio="10">
+ <workspaceSpec
+ launcher:maxAvailableSize="9999dp"
+ launcher:dimensionType="height">
+ <cellSize launcher:fixedSize="104dp" />
+ <endPadding launcher:ofRemainderSpace="1" />
+ <gutter launcher:fixedSize="16dp" />
+ <startPadding launcher:fixedSize="8dp" />
+ </workspaceSpec>
+
+ <workspaceSpec
+ launcher:maxAvailableSize="9999dp"
+ launcher:dimensionType="width">
+ <cellSize launcher:ofRemainderSpace="0.25" />
+ <endPadding launcher:fixedSize="22dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <startPadding launcher:fixedSize="22dp" />
+ </workspaceSpec>
+ </specs>
+
+ <specs launcher:maxAspectRatio="0">
+ <workspaceSpec
+ launcher:maxAvailableSize="9999dp"
+ launcher:dimensionType="height">
+ <cellSize launcher:fixedSize="104dp" />
+ <endPadding launcher:ofRemainderSpace="1" />
+ <gutter launcher:fixedSize="16dp" />
+ <startPadding launcher:fixedSize="8dp" />
+ </workspaceSpec>
+
+ <workspaceSpec
+ launcher:maxAvailableSize="9999dp"
+ launcher:dimensionType="width">
+ <cellSize launcher:ofRemainderSpace="0.25" />
+ <endPadding launcher:fixedSize="22dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <startPadding launcher:fixedSize="22dp" />
+ </workspaceSpec>
+ </specs>
+
+</workspaceSpecs>
diff --git a/tests/res/xml/invalid_workspace_file_case_1.xml b/tests/res/xml/invalid_workspace_file_case_1.xml
index 0be704b..7a234d1 100644
--- a/tests/res/xml/invalid_workspace_file_case_1.xml
+++ b/tests/res/xml/invalid_workspace_file_case_1.xml
@@ -15,42 +15,44 @@
-->
<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
- <workspaceSpec
- launcher:specType="height"
- launcher:maxAvailableSize="648dp">
- <!-- missing startPadding -->
- <endPadding
- launcher:ofAvailableSpace="0.05" />
- <gutter
- launcher:fixedSize="16dp" />
- <cellSize
- launcher:ofRemainderSpace="0.2" />
- </workspaceSpec>
+ <specs launcher:maxAspectRatio="10">
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="648dp">
+ <!-- missing startPadding -->
+ <endPadding
+ launcher:ofAvailableSpace="0.05" />
+ <gutter
+ launcher:fixedSize="16dp" />
+ <cellSize
+ launcher:ofRemainderSpace="0.2" />
+ </workspaceSpec>
- <workspaceSpec
- launcher:specType="height"
- launcher:maxAvailableSize="9999dp">
- <startPadding
- launcher:ofAvailableSpace="0.0306" />
- <endPadding
- launcher:ofAvailableSpace="0.068" />
- <gutter
- launcher:fixedSize="16dp" />
- <cellSize
- launcher:ofRemainderSpace="0.2" />
- </workspaceSpec>
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding
+ launcher:ofAvailableSpace="0.0306" />
+ <endPadding
+ launcher:ofAvailableSpace="0.068" />
+ <gutter
+ launcher:fixedSize="16dp" />
+ <cellSize
+ launcher:ofRemainderSpace="0.2" />
+ </workspaceSpec>
- <!-- Width spec is always the same -->
- <workspaceSpec
- launcher:specType="width"
- launcher:maxAvailableSize="9999dp">
- <startPadding
- launcher:ofRemainderSpace="0.21436227" />
- <endPadding
- launcher:ofRemainderSpace="0.21436227" />
- <gutter
- launcher:ofRemainderSpace="0.11425509" />
- <cellSize
- launcher:fixedSize="120dp" />
- </workspaceSpec>
+ <!-- Width spec is always the same -->
+ <workspaceSpec
+ launcher:dimensionType="width"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding
+ launcher:ofRemainderSpace="0.21436227" />
+ <endPadding
+ launcher:ofRemainderSpace="0.21436227" />
+ <gutter
+ launcher:ofRemainderSpace="0.11425509" />
+ <cellSize
+ launcher:fixedSize="120dp" />
+ </workspaceSpec>
+ </specs>
</workspaceSpecs>
diff --git a/tests/res/xml/invalid_workspace_file_case_2.xml b/tests/res/xml/invalid_workspace_file_case_2.xml
index 5a37d97..6638285 100644
--- a/tests/res/xml/invalid_workspace_file_case_2.xml
+++ b/tests/res/xml/invalid_workspace_file_case_2.xml
@@ -15,45 +15,47 @@
-->
<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
- <workspaceSpec
- launcher:specType="height"
- launcher:maxAvailableSize="648dp">
- <startPadding
- launcher:ofAvailableSpace="0.0125" />
- <endPadding
- launcher:ofAvailableSpace="0.05" />
- <!-- more than 1 value in one tag -->
- <gutter
- launcher:ofAvailableSpace="0.0125"
- launcher:fixedSize="16dp" />
- <cellSize
- launcher:ofRemainderSpace="0.2" />
- </workspaceSpec>
+ <specs launcher:maxAspectRatio="10">
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="648dp">
+ <startPadding
+ launcher:ofAvailableSpace="0.0125" />
+ <endPadding
+ launcher:ofAvailableSpace="0.05" />
+ <!-- more than 1 value in one tag -->
+ <gutter
+ launcher:ofAvailableSpace="0.0125"
+ launcher:fixedSize="16dp" />
+ <cellSize
+ launcher:ofRemainderSpace="0.2" />
+ </workspaceSpec>
- <workspaceSpec
- launcher:specType="height"
- launcher:maxAvailableSize="9999dp">
- <startPadding
- launcher:ofAvailableSpace="0.0306" />
- <endPadding
- launcher:ofAvailableSpace="0.068" />
- <gutter
- launcher:fixedSize="16dp" />
- <cellSize
- launcher:ofRemainderSpace="0.2" />
- </workspaceSpec>
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding
+ launcher:ofAvailableSpace="0.0306" />
+ <endPadding
+ launcher:ofAvailableSpace="0.068" />
+ <gutter
+ launcher:fixedSize="16dp" />
+ <cellSize
+ launcher:ofRemainderSpace="0.2" />
+ </workspaceSpec>
- <!-- Width spec is always the same -->
- <workspaceSpec
- launcher:specType="width"
- launcher:maxAvailableSize="9999dp">
- <startPadding
- launcher:ofRemainderSpace="0.21436227" />
- <endPadding
- launcher:ofRemainderSpace="0.21436227" />
- <gutter
- launcher:ofRemainderSpace="0.11425509" />
- <cellSize
- launcher:fixedSize="120dp" />
- </workspaceSpec>
+ <!-- Width spec is always the same -->
+ <workspaceSpec
+ launcher:dimensionType="width"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding
+ launcher:ofRemainderSpace="0.21436227" />
+ <endPadding
+ launcher:ofRemainderSpace="0.21436227" />
+ <gutter
+ launcher:ofRemainderSpace="0.11425509" />
+ <cellSize
+ launcher:fixedSize="120dp" />
+ </workspaceSpec>
+ </specs>
</workspaceSpecs>
diff --git a/tests/res/xml/invalid_workspace_file_case_3.xml b/tests/res/xml/invalid_workspace_file_case_3.xml
index 3e68edb..cb3e63f 100644
--- a/tests/res/xml/invalid_workspace_file_case_3.xml
+++ b/tests/res/xml/invalid_workspace_file_case_3.xml
@@ -15,44 +15,46 @@
-->
<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
- <workspaceSpec
- launcher:specType="height"
- launcher:maxAvailableSize="648dp">
- <startPadding
- launcher:ofAvailableSpace="0.0125" />
- <endPadding
- launcher:ofAvailableSpace="0.05" />
- <gutter
- launcher:fixedSize="16dp" />
- <!-- value bigger than 1 -->
- <cellSize
- launcher:ofRemainderSpace="1.001" />
- </workspaceSpec>
+ <specs launcher:maxAspectRatio="10">
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="648dp">
+ <startPadding
+ launcher:ofAvailableSpace="0.0125" />
+ <endPadding
+ launcher:ofAvailableSpace="0.05" />
+ <gutter
+ launcher:fixedSize="16dp" />
+ <!-- value bigger than 1 -->
+ <cellSize
+ launcher:ofRemainderSpace="1.001" />
+ </workspaceSpec>
- <workspaceSpec
- launcher:specType="height"
- launcher:maxAvailableSize="9999dp">
- <startPadding
- launcher:ofAvailableSpace="0.0306" />
- <endPadding
- launcher:ofAvailableSpace="0.068" />
- <gutter
- launcher:fixedSize="16dp" />
- <cellSize
- launcher:ofRemainderSpace="0.2" />
- </workspaceSpec>
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding
+ launcher:ofAvailableSpace="0.0306" />
+ <endPadding
+ launcher:ofAvailableSpace="0.068" />
+ <gutter
+ launcher:fixedSize="16dp" />
+ <cellSize
+ launcher:ofRemainderSpace="0.2" />
+ </workspaceSpec>
- <!-- Width spec is always the same -->
- <workspaceSpec
- launcher:specType="width"
- launcher:maxAvailableSize="9999dp">
- <startPadding
- launcher:ofRemainderSpace="0.21436227" />
- <endPadding
- launcher:ofRemainderSpace="0.21436227" />
- <gutter
- launcher:ofRemainderSpace="0.11425509" />
- <cellSize
- launcher:fixedSize="120dp" />
- </workspaceSpec>
+ <!-- Width spec is always the same -->
+ <workspaceSpec
+ launcher:dimensionType="width"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding
+ launcher:ofRemainderSpace="0.21436227" />
+ <endPadding
+ launcher:ofRemainderSpace="0.21436227" />
+ <gutter
+ launcher:ofRemainderSpace="0.11425509" />
+ <cellSize
+ launcher:fixedSize="120dp" />
+ </workspaceSpec>
+ </specs>
</workspaceSpecs>
diff --git a/tests/res/xml/invalid_workspace_file_case_4.xml b/tests/res/xml/invalid_workspace_file_case_4.xml
index 9e74c85..901278d 100644
--- a/tests/res/xml/invalid_workspace_file_case_4.xml
+++ b/tests/res/xml/invalid_workspace_file_case_4.xml
@@ -15,44 +15,46 @@
-->
<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
- <workspaceSpec
- launcher:specType="height"
- launcher:maxAvailableSize="648dp">
- <startPadding
- launcher:ofAvailableSpace="0.0125" />
- <endPadding
- launcher:ofAvailableSpace="0.05" />
- <!-- value in workspace spec using matchWorkspace -->
- <gutter
- launcher:matchWorkspace="true" />
- <cellSize
- launcher:ofRemainderSpace="0.2" />
- </workspaceSpec>
+ <specs launcher:maxAspectRatio="10">
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="648dp">
+ <startPadding
+ launcher:ofAvailableSpace="0.0125" />
+ <endPadding
+ launcher:ofAvailableSpace="0.05" />
+ <!-- value in workspace spec using matchWorkspace -->
+ <gutter
+ launcher:matchWorkspace="true" />
+ <cellSize
+ launcher:ofRemainderSpace="0.2" />
+ </workspaceSpec>
- <workspaceSpec
- launcher:specType="height"
- launcher:maxAvailableSize="9999dp">
- <startPadding
- launcher:ofAvailableSpace="0.0306" />
- <endPadding
- launcher:ofAvailableSpace="0.068" />
- <gutter
- launcher:fixedSize="16dp" />
- <cellSize
- launcher:ofRemainderSpace="0.2" />
- </workspaceSpec>
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding
+ launcher:ofAvailableSpace="0.0306" />
+ <endPadding
+ launcher:ofAvailableSpace="0.068" />
+ <gutter
+ launcher:fixedSize="16dp" />
+ <cellSize
+ launcher:ofRemainderSpace="0.2" />
+ </workspaceSpec>
- <!-- Width spec is always the same -->
- <workspaceSpec
- launcher:specType="width"
- launcher:maxAvailableSize="9999dp">
- <startPadding
- launcher:ofRemainderSpace="0.21436227" />
- <endPadding
- launcher:ofRemainderSpace="0.21436227" />
- <gutter
- launcher:ofRemainderSpace="0.11425509" />
- <cellSize
- launcher:fixedSize="120dp" />
- </workspaceSpec>
+ <!-- Width spec is always the same -->
+ <workspaceSpec
+ launcher:dimensionType="width"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding
+ launcher:ofRemainderSpace="0.21436227" />
+ <endPadding
+ launcher:ofRemainderSpace="0.21436227" />
+ <gutter
+ launcher:ofRemainderSpace="0.11425509" />
+ <cellSize
+ launcher:fixedSize="120dp" />
+ </workspaceSpec>
+ </specs>
</workspaceSpecs>
diff --git a/tests/res/xml/valid_all_apps_file.xml b/tests/res/xml/valid_all_apps_file.xml
index 0be55d1..33ea9b6 100644
--- a/tests/res/xml/valid_all_apps_file.xml
+++ b/tests/res/xml/valid_all_apps_file.xml
@@ -15,22 +15,23 @@
-->
<allAppsSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
- <allAppsSpec
- launcher:specType="height"
- launcher:maxAvailableSize="9999dp">
- <startPadding launcher:fixedSize="0dp" />
- <endPadding launcher:fixedSize="0dp" />
- <gutter launcher:matchWorkspace="true" />
- <cellSize launcher:matchWorkspace="true" />
- </allAppsSpec>
+ <specs launcher:maxAspectRatio="10">
+ <allAppsSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="0dp" />
+ <endPadding launcher:fixedSize="0dp" />
+ <gutter launcher:matchWorkspace="true" />
+ <cellSize launcher:matchWorkspace="true" />
+ </allAppsSpec>
- <allAppsSpec
- launcher:specType="width"
- launcher:maxAvailableSize="9999dp">
- <startPadding launcher:matchWorkspace="true" />
- <endPadding launcher:matchWorkspace="true" />
- <gutter launcher:matchWorkspace="true" />
- <cellSize launcher:matchWorkspace="true" />
- </allAppsSpec>
-
+ <allAppsSpec
+ launcher:dimensionType="width"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:matchWorkspace="true" />
+ <endPadding launcher:matchWorkspace="true" />
+ <gutter launcher:matchWorkspace="true" />
+ <cellSize launcher:matchWorkspace="true" />
+ </allAppsSpec>
+ </specs>
</allAppsSpecs>
diff --git a/tests/res/xml/valid_folders_specs.xml b/tests/res/xml/valid_folders_specs.xml
index 0c45544..ecff9b8 100644
--- a/tests/res/xml/valid_folders_specs.xml
+++ b/tests/res/xml/valid_folders_specs.xml
@@ -14,25 +14,27 @@
~ limitations under the License.
-->
<folderSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
- <folderSpec launcher:specType="width" launcher:maxAvailableSize="800dp">
- <startPadding launcher:fixedSize="16dp" />
- <endPadding launcher:fixedSize="16dp" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:matchWorkspace="true" />
- </folderSpec>
- <folderSpec launcher:specType="width" launcher:maxAvailableSize="9999dp">
- <startPadding launcher:fixedSize="16dp" />
- <endPadding launcher:fixedSize="16dp" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:fixedSize="102dp" />
- </folderSpec>
+ <specs launcher:maxAspectRatio="10">
+ <folderSpec launcher:dimensionType="width" launcher:maxAvailableSize="800dp">
+ <startPadding launcher:fixedSize="16dp" />
+ <endPadding launcher:fixedSize="16dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:matchWorkspace="true" />
+ </folderSpec>
+ <folderSpec launcher:dimensionType="width" launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="16dp" />
+ <endPadding launcher:fixedSize="16dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:fixedSize="102dp" />
+ </folderSpec>
- <!-- Height spec is fixed -->
- <folderSpec launcher:specType="height" launcher:maxAvailableSize="9999dp">
- <startPadding launcher:fixedSize="24dp" />
- <!-- mapped to footer height size -->
- <endPadding launcher:fixedSize="64dp" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:matchWorkspace="true" />
- </folderSpec>
+ <!-- Height spec is fixed -->
+ <folderSpec launcher:dimensionType="height" launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="24dp" />
+ <!-- mapped to footer height size -->
+ <endPadding launcher:fixedSize="64dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:matchWorkspace="true" />
+ </folderSpec>
+ </specs>
</folderSpecs>
diff --git a/tests/res/xml/valid_hotseat_file.xml b/tests/res/xml/valid_hotseat_file.xml
index f698bd1..65c1d8b 100644
--- a/tests/res/xml/valid_hotseat_file.xml
+++ b/tests/res/xml/valid_hotseat_file.xml
@@ -14,19 +14,19 @@
~ limitations under the License.
-->
<hotseatSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+ <specs launcher:maxAspectRatio="10">
+ <hotseatSpec
+ launcher:maxAvailableSize="847dp"
+ launcher:dimensionType="height">
+ <hotseatQsbSpace launcher:fixedSize="24dp" />
+ <edgePadding launcher:fixedSize="48dp" />
+ </hotseatSpec>
- <hotseatSpec
- launcher:maxAvailableSize="847dp"
- launcher:specType="height">
- <hotseatQsbSpace launcher:fixedSize="24dp" />
- <edgePadding launcher:fixedSize="48dp" />
- </hotseatSpec>
-
- <hotseatSpec
- launcher:maxAvailableSize="9999dp"
- launcher:specType="height">
- <hotseatQsbSpace launcher:fixedSize="36dp" />
- <edgePadding launcher:fixedSize="48dp" />
- </hotseatSpec>
-
+ <hotseatSpec
+ launcher:maxAvailableSize="9999dp"
+ launcher:dimensionType="height">
+ <hotseatQsbSpace launcher:fixedSize="36dp" />
+ <edgePadding launcher:fixedSize="48dp" />
+ </hotseatSpec>
+ </specs>
</hotseatSpecs>
\ No newline at end of file
diff --git a/tests/res/xml/valid_hotseat_land_file.xml b/tests/res/xml/valid_hotseat_land_file.xml
index fc4a836..f67adad 100644
--- a/tests/res/xml/valid_hotseat_land_file.xml
+++ b/tests/res/xml/valid_hotseat_land_file.xml
@@ -14,19 +14,19 @@
~ limitations under the License.
-->
<hotseatSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+ <specs launcher:maxAspectRatio="10">
+ <hotseatSpec
+ launcher:maxAvailableSize="743dp"
+ launcher:dimensionType="width">
+ <hotseatQsbSpace launcher:fixedSize="0dp" />
+ <edgePadding launcher:fixedSize="48dp" />
+ </hotseatSpec>
- <hotseatSpec
- launcher:maxAvailableSize="743dp"
- launcher:specType="width">
- <hotseatQsbSpace launcher:fixedSize="0dp" />
- <edgePadding launcher:fixedSize="48dp" />
- </hotseatSpec>
-
- <hotseatSpec
- launcher:maxAvailableSize="9999dp"
- launcher:specType="width">
- <hotseatQsbSpace launcher:fixedSize="0dp" />
- <edgePadding launcher:fixedSize="64dp" />
- </hotseatSpec>
-
+ <hotseatSpec
+ launcher:maxAvailableSize="9999dp"
+ launcher:dimensionType="width">
+ <hotseatQsbSpace launcher:fixedSize="0dp" />
+ <edgePadding launcher:fixedSize="64dp" />
+ </hotseatSpec>
+ </specs>
</hotseatSpecs>
\ No newline at end of file
diff --git a/tests/res/xml/valid_responsive_spec_unsorted.xml b/tests/res/xml/valid_responsive_spec_unsorted.xml
new file mode 100644
index 0000000..9a463d5
--- /dev/null
+++ b/tests/res/xml/valid_responsive_spec_unsorted.xml
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+ <specs launcher:maxAspectRatio="10">
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="0dp" />
+ <endPadding launcher:fixedSize="34dp" />
+ <gutter launcher:fixedSize="12dp" />
+ <cellSize launcher:ofRemainderSpace="0.25" />
+ </workspaceSpec>
+
+ <!-- Height spec -->
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="371dp">
+ <startPadding launcher:fixedSize="0dp" />
+ <endPadding launcher:fixedSize="24dp" />
+ <gutter launcher:fixedSize="12dp" />
+ <cellSize launcher:ofRemainderSpace="0.25" />
+ </workspaceSpec>
+
+ <!-- Width spec -->
+ <workspaceSpec
+ launcher:dimensionType="width"
+ launcher:maxAvailableSize="716dp">
+ <startPadding launcher:fixedSize="16dp" />
+ <endPadding launcher:fixedSize="64dp" />
+ <gutter launcher:fixedSize="12dp" />
+ <cellSize launcher:ofRemainderSpace="0.25" />
+ </workspaceSpec>
+ <workspaceSpec
+ launcher:dimensionType="width"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="36dp" />
+ <endPadding launcher:fixedSize="80dp" />
+ <gutter launcher:fixedSize="12dp" />
+ <cellSize launcher:ofRemainderSpace="0.25" />
+ </workspaceSpec>
+ <workspaceSpec
+ launcher:dimensionType="width"
+ launcher:maxAvailableSize="602dp">
+ <startPadding launcher:fixedSize="0dp" />
+ <endPadding launcher:fixedSize="36dp" />
+ <gutter launcher:fixedSize="12dp" />
+ <cellSize launcher:ofRemainderSpace="0.25" />
+ </workspaceSpec>
+ </specs>
+
+ <!-- specs from land/handheld_workspace_spec_4x4.xml -->
+ <specs launcher:maxAspectRatio="12">
+ <!-- Height spec -->
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="2dp" />
+ <endPadding launcher:fixedSize="2dp" />
+ <gutter launcher:fixedSize="8dp" />
+ <cellSize launcher:ofRemainderSpace="0.25" />
+ </workspaceSpec>
+
+ <!-- Width spec -->
+ <workspaceSpec
+ launcher:dimensionType="width"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="1dp" />
+ <endPadding launcher:fixedSize="1dp" />
+ <gutter launcher:fixedSize="8dp" />
+ <cellSize launcher:ofRemainderSpace="0.25" />
+ </workspaceSpec>
+ </specs>
+
+ <specs launcher:maxAspectRatio="1.05">
+ <!-- 584 grid height + 28 remainder space -->
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="612dp">
+ <startPadding launcher:fixedSize="0dp" />
+ <endPadding launcher:ofRemainderSpace="1" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:fixedSize="104dp" />
+ </workspaceSpec>
+
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="8dp" />
+ <endPadding launcher:ofRemainderSpace="1" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:fixedSize="104dp" />
+ </workspaceSpec>
+
+ <!-- 584 grid height -->
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="584dp">
+ <startPadding launcher:fixedSize="0dp" />
+ <endPadding launcher:fixedSize="32dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:ofAvailableSpace="0.15808" />
+ </workspaceSpec>
+
+ <!-- Width spec is always the same -->
+ <workspaceSpec
+ launcher:dimensionType="width"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="22dp" />
+ <endPadding launcher:fixedSize="22dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:ofRemainderSpace="0.25" />
+ </workspaceSpec>
+ </specs>
+</workspaceSpecs>
diff --git a/tests/res/xml/valid_workspace_file.xml b/tests/res/xml/valid_workspace_file.xml
index 1f97314..9c44502 100644
--- a/tests/res/xml/valid_workspace_file.xml
+++ b/tests/res/xml/valid_workspace_file.xml
@@ -15,45 +15,93 @@
-->
<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
- <!-- 584 grid height -->
- <workspaceSpec
- launcher:specType="height"
- launcher:maxAvailableSize="584dp">
- <startPadding launcher:fixedSize="0dp" />
- <endPadding launcher:fixedSize="32dp" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:ofAvailableSpace="0.15808" />
- </workspaceSpec>
+ <specs launcher:maxAspectRatio="1.05">
+ <!-- 584 grid height -->
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="584dp">
+ <startPadding launcher:fixedSize="0dp" />
+ <endPadding launcher:fixedSize="32dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:ofAvailableSpace="0.15808" />
+ </workspaceSpec>
- <!-- 584 grid height + 28 remainder space -->
- <workspaceSpec
- launcher:specType="height"
- launcher:maxAvailableSize="612dp">
- <startPadding launcher:fixedSize="0dp" />
- <endPadding launcher:ofRemainderSpace="1" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:fixedSize="104dp" />
- </workspaceSpec>
+ <!-- 584 grid height + 28 remainder space -->
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="612dp">
+ <startPadding launcher:fixedSize="0dp" />
+ <endPadding launcher:ofRemainderSpace="1" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:fixedSize="104dp" />
+ </workspaceSpec>
- <workspaceSpec
- launcher:specType="height"
- launcher:maxAvailableSize="9999dp">
- <startPadding launcher:fixedSize="8dp" />
- <endPadding launcher:ofRemainderSpace="1" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:fixedSize="104dp" />
- </workspaceSpec>
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="8dp" />
+ <endPadding launcher:ofRemainderSpace="1" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:fixedSize="104dp" />
+ </workspaceSpec>
- <!-- TODO(b/241386436): other specs here for height ... -->
+ <!-- TODO(b/241386436): other specs here for height ... -->
- <!-- Width spec is always the same -->
- <workspaceSpec
- launcher:specType="width"
- launcher:maxAvailableSize="9999dp">
- <startPadding launcher:fixedSize="22dp" />
- <endPadding launcher:fixedSize="22dp" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:ofRemainderSpace="0.25" />
- </workspaceSpec>
+ <!-- Width spec is always the same -->
+ <workspaceSpec
+ launcher:dimensionType="width"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="22dp" />
+ <endPadding launcher:fixedSize="22dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:ofRemainderSpace="0.25" />
+ </workspaceSpec>
+ </specs>
+ <!-- specs from land/handheld_workspace_spec_4x4.xml -->
+ <specs launcher:maxAspectRatio="99999">
+ <!-- Height spec -->
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="371dp">
+ <startPadding launcher:fixedSize="0dp" />
+ <endPadding launcher:fixedSize="24dp" />
+ <gutter launcher:fixedSize="12dp" />
+ <cellSize launcher:ofRemainderSpace="0.25" />
+ </workspaceSpec>
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="0dp" />
+ <endPadding launcher:fixedSize="34dp" />
+ <gutter launcher:fixedSize="12dp" />
+ <cellSize launcher:ofRemainderSpace="0.25" />
+ </workspaceSpec>
+
+ <!-- Width spec -->
+ <workspaceSpec
+ launcher:dimensionType="width"
+ launcher:maxAvailableSize="602dp">
+ <startPadding launcher:fixedSize="0dp" />
+ <endPadding launcher:fixedSize="36dp" />
+ <gutter launcher:fixedSize="12dp" />
+ <cellSize launcher:ofRemainderSpace="0.25" />
+ </workspaceSpec>
+ <workspaceSpec
+ launcher:dimensionType="width"
+ launcher:maxAvailableSize="716dp">
+ <startPadding launcher:fixedSize="16dp" />
+ <endPadding launcher:fixedSize="64dp" />
+ <gutter launcher:fixedSize="12dp" />
+ <cellSize launcher:ofRemainderSpace="0.25" />
+ </workspaceSpec>
+ <workspaceSpec
+ launcher:dimensionType="width"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="36dp" />
+ <endPadding launcher:fixedSize="80dp" />
+ <gutter launcher:fixedSize="12dp" />
+ <cellSize launcher:ofRemainderSpace="0.25" />
+ </workspaceSpec>
+ </specs>
</workspaceSpecs>
diff --git a/tests/res/xml/valid_workspace_unsorted_file.xml b/tests/res/xml/valid_workspace_unsorted_file.xml
index 1216c81..6bf7c78 100644
--- a/tests/res/xml/valid_workspace_unsorted_file.xml
+++ b/tests/res/xml/valid_workspace_unsorted_file.xml
@@ -15,44 +15,44 @@
-->
<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
+ <specs launcher:maxAspectRatio="1.05">
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="8dp" />
+ <endPadding launcher:ofRemainderSpace="1" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:fixedSize="104dp" />
+ </workspaceSpec>
- <workspaceSpec
- launcher:specType="height"
- launcher:maxAvailableSize="9999dp">
- <startPadding launcher:fixedSize="8dp" />
- <endPadding launcher:ofRemainderSpace="1" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:fixedSize="104dp" />
- </workspaceSpec>
+ <!-- 584 grid height -->
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="584dp">
+ <startPadding launcher:fixedSize="0dp" />
+ <endPadding launcher:fixedSize="32dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:ofAvailableSpace="0.15808" />
+ </workspaceSpec>
- <!-- 584 grid height -->
- <workspaceSpec
- launcher:specType="height"
- launcher:maxAvailableSize="584dp">
- <startPadding launcher:fixedSize="0dp" />
- <endPadding launcher:fixedSize="32dp" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:ofAvailableSpace="0.15808" />
- </workspaceSpec>
+ <!-- 584 grid height + 28 remainder space -->
+ <workspaceSpec
+ launcher:dimensionType="height"
+ launcher:maxAvailableSize="612dp">
+ <startPadding launcher:fixedSize="0dp" />
+ <endPadding launcher:ofRemainderSpace="1" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:fixedSize="104dp" />
+ </workspaceSpec>
- <!-- 584 grid height + 28 remainder space -->
- <workspaceSpec
- launcher:specType="height"
- launcher:maxAvailableSize="612dp">
- <startPadding launcher:fixedSize="0dp" />
- <endPadding launcher:ofRemainderSpace="1" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:fixedSize="104dp" />
- </workspaceSpec>
-
- <!-- Width spec is always the same -->
- <workspaceSpec
- launcher:specType="width"
- launcher:maxAvailableSize="9999dp">
- <startPadding launcher:fixedSize="22dp" />
- <endPadding launcher:fixedSize="22dp" />
- <gutter launcher:fixedSize="16dp" />
- <cellSize launcher:ofRemainderSpace="0.25" />
- </workspaceSpec>
-
+ <!-- Width spec is always the same -->
+ <workspaceSpec
+ launcher:dimensionType="width"
+ launcher:maxAvailableSize="9999dp">
+ <startPadding launcher:fixedSize="22dp" />
+ <endPadding launcher:fixedSize="22dp" />
+ <gutter launcher:fixedSize="16dp" />
+ <cellSize launcher:ofRemainderSpace="0.25" />
+ </workspaceSpec>
+ </specs>
</workspaceSpecs>
diff --git a/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java b/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java
index 80f73cb..fe9464a 100644
--- a/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java
+++ b/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java
@@ -21,6 +21,8 @@
import static org.junit.Assert.assertTrue;
import android.view.KeyEvent;
+import android.view.View;
+import android.view.WindowInsets;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -76,4 +78,39 @@
allApps.unfreeze();
}
}
+
+ @Test
+ public void testAllAppsExitSearchAndFocusSearchResults() {
+ final HomeAllApps allApps = mLauncher.goHome().switchToAllApps();
+ assertTrue("Launcher internal state is not All Apps",
+ isInState(() -> LauncherState.ALL_APPS));
+ allApps.freeze();
+ try {
+ executeOnLauncher(launcher -> launcher.getAppsView().getSearchView().requestFocus());
+ waitForLauncherCondition("Search view does not have focus.",
+ launcher -> launcher.getAppsView().getSearchView().hasFocus());
+
+ mLauncher.pressAndHoldKeyCode(KeyEvent.KEYCODE_C, 0);
+ waitForLauncherCondition("Search view not active.",
+ launcher -> launcher.getAppsView().getActiveRecyclerView()
+ instanceof SearchRecyclerView);
+ mLauncher.unpressKeyCode(KeyEvent.KEYCODE_C, 0);
+
+ executeOnLauncher(launcher -> launcher.getAppsView().getSearchUiManager().getEditText()
+ .hideKeyboard(/* clearFocus= */ false));
+ waitForLauncherCondition("Keyboard still visible.", launcher -> {
+ View root = launcher.getDragLayer();
+ WindowInsets insets = root.getRootWindowInsets();
+ return insets != null && !insets.isVisible(WindowInsets.Type.ime());
+ });
+
+ mLauncher.pressAndHoldKeyCode(KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ mLauncher.unpressKeyCode(KeyEvent.KEYCODE_DPAD_DOWN, 0);
+ waitForLauncherCondition("No focused child", launcher ->
+ launcher.getAppsView().getActiveRecyclerView().getApps().getFocusedChild()
+ != null);
+ } finally {
+ allApps.unfreeze();
+ }
+ }
}
diff --git a/tests/src/com/android/launcher3/dragging/TaplUninstallRemove.java b/tests/src/com/android/launcher3/dragging/TaplUninstallRemove.java
index 7027e85..a690543 100644
--- a/tests/src/com/android/launcher3/dragging/TaplUninstallRemove.java
+++ b/tests/src/com/android/launcher3/dragging/TaplUninstallRemove.java
@@ -100,8 +100,7 @@
*/
@Test
@PortraitLandscape
- // TODO(b/293944634): Remove Screenrecord after flaky debug, and add
- // @PlatinumTest(focusArea = "launcher") back
+ @PlatinumTest(focusArea = "launcher")
@ScreenRecordRule.ScreenRecord
public void testUninstallFromWorkspace() throws Exception {
installDummyAppAndWaitForUIUpdate();
diff --git a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
index 036f2d8..def27b8 100644
--- a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
@@ -1,10 +1,12 @@
package com.android.launcher3.model
-import android.appwidget.AppWidgetManager
+import android.content.Context
import android.os.UserHandle
+import android.platform.test.flag.junit.SetFlagsRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.Flags
import com.android.launcher3.InvariantDeviceProfile
import com.android.launcher3.LauncherAppState
import com.android.launcher3.LauncherModel
@@ -12,19 +14,25 @@
import com.android.launcher3.icons.IconCache
import com.android.launcher3.icons.cache.CachingLogic
import com.android.launcher3.icons.cache.IconCacheUpdateHandler
+import com.android.launcher3.pm.UserCache
import com.android.launcher3.util.Executors.MODEL_EXECUTOR
import com.android.launcher3.util.LooperIdleLock
+import com.android.launcher3.util.UserIconInfo
+import com.android.launcher3.util.rule.StaticMockitoRule
import com.google.common.truth.Truth
import java.util.concurrent.CountDownLatch
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
import org.mockito.Mock
+import org.mockito.Mockito
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
+import org.mockito.Spy
private const val INSERTION_STATEMENT_FILE = "databases/workspace_items.sql"
@@ -40,7 +48,13 @@
@Mock private lateinit var iconCache: IconCache
@Mock private lateinit var idleLock: LooperIdleLock
@Mock private lateinit var iconCacheUpdateHandler: IconCacheUpdateHandler
- @Mock private lateinit var appWidgetManager: AppWidgetManager
+ @Mock private lateinit var userCache: UserCache
+
+ @Spy private var userManagerState: UserManagerState? = UserManagerState()
+
+ @get:Rule(order = 0) val staticMockitoRule = StaticMockitoRule(UserCache::class.java)
+ @get:Rule(order = 1)
+ val setFlagsRule = SetFlagsRule().apply { initAllFlagsToReleaseConfigDefault() }
@Before
fun setup() {
@@ -63,8 +77,7 @@
`when`(launcherBinder.newIdleLock(any(LoaderTask::class.java))).thenReturn(idleLock)
`when`(idleLock.awaitLocked(1000)).thenReturn(false)
`when`(iconCache.updateHandler).thenReturn(iconCacheUpdateHandler)
- `when`(appWidgetManager.getInstalledProvidersForProfile(any(UserHandle::class.java)))
- .thenReturn(emptyList())
+ `when`(UserCache.getInstance(any(Context::class.java))).thenReturn(userCache)
}
@Test
@@ -95,6 +108,48 @@
verify(modelDelegate).modelLoadComplete()
verify(transaction).commit()
}
+
+ @Test
+ fun setsQuietModeFlagCorrectlyForWorkProfile() =
+ with(BgDataModel()) {
+ setFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE)
+ val MAIN_HANDLE = UserHandle.of(0)
+ val mockUserHandles = arrayListOf<UserHandle>(MAIN_HANDLE)
+ `when`(userCache.userProfiles).thenReturn(mockUserHandles)
+ `when`(userManagerState?.isUserQuiet(MAIN_HANDLE)).thenReturn(true)
+ `when`(userCache.getUserInfo(MAIN_HANDLE)).thenReturn(UserIconInfo(MAIN_HANDLE, 1))
+
+ LoaderTask(app, bgAllAppsList, this, modelDelegate, launcherBinder, userManagerState)
+ .runSyncOnBackgroundThread()
+
+ verify(bgAllAppsList)
+ .setFlags(BgDataModel.Callbacks.FLAG_WORK_PROFILE_QUIET_MODE_ENABLED, true)
+ verify(bgAllAppsList)
+ .setFlags(BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED, false)
+ verify(bgAllAppsList, Mockito.never())
+ .setFlags(BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED, true)
+ }
+
+ @Test
+ fun setsQuietModeFlagCorrectlyForPrivateProfile() =
+ with(BgDataModel()) {
+ setFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE)
+ val MAIN_HANDLE = UserHandle.of(0)
+ val mockUserHandles = arrayListOf<UserHandle>(MAIN_HANDLE)
+ `when`(userCache.userProfiles).thenReturn(mockUserHandles)
+ `when`(userManagerState?.isUserQuiet(MAIN_HANDLE)).thenReturn(true)
+ `when`(userCache.getUserInfo(MAIN_HANDLE)).thenReturn(UserIconInfo(MAIN_HANDLE, 3))
+
+ LoaderTask(app, bgAllAppsList, this, modelDelegate, launcherBinder, userManagerState)
+ .runSyncOnBackgroundThread()
+
+ verify(bgAllAppsList)
+ .setFlags(BgDataModel.Callbacks.FLAG_WORK_PROFILE_QUIET_MODE_ENABLED, false)
+ verify(bgAllAppsList)
+ .setFlags(BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED, true)
+ verify(bgAllAppsList, Mockito.never())
+ .setFlags(BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED, true)
+ }
}
private fun LoaderTask.runSyncOnBackgroundThread() {
diff --git a/tests/src/com/android/launcher3/responsive/AllAppsSpecsTest.kt b/tests/src/com/android/launcher3/responsive/AllAppsSpecsTest.kt
index cd95e99..c99da96 100644
--- a/tests/src/com/android/launcher3/responsive/AllAppsSpecsTest.kt
+++ b/tests/src/com/android/launcher3/responsive/AllAppsSpecsTest.kt
@@ -21,6 +21,7 @@
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
import com.android.launcher3.tests.R as TestR
import com.android.launcher3.util.TestResourceHelper
import com.google.common.truth.Truth.assertThat
@@ -32,22 +33,30 @@
@RunWith(AndroidJUnit4::class)
class AllAppsSpecsTest : AbstractDeviceProfileTest() {
override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
+ val deviceSpec = deviceSpecs["phone"]!!
+ val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
@Before
fun setup() {
- initializeVarsForPhone(deviceSpecs["phone"]!!)
+ initializeVarsForPhone(deviceSpec)
}
@Test
fun parseValidFile() {
val allAppsSpecs =
- AllAppsSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_all_apps_file))
- assertThat(allAppsSpecs.heightSpecs.size).isEqualTo(1)
- assertThat(allAppsSpecs.heightSpecs[0].toString())
+ ResponsiveSpecsProvider.create(
+ TestResourceHelper(context, TestR.xml.valid_all_apps_file),
+ ResponsiveSpecType.AllApps
+ )
+
+ val specs = allAppsSpecs.getSpecsByAspectRatio(aspectRatio)
+ assertThat(specs.heightSpecs.size).isEqualTo(1)
+ assertThat(specs.heightSpecs[0].toString())
.isEqualTo(
- "AllAppsSpec(" +
+ "ResponsiveSpec(" +
"maxAvailableSize=26247, " +
- "specType=HEIGHT, " +
+ "dimensionType=HEIGHT, " +
+ "specType=AllApps, " +
"startPadding=SizeSpec(fixedSize=0.0, " +
"ofAvailableSpace=0.0, " +
"ofRemainderSpace=0.0, " +
@@ -71,12 +80,13 @@
")"
)
- assertThat(allAppsSpecs.widthSpecs.size).isEqualTo(1)
- assertThat(allAppsSpecs.widthSpecs[0].toString())
+ assertThat(specs.widthSpecs.size).isEqualTo(1)
+ assertThat(specs.widthSpecs[0].toString())
.isEqualTo(
- "AllAppsSpec(" +
+ "ResponsiveSpec(" +
"maxAvailableSize=26247, " +
- "specType=WIDTH, " +
+ "dimensionType=WIDTH, " +
+ "specType=AllApps, " +
"startPadding=SizeSpec(fixedSize=0.0, " +
"ofAvailableSpace=0.0, " +
"ofRemainderSpace=0.0, " +
@@ -103,16 +113,25 @@
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_missingTag_throwsError() {
- AllAppsSpecs.create(TestResourceHelper(context!!, TestR.xml.invalid_all_apps_file_case_1))
+ ResponsiveSpecsProvider.create(
+ TestResourceHelper(context, TestR.xml.invalid_all_apps_file_case_1),
+ ResponsiveSpecType.AllApps
+ )
}
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_moreThanOneValuePerTag_throwsError() {
- AllAppsSpecs.create(TestResourceHelper(context!!, TestR.xml.invalid_all_apps_file_case_2))
+ ResponsiveSpecsProvider.create(
+ TestResourceHelper(context, TestR.xml.invalid_all_apps_file_case_2),
+ ResponsiveSpecType.AllApps
+ )
}
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_valueBiggerThan1_throwsError() {
- AllAppsSpecs.create(TestResourceHelper(context!!, TestR.xml.invalid_all_apps_file_case_3))
+ ResponsiveSpecsProvider.create(
+ TestResourceHelper(context, TestR.xml.invalid_all_apps_file_case_3),
+ ResponsiveSpecType.AllApps
+ )
}
}
diff --git a/tests/src/com/android/launcher3/responsive/CalculatedAllAppsSpecTest.kt b/tests/src/com/android/launcher3/responsive/CalculatedAllAppsSpecTest.kt
index 0f12e58..1cc5ed2 100644
--- a/tests/src/com/android/launcher3/responsive/CalculatedAllAppsSpecTest.kt
+++ b/tests/src/com/android/launcher3/responsive/CalculatedAllAppsSpecTest.kt
@@ -21,6 +21,8 @@
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
+import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
import com.android.launcher3.tests.R as TestR
import com.android.launcher3.util.TestResourceHelper
import com.google.common.truth.Truth.assertThat
@@ -40,6 +42,7 @@
@Test
fun normalPhone_copiesFromWorkspace() {
val deviceSpec = deviceSpecs["phone"]!!
+ val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
initializeVarsForPhone(deviceSpec)
val availableWidth = deviceSpec.naturalSize.first
@@ -48,14 +51,30 @@
val availableHeight = deviceSpec.naturalSize.second - deviceSpec.statusBarNaturalPx - 495
val workspaceSpecs =
- WorkspaceSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_workspace_file))
- val widthSpec = workspaceSpecs.getCalculatedWidthSpec(4, availableWidth)
- val heightSpec = workspaceSpecs.getCalculatedHeightSpec(5, availableHeight)
+ ResponsiveSpecsProvider.create(
+ TestResourceHelper(context, TestR.xml.valid_workspace_file),
+ ResponsiveSpecType.Workspace
+ )
+ val widthSpec =
+ workspaceSpecs.getCalculatedSpec(aspectRatio, DimensionType.WIDTH, 4, availableWidth)
+ val heightSpec =
+ workspaceSpecs.getCalculatedSpec(aspectRatio, DimensionType.HEIGHT, 5, availableHeight)
val allAppsSpecs =
- AllAppsSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_all_apps_file))
+ ResponsiveSpecsProvider.create(
+ TestResourceHelper(context, TestR.xml.valid_all_apps_file),
+ ResponsiveSpecType.AllApps
+ )
- with(allAppsSpecs.getCalculatedWidthSpec(4, availableWidth, widthSpec)) {
+ with(
+ allAppsSpecs.getCalculatedSpec(
+ aspectRatio,
+ DimensionType.WIDTH,
+ 4,
+ availableWidth,
+ widthSpec
+ )
+ ) {
assertThat(availableSpace).isEqualTo(availableWidth)
assertThat(cells).isEqualTo(4)
assertThat(startPaddingPx).isEqualTo(widthSpec.startPaddingPx)
@@ -64,7 +83,15 @@
assertThat(cellSizePx).isEqualTo(widthSpec.cellSizePx)
}
- with(allAppsSpecs.getCalculatedHeightSpec(5, availableHeight, heightSpec)) {
+ with(
+ allAppsSpecs.getCalculatedSpec(
+ aspectRatio,
+ DimensionType.HEIGHT,
+ 5,
+ availableHeight,
+ heightSpec
+ )
+ ) {
assertThat(availableSpace).isEqualTo(availableHeight)
assertThat(cells).isEqualTo(5)
assertThat(startPaddingPx).isEqualTo(0)
diff --git a/tests/src/com/android/launcher3/responsive/CalculatedFolderSpecTest.kt b/tests/src/com/android/launcher3/responsive/CalculatedFolderSpecTest.kt
new file mode 100644
index 0000000..c4e2d2a
--- /dev/null
+++ b/tests/src/com/android/launcher3/responsive/CalculatedFolderSpecTest.kt
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.responsive
+
+import android.content.Context
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
+import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
+import com.android.launcher3.tests.R
+import com.android.launcher3.util.TestResourceHelper
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CalculatedFolderSpecTest : AbstractDeviceProfileTest() {
+ override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
+ private val deviceSpec = deviceSpecs["phone"]!!
+ private val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
+
+ @Before
+ fun setup() {
+ initializeVarsForPhone(deviceSpec)
+ }
+
+ @Test
+ fun validate_matchWidthWorkspace() {
+ val columns = 6
+
+ // Loading workspace specs
+ val resourceHelperWorkspace = TestResourceHelper(context, R.xml.valid_workspace_file)
+ val workspaceSpecs =
+ ResponsiveSpecsProvider.create(resourceHelperWorkspace, ResponsiveSpecType.Workspace)
+
+ // Loading folders specs
+ val resourceHelperFolder = TestResourceHelper(context, R.xml.valid_folders_specs)
+ val folderSpecs =
+ ResponsiveSpecsProvider.create(resourceHelperFolder, ResponsiveSpecType.Folder)
+ val specs = folderSpecs.getSpecsByAspectRatio(aspectRatio)
+
+ assertThat(specs.widthSpecs.size).isEqualTo(2)
+ assertThat(specs.widthSpecs[0].cellSize.matchWorkspace).isEqualTo(true)
+ assertThat(specs.widthSpecs[1].cellSize.matchWorkspace).isEqualTo(false)
+
+ // Validate width spec <= 800
+ var availableWidth = deviceSpec.naturalSize.first
+ var calculatedWorkspace =
+ workspaceSpecs.getCalculatedSpec(
+ aspectRatio,
+ DimensionType.WIDTH,
+ columns,
+ availableWidth
+ )
+ var calculatedWidthFolderSpec =
+ folderSpecs.getCalculatedSpec(
+ aspectRatio,
+ DimensionType.WIDTH,
+ columns,
+ availableWidth,
+ calculatedWorkspace
+ )
+ with(calculatedWidthFolderSpec) {
+ assertThat(availableSpace).isEqualTo(availableWidth)
+ assertThat(cells).isEqualTo(columns)
+ assertThat(startPaddingPx).isEqualTo(16.dpToPx())
+ assertThat(endPaddingPx).isEqualTo(16.dpToPx())
+ assertThat(gutterPx).isEqualTo(16.dpToPx())
+ assertThat(cellSizePx).isEqualTo(calculatedWorkspace.cellSizePx)
+ }
+
+ // Validate width spec > 800
+ availableWidth = 2000.dpToPx()
+ calculatedWorkspace =
+ workspaceSpecs.getCalculatedSpec(
+ aspectRatio,
+ DimensionType.WIDTH,
+ columns,
+ availableWidth
+ )
+ calculatedWidthFolderSpec =
+ folderSpecs.getCalculatedSpec(
+ aspectRatio,
+ DimensionType.WIDTH,
+ columns,
+ availableWidth,
+ calculatedWorkspace
+ )
+ with(calculatedWidthFolderSpec) {
+ assertThat(availableSpace).isEqualTo(availableWidth)
+ assertThat(cells).isEqualTo(columns)
+ assertThat(startPaddingPx).isEqualTo(16.dpToPx())
+ assertThat(endPaddingPx).isEqualTo(16.dpToPx())
+ assertThat(gutterPx).isEqualTo(16.dpToPx())
+ assertThat(cellSizePx).isEqualTo(102.dpToPx())
+ }
+ }
+
+ @Test
+ fun validate_matchHeightWorkspace() {
+ // Hotseat is roughly 495px on a real device, it doesn't need to be precise on unit tests
+ val hotseatSize = 495
+ val statusBarHeight = deviceSpec.statusBarNaturalPx
+ val availableHeight = deviceSpec.naturalSize.second - statusBarHeight - hotseatSize
+ val rows = 5
+
+ // Loading workspace specs
+ val resourceHelperWorkspace = TestResourceHelper(context, R.xml.valid_workspace_file)
+ val workspaceSpecs =
+ ResponsiveSpecsProvider.create(resourceHelperWorkspace, ResponsiveSpecType.Workspace)
+
+ // Loading folders specs
+ val resourceHelperFolder = TestResourceHelper(context, R.xml.valid_folders_specs)
+ val folderSpecs =
+ ResponsiveSpecsProvider.create(resourceHelperFolder, ResponsiveSpecType.Folder)
+ val specs = folderSpecs.getSpecsByAspectRatio(aspectRatio)
+
+ assertThat(specs.heightSpecs.size).isEqualTo(1)
+ assertThat(specs.heightSpecs[0].cellSize.matchWorkspace).isEqualTo(true)
+
+ // Validate height spec
+ val calculatedWorkspace =
+ workspaceSpecs.getCalculatedSpec(
+ aspectRatio,
+ DimensionType.HEIGHT,
+ rows,
+ availableHeight
+ )
+ val calculatedFolderSpec =
+ folderSpecs.getCalculatedSpec(
+ aspectRatio,
+ DimensionType.HEIGHT,
+ rows,
+ availableHeight,
+ calculatedWorkspace
+ )
+ with(calculatedFolderSpec) {
+ assertThat(availableSpace).isEqualTo(availableHeight)
+ assertThat(cells).isEqualTo(rows)
+ assertThat(startPaddingPx).isEqualTo(24.dpToPx())
+ assertThat(endPaddingPx).isEqualTo(64.dpToPx())
+ assertThat(gutterPx).isEqualTo(16.dpToPx())
+ assertThat(cellSizePx).isEqualTo(calculatedWorkspace.cellSizePx)
+ }
+ }
+}
diff --git a/tests/src/com/android/launcher3/responsive/CalculatedFolderSpecsTest.kt b/tests/src/com/android/launcher3/responsive/CalculatedFolderSpecsTest.kt
deleted file mode 100644
index f2a269a..0000000
--- a/tests/src/com/android/launcher3/responsive/CalculatedFolderSpecsTest.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.responsive
-
-import android.content.Context
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.launcher3.AbstractDeviceProfileTest
-import com.android.launcher3.tests.R
-import com.android.launcher3.util.TestResourceHelper
-import com.google.common.truth.Truth.assertThat
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class CalculatedFolderSpecsTest : AbstractDeviceProfileTest() {
- override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
-
- private val deviceSpec = deviceSpecs["phone"]!!
-
- @Before
- fun setup() {
- initializeVarsForPhone(deviceSpec)
- }
-
- @Test
- fun validate_matchWidthWorkspace() {
- val columns = 6
-
- // Loading workspace specs
- val resourceHelperWorkspace = TestResourceHelper(context!!, R.xml.valid_workspace_file)
- val workspaceSpecs = WorkspaceSpecs.create(resourceHelperWorkspace)
-
- // Loading folders specs
- val resourceHelperFolder = TestResourceHelper(context!!, R.xml.valid_folders_specs)
- val folderSpecs = FolderSpecs.create(resourceHelperFolder)
-
- assertThat(folderSpecs.widthSpecs.size).isEqualTo(2)
- assertThat(folderSpecs.widthSpecs[0].cellSize.matchWorkspace).isEqualTo(true)
- assertThat(folderSpecs.widthSpecs[1].cellSize.matchWorkspace).isEqualTo(false)
-
- // Validate width spec <= 800
- var availableWidth = deviceSpec.naturalSize.first
- var calculatedWorkspace = workspaceSpecs.getCalculatedWidthSpec(columns, availableWidth)
- var calculatedWidthFolderSpec =
- folderSpecs.getCalculatedWidthSpec(columns, availableWidth, calculatedWorkspace)
- with(calculatedWidthFolderSpec) {
- assertThat(availableSpace).isEqualTo(availableWidth)
- assertThat(cells).isEqualTo(columns)
- assertThat(startPaddingPx).isEqualTo(16.dpToPx())
- assertThat(endPaddingPx).isEqualTo(16.dpToPx())
- assertThat(gutterPx).isEqualTo(16.dpToPx())
- assertThat(cellSizePx).isEqualTo(calculatedWorkspace.cellSizePx)
- }
-
- // Validate width spec > 800
- availableWidth = 2000.dpToPx()
- calculatedWorkspace = workspaceSpecs.getCalculatedWidthSpec(columns, availableWidth)
- calculatedWidthFolderSpec =
- folderSpecs.getCalculatedWidthSpec(columns, availableWidth, calculatedWorkspace)
- with(calculatedWidthFolderSpec) {
- assertThat(availableSpace).isEqualTo(availableWidth)
- assertThat(cells).isEqualTo(columns)
- assertThat(startPaddingPx).isEqualTo(16.dpToPx())
- assertThat(endPaddingPx).isEqualTo(16.dpToPx())
- assertThat(gutterPx).isEqualTo(16.dpToPx())
- assertThat(cellSizePx).isEqualTo(102.dpToPx())
- }
- }
-
- @Test
- fun validate_matchHeightWorkspace() {
- // Hotseat is roughly 495px on a real device, it doesn't need to be precise on unit tests
- val hotseatSize = 495
- val statusBarHeight = deviceSpec.statusBarNaturalPx
- val availableHeight = deviceSpec.naturalSize.second - statusBarHeight - hotseatSize
- val rows = 5
-
- // Loading workspace specs
- val resourceHelperWorkspace = TestResourceHelper(context!!, R.xml.valid_workspace_file)
- val workspaceSpecs = WorkspaceSpecs.create(resourceHelperWorkspace)
-
- // Loading folders specs
- val resourceHelperFolder = TestResourceHelper(context!!, R.xml.valid_folders_specs)
- val folderSpecs = FolderSpecs.create(resourceHelperFolder)
-
- assertThat(folderSpecs.heightSpecs.size).isEqualTo(1)
- assertThat(folderSpecs.heightSpecs[0].cellSize.matchWorkspace).isEqualTo(true)
-
- // Validate height spec
- val calculatedWorkspace = workspaceSpecs.getCalculatedHeightSpec(rows, availableHeight)
- val calculatedFolderSpec =
- folderSpecs.getCalculatedHeightSpec(rows, availableHeight, calculatedWorkspace)
- with(calculatedFolderSpec) {
- assertThat(availableSpace).isEqualTo(availableHeight)
- assertThat(cells).isEqualTo(rows)
- assertThat(startPaddingPx).isEqualTo(24.dpToPx())
- assertThat(endPaddingPx).isEqualTo(64.dpToPx())
- assertThat(gutterPx).isEqualTo(16.dpToPx())
- assertThat(cellSizePx).isEqualTo(calculatedWorkspace.cellSizePx)
- }
- }
-}
diff --git a/tests/src/com/android/launcher3/responsive/CalculatedHotseatSpecTest.kt b/tests/src/com/android/launcher3/responsive/CalculatedHotseatSpecTest.kt
index 5865036..1a564ac 100644
--- a/tests/src/com/android/launcher3/responsive/CalculatedHotseatSpecTest.kt
+++ b/tests/src/com/android/launcher3/responsive/CalculatedHotseatSpecTest.kt
@@ -21,6 +21,7 @@
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
import com.android.launcher3.tests.R as TestR
import com.android.launcher3.util.TestResourceHelper
import com.google.common.truth.Truth.assertThat
@@ -31,6 +32,8 @@
@RunWith(AndroidJUnit4::class)
class CalculatedHotseatSpecTest : AbstractDeviceProfileTest() {
override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
+ val deviceSpec = deviceSpecs["phone"]!!
+ val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
/**
* This test tests:
@@ -38,15 +41,19 @@
*/
@Test
fun normalPhone_returnsSecondBreakpointSpec() {
- val deviceSpec = deviceSpecs["phone"]!!
initializeVarsForPhone(deviceSpec)
// Hotseat uses the whole device height
val availableHeight = deviceSpec.naturalSize.second
- val hotseatSpecs =
- HotseatSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_hotseat_file))
- val heightSpec = hotseatSpecs.getCalculatedHeightSpec(availableHeight)
+ val hotseatSpecsProvider =
+ HotseatSpecsProvider.create(TestResourceHelper(context, TestR.xml.valid_hotseat_file))
+ val heightSpec =
+ hotseatSpecsProvider.getCalculatedSpec(
+ aspectRatio,
+ DimensionType.HEIGHT,
+ availableHeight
+ )
assertThat(heightSpec.availableSpace).isEqualTo(availableHeight)
assertThat(heightSpec.hotseatQsbSpace).isEqualTo(95)
@@ -59,16 +66,20 @@
*/
@Test
fun smallPhone_returnsFirstBreakpointSpec() {
- val deviceSpec = deviceSpecs["phone"]!!
deviceSpec.densityDpi = 540 // larger display size
initializeVarsForPhone(deviceSpec)
// Hotseat uses the whole device height
val availableHeight = deviceSpec.naturalSize.second
- val hotseatSpecs =
- HotseatSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_hotseat_file))
- val heightSpec = hotseatSpecs.getCalculatedHeightSpec(availableHeight)
+ val hotseatSpecsProvider =
+ HotseatSpecsProvider.create(TestResourceHelper(context, TestR.xml.valid_hotseat_file))
+ val heightSpec =
+ hotseatSpecsProvider.getCalculatedSpec(
+ aspectRatio,
+ DimensionType.HEIGHT,
+ availableHeight
+ )
assertThat(heightSpec.availableSpace).isEqualTo(availableHeight)
assertThat(heightSpec.hotseatQsbSpace).isEqualTo(81)
@@ -81,15 +92,17 @@
*/
@Test
fun normalPhoneLandscape_returnsSecondBreakpointSpec() {
- val deviceSpec = deviceSpecs["phone"]!!
initializeVarsForPhone(deviceSpec, isVerticalBar = true)
// Hotseat uses the whole device width
val availableWidth = deviceSpec.naturalSize.second
- val hotseatSpecs =
- HotseatSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_hotseat_land_file))
- val widthSpec = hotseatSpecs.getCalculatedWidthSpec(availableWidth)
+ val hotseatSpecsProvider =
+ HotseatSpecsProvider.create(
+ TestResourceHelper(context, TestR.xml.valid_hotseat_land_file)
+ )
+ val widthSpec =
+ hotseatSpecsProvider.getCalculatedSpec(aspectRatio, DimensionType.WIDTH, availableWidth)
assertThat(widthSpec.availableSpace).isEqualTo(availableWidth)
assertThat(widthSpec.hotseatQsbSpace).isEqualTo(0)
diff --git a/tests/src/com/android/launcher3/responsive/CalculatedWorkspaceSpecTest.kt b/tests/src/com/android/launcher3/responsive/CalculatedWorkspaceSpecTest.kt
index 8f56c5f..0c5d347 100644
--- a/tests/src/com/android/launcher3/responsive/CalculatedWorkspaceSpecTest.kt
+++ b/tests/src/com/android/launcher3/responsive/CalculatedWorkspaceSpecTest.kt
@@ -21,6 +21,8 @@
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
+import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
import com.android.launcher3.tests.R as TestR
import com.android.launcher3.util.TestResourceHelper
import com.google.common.truth.Truth.assertThat
@@ -41,6 +43,7 @@
@Test
fun normalPhone_returnsThirdBreakpointSpec() {
val deviceSpec = deviceSpecs["phone"]!!
+ val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
initializeVarsForPhone(deviceSpec)
val availableWidth = deviceSpec.naturalSize.first
@@ -49,9 +52,14 @@
val availableHeight = deviceSpec.naturalSize.second - deviceSpec.statusBarNaturalPx - 495
val workspaceSpecs =
- WorkspaceSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_workspace_file))
- val widthSpec = workspaceSpecs.getCalculatedWidthSpec(4, availableWidth)
- val heightSpec = workspaceSpecs.getCalculatedHeightSpec(5, availableHeight)
+ ResponsiveSpecsProvider.create(
+ TestResourceHelper(context, TestR.xml.valid_workspace_file),
+ ResponsiveSpecType.Workspace
+ )
+ val widthSpec =
+ workspaceSpecs.getCalculatedSpec(aspectRatio, DimensionType.WIDTH, 4, availableWidth)
+ val heightSpec =
+ workspaceSpecs.getCalculatedSpec(aspectRatio, DimensionType.HEIGHT, 5, availableHeight)
assertThat(widthSpec.availableSpace).isEqualTo(availableWidth)
assertThat(widthSpec.cells).isEqualTo(4)
@@ -77,6 +85,7 @@
@Test
fun smallPhone_returnsFirstBreakpointSpec() {
val deviceSpec = deviceSpecs["phone"]!!
+ val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
deviceSpec.densityDpi = 540 // larger display size
initializeVarsForPhone(deviceSpec)
@@ -86,9 +95,14 @@
val availableHeight = deviceSpec.naturalSize.second - deviceSpec.statusBarNaturalPx - 640
val workspaceSpecs =
- WorkspaceSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_workspace_file))
- val widthSpec = workspaceSpecs.getCalculatedWidthSpec(4, availableWidth)
- val heightSpec = workspaceSpecs.getCalculatedHeightSpec(5, availableHeight)
+ ResponsiveSpecsProvider.create(
+ TestResourceHelper(context, TestR.xml.valid_workspace_file),
+ ResponsiveSpecType.Workspace
+ )
+ val widthSpec =
+ workspaceSpecs.getCalculatedSpec(aspectRatio, DimensionType.WIDTH, 4, availableWidth)
+ val heightSpec =
+ workspaceSpecs.getCalculatedSpec(aspectRatio, DimensionType.HEIGHT, 5, availableHeight)
assertThat(widthSpec.availableSpace).isEqualTo(availableWidth)
assertThat(widthSpec.cells).isEqualTo(4)
@@ -114,6 +128,7 @@
@Test
fun smallPhone_returnsFirstBreakpointSpec_unsortedFile() {
val deviceSpec = deviceSpecs["phone"]!!
+ val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
deviceSpec.densityDpi = 540 // larger display size
initializeVarsForPhone(deviceSpec)
@@ -121,13 +136,15 @@
// Hotseat size is roughly 640px on a real device,
// it doesn't need to be precise on unit tests
val availableHeight = deviceSpec.naturalSize.second - deviceSpec.statusBarNaturalPx - 640
-
val workspaceSpecs =
- WorkspaceSpecs.create(
- TestResourceHelper(context!!, TestR.xml.valid_workspace_unsorted_file)
+ ResponsiveSpecsProvider.create(
+ TestResourceHelper(context, TestR.xml.valid_workspace_unsorted_file),
+ ResponsiveSpecType.Workspace
)
- val widthSpec = workspaceSpecs.getCalculatedWidthSpec(4, availableWidth)
- val heightSpec = workspaceSpecs.getCalculatedHeightSpec(5, availableHeight)
+ val widthSpec =
+ workspaceSpecs.getCalculatedSpec(aspectRatio, DimensionType.WIDTH, 4, availableWidth)
+ val heightSpec =
+ workspaceSpecs.getCalculatedSpec(aspectRatio, DimensionType.HEIGHT, 5, availableHeight)
assertThat(widthSpec.availableSpace).isEqualTo(availableWidth)
assertThat(widthSpec.cells).isEqualTo(4)
diff --git a/tests/src/com/android/launcher3/responsive/FolderSpecTest.kt b/tests/src/com/android/launcher3/responsive/FolderSpecTest.kt
new file mode 100644
index 0000000..5cfa49f
--- /dev/null
+++ b/tests/src/com/android/launcher3/responsive/FolderSpecTest.kt
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.responsive
+
+import android.content.Context
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
+import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
+import com.android.launcher3.tests.R
+import com.android.launcher3.util.TestResourceHelper
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class FolderSpecTest : AbstractDeviceProfileTest() {
+ override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
+ val deviceSpec = deviceSpecs["tablet"]!!
+ val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
+
+ @Before
+ fun setup() {
+ initializeVarsForPhone(deviceSpec)
+ }
+
+ @Test
+ fun parseValidFile() {
+ val resourceHelper = TestResourceHelper(context, R.xml.valid_folders_specs)
+ val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+ val specs = folderSpecs.getSpecsByAspectRatio(aspectRatio)
+
+ val sizeSpec16 = SizeSpec(16f.dpToPx())
+ val widthSpecsExpected =
+ listOf(
+ ResponsiveSpec(
+ maxAvailableSize = 800.dpToPx(),
+ dimensionType = DimensionType.WIDTH,
+ specType = ResponsiveSpecType.Folder,
+ startPadding = sizeSpec16,
+ endPadding = sizeSpec16,
+ gutter = sizeSpec16,
+ cellSize = SizeSpec(matchWorkspace = true)
+ ),
+ ResponsiveSpec(
+ maxAvailableSize = 9999.dpToPx(),
+ dimensionType = DimensionType.WIDTH,
+ specType = ResponsiveSpecType.Folder,
+ startPadding = sizeSpec16,
+ endPadding = sizeSpec16,
+ gutter = sizeSpec16,
+ cellSize = SizeSpec(102f.dpToPx())
+ )
+ )
+
+ val heightSpecsExpected =
+ ResponsiveSpec(
+ maxAvailableSize = 9999.dpToPx(),
+ dimensionType = DimensionType.HEIGHT,
+ specType = ResponsiveSpecType.Folder,
+ startPadding = SizeSpec(24f.dpToPx()),
+ endPadding = SizeSpec(64f.dpToPx()),
+ gutter = sizeSpec16,
+ cellSize = SizeSpec(matchWorkspace = true)
+ )
+
+ assertThat(specs.widthSpecs.size).isEqualTo(widthSpecsExpected.size)
+ assertThat(specs.widthSpecs[0]).isEqualTo(widthSpecsExpected[0])
+ assertThat(specs.widthSpecs[1]).isEqualTo(widthSpecsExpected[1])
+
+ assertThat(specs.heightSpecs.size).isEqualTo(1)
+ assertThat(specs.heightSpecs[0]).isEqualTo(heightSpecsExpected)
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun parseInvalidFile_missingTag_throwsError() {
+ val resourceHelper = TestResourceHelper(context, R.xml.invalid_folders_specs_1)
+ ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun parseInvalidFile_moreThanOneValuePerTag_throwsError() {
+ val resourceHelper = TestResourceHelper(context, R.xml.invalid_folders_specs_2)
+ ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun parseInvalidFile_valueBiggerThan1_throwsError() {
+ val resourceHelper = TestResourceHelper(context, R.xml.invalid_folders_specs_3)
+ ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun parseInvalidFile_missingSpecs_throwsError() {
+ val resourceHelper = TestResourceHelper(context, R.xml.invalid_folders_specs_4)
+ ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun parseInvalidFile_missingWidthBreakpoint_throwsError() {
+ val availableSpace = 900.dpToPx()
+ val cells = 3
+
+ val workspaceSpec =
+ ResponsiveSpec(
+ maxAvailableSize = availableSpace,
+ dimensionType = DimensionType.WIDTH,
+ specType = ResponsiveSpecType.Folder,
+ startPadding = SizeSpec(fixedSize = 10f),
+ endPadding = SizeSpec(fixedSize = 10f),
+ gutter = SizeSpec(fixedSize = 10f),
+ cellSize = SizeSpec(fixedSize = 10f)
+ )
+ val calculatedWorkspaceSpec =
+ CalculatedResponsiveSpec(aspectRatio, availableSpace, cells, workspaceSpec)
+
+ val resourceHelper = TestResourceHelper(context, R.xml.invalid_folders_specs_5)
+ val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+ folderSpecs.getCalculatedSpec(
+ aspectRatio,
+ DimensionType.WIDTH,
+ cells,
+ availableSpace,
+ calculatedWorkspaceSpec
+ )
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun parseInvalidFile_missingHeightBreakpoint_throwsError() {
+ val availableSpace = 900.dpToPx()
+ val cells = 3
+
+ val workspaceSpec =
+ ResponsiveSpec(
+ maxAvailableSize = availableSpace,
+ dimensionType = DimensionType.HEIGHT,
+ specType = ResponsiveSpecType.Folder,
+ startPadding = SizeSpec(fixedSize = 10f),
+ endPadding = SizeSpec(fixedSize = 10f),
+ gutter = SizeSpec(fixedSize = 10f),
+ cellSize = SizeSpec(fixedSize = 10f)
+ )
+ val calculatedWorkspaceSpec =
+ CalculatedResponsiveSpec(aspectRatio, availableSpace, cells, workspaceSpec)
+
+ val resourceHelper = TestResourceHelper(context, R.xml.invalid_folders_specs_5)
+ val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+ folderSpecs.getCalculatedSpec(
+ aspectRatio,
+ DimensionType.HEIGHT,
+ cells,
+ availableSpace,
+ calculatedWorkspaceSpec
+ )
+ }
+
+ @Test
+ fun retrievesCalculatedWidthSpec() {
+ val availableSpace = 800.dpToPx()
+ val cells = 3
+
+ val workspaceSpec =
+ ResponsiveSpec(
+ maxAvailableSize = availableSpace,
+ dimensionType = DimensionType.WIDTH,
+ specType = ResponsiveSpecType.Workspace,
+ startPadding = SizeSpec(fixedSize = 10f),
+ endPadding = SizeSpec(fixedSize = 10f),
+ gutter = SizeSpec(fixedSize = 10f),
+ cellSize = SizeSpec(fixedSize = 10f)
+ )
+ val calculatedWorkspaceSpec =
+ CalculatedResponsiveSpec(aspectRatio, availableSpace, cells, workspaceSpec)
+
+ val resourceHelper = TestResourceHelper(context, R.xml.valid_folders_specs)
+ val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+ val calculatedWidthSpec =
+ folderSpecs.getCalculatedSpec(
+ aspectRatio,
+ DimensionType.WIDTH,
+ cells,
+ availableSpace,
+ calculatedWorkspaceSpec
+ )
+
+ assertThat(calculatedWidthSpec.cells).isEqualTo(cells)
+ assertThat(calculatedWidthSpec.availableSpace).isEqualTo(availableSpace)
+ assertThat(calculatedWidthSpec.startPaddingPx).isEqualTo(16.dpToPx())
+ assertThat(calculatedWidthSpec.endPaddingPx).isEqualTo(16.dpToPx())
+ assertThat(calculatedWidthSpec.gutterPx).isEqualTo(16.dpToPx())
+ assertThat(calculatedWidthSpec.cellSizePx).isEqualTo(calculatedWorkspaceSpec.cellSizePx)
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun retrievesCalculatedWidthSpec_invalidCalculatedResponsiveSpecType_throwsError() {
+ val availableSpace = 10.dpToPx()
+ val cells = 3
+
+ val workspaceSpec =
+ ResponsiveSpec(
+ maxAvailableSize = availableSpace,
+ dimensionType = DimensionType.HEIGHT,
+ specType = ResponsiveSpecType.Folder,
+ startPadding = SizeSpec(fixedSize = 10f),
+ endPadding = SizeSpec(fixedSize = 10f),
+ gutter = SizeSpec(fixedSize = 10f),
+ cellSize = SizeSpec(fixedSize = 10f)
+ )
+ val calculatedWorkspaceSpec =
+ CalculatedResponsiveSpec(aspectRatio, availableSpace, cells, workspaceSpec)
+
+ val resourceHelper = TestResourceHelper(context, R.xml.valid_folders_specs)
+ val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+ folderSpecs.getCalculatedSpec(
+ aspectRatio,
+ DimensionType.WIDTH,
+ cells,
+ availableSpace,
+ calculatedWorkspaceSpec
+ )
+ }
+
+ @Test
+ fun retrievesCalculatedHeightSpec() {
+ val availableSpace = 700.dpToPx()
+ val cells = 3
+
+ val workspaceSpec =
+ ResponsiveSpec(
+ maxAvailableSize = availableSpace,
+ dimensionType = DimensionType.HEIGHT,
+ specType = ResponsiveSpecType.Workspace,
+ startPadding = SizeSpec(fixedSize = 10f),
+ endPadding = SizeSpec(fixedSize = 10f),
+ gutter = SizeSpec(fixedSize = 10f),
+ cellSize = SizeSpec(fixedSize = 10f)
+ )
+ val calculatedWorkspaceSpec =
+ CalculatedResponsiveSpec(aspectRatio, availableSpace, cells, workspaceSpec)
+
+ val resourceHelper = TestResourceHelper(context, R.xml.valid_folders_specs)
+ val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+ val calculatedHeightSpec =
+ folderSpecs.getCalculatedSpec(
+ aspectRatio,
+ DimensionType.HEIGHT,
+ cells,
+ availableSpace,
+ calculatedWorkspaceSpec
+ )
+
+ assertThat(calculatedHeightSpec.cells).isEqualTo(cells)
+ assertThat(calculatedHeightSpec.availableSpace).isEqualTo(availableSpace)
+ assertThat(calculatedHeightSpec.startPaddingPx).isEqualTo(24.dpToPx())
+ assertThat(calculatedHeightSpec.endPaddingPx).isEqualTo(64.dpToPx())
+ assertThat(calculatedHeightSpec.gutterPx).isEqualTo(16.dpToPx())
+ assertThat(calculatedHeightSpec.cellSizePx).isEqualTo(calculatedWorkspaceSpec.cellSizePx)
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun retrievesCalculatedHeightSpec_invalidCalculatedResponsiveSpecType_throwsError() {
+ val availableSpace = 10.dpToPx()
+ val cells = 3
+
+ val workspaceSpec =
+ ResponsiveSpec(
+ maxAvailableSize = availableSpace,
+ dimensionType = DimensionType.WIDTH,
+ specType = ResponsiveSpecType.Folder,
+ startPadding = SizeSpec(fixedSize = 10f),
+ endPadding = SizeSpec(fixedSize = 10f),
+ gutter = SizeSpec(fixedSize = 10f),
+ cellSize = SizeSpec(fixedSize = 10f)
+ )
+ val calculatedWorkspaceSpec =
+ CalculatedResponsiveSpec(aspectRatio, availableSpace, cells, workspaceSpec)
+
+ val resourceHelper = TestResourceHelper(context, R.xml.valid_folders_specs)
+ val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
+ folderSpecs.getCalculatedSpec(
+ aspectRatio,
+ DimensionType.HEIGHT,
+ cells,
+ availableSpace,
+ calculatedWorkspaceSpec
+ )
+ }
+}
diff --git a/tests/src/com/android/launcher3/responsive/FolderSpecsTest.kt b/tests/src/com/android/launcher3/responsive/FolderSpecsTest.kt
deleted file mode 100644
index 4b05949..0000000
--- a/tests/src/com/android/launcher3/responsive/FolderSpecsTest.kt
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.responsive
-
-import android.content.Context
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.launcher3.AbstractDeviceProfileTest
-import com.android.launcher3.responsive.ResponsiveSpec.SpecType
-import com.android.launcher3.tests.R
-import com.android.launcher3.util.TestResourceHelper
-import com.google.common.truth.Truth.assertThat
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class FolderSpecsTest : AbstractDeviceProfileTest() {
- override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
-
- @Before
- fun setup() {
- initializeVarsForPhone(deviceSpecs["tablet"]!!)
- }
-
- @Test
- fun parseValidFile() {
- val resourceHelper = TestResourceHelper(context!!, R.xml.valid_folders_specs)
- val folderSpecs = FolderSpecs.create(resourceHelper)
-
- val sizeSpec16 = SizeSpec(16f.dpToPx())
- val widthSpecsExpected =
- listOf(
- FolderSpec(
- maxAvailableSize = 800.dpToPx(),
- specType = SpecType.WIDTH,
- startPadding = sizeSpec16,
- endPadding = sizeSpec16,
- gutter = sizeSpec16,
- cellSize = SizeSpec(matchWorkspace = true)
- ),
- FolderSpec(
- maxAvailableSize = 9999.dpToPx(),
- specType = SpecType.WIDTH,
- startPadding = sizeSpec16,
- endPadding = sizeSpec16,
- gutter = sizeSpec16,
- cellSize = SizeSpec(102f.dpToPx())
- )
- )
-
- val heightSpecsExpected =
- FolderSpec(
- maxAvailableSize = 9999.dpToPx(),
- specType = SpecType.HEIGHT,
- startPadding = SizeSpec(24f.dpToPx()),
- endPadding = SizeSpec(64f.dpToPx()),
- gutter = sizeSpec16,
- cellSize = SizeSpec(matchWorkspace = true)
- )
-
- assertThat(folderSpecs.widthSpecs.size).isEqualTo(widthSpecsExpected.size)
- assertThat(folderSpecs.widthSpecs[0]).isEqualTo(widthSpecsExpected[0])
- assertThat(folderSpecs.widthSpecs[1]).isEqualTo(widthSpecsExpected[1])
-
- assertThat(folderSpecs.heightSpecs.size).isEqualTo(1)
- assertThat(folderSpecs.heightSpecs[0]).isEqualTo(heightSpecsExpected)
- }
-
- @Test(expected = IllegalStateException::class)
- fun parseInvalidFile_missingTag_throwsError() {
- val resourceHelper = TestResourceHelper(context!!, R.xml.invalid_folders_specs_1)
- FolderSpecs.create(resourceHelper)
- }
-
- @Test(expected = IllegalStateException::class)
- fun parseInvalidFile_moreThanOneValuePerTag_throwsError() {
- val resourceHelper = TestResourceHelper(context!!, R.xml.invalid_folders_specs_2)
- FolderSpecs.create(resourceHelper)
- }
-
- @Test(expected = IllegalStateException::class)
- fun parseInvalidFile_valueBiggerThan1_throwsError() {
- val resourceHelper = TestResourceHelper(context!!, R.xml.invalid_folders_specs_3)
- FolderSpecs.create(resourceHelper)
- }
-
- @Test(expected = IllegalStateException::class)
- fun parseInvalidFile_missingSpecs_throwsError() {
- val resourceHelper = TestResourceHelper(context!!, R.xml.invalid_folders_specs_4)
- FolderSpecs.create(resourceHelper)
- }
-
- @Test(expected = IllegalStateException::class)
- fun parseInvalidFile_missingWidthBreakpoint_throwsError() {
- val availableSpace = 900.dpToPx()
- val cells = 3
-
- val workspaceSpec =
- WorkspaceSpec(
- maxAvailableSize = availableSpace,
- specType = SpecType.WIDTH,
- startPadding = SizeSpec(fixedSize = 10f),
- endPadding = SizeSpec(fixedSize = 10f),
- gutter = SizeSpec(fixedSize = 10f),
- cellSize = SizeSpec(fixedSize = 10f)
- )
- val calculatedWorkspaceSpec = CalculatedWorkspaceSpec(availableSpace, cells, workspaceSpec)
-
- val resourceHelper = TestResourceHelper(context!!, R.xml.invalid_folders_specs_5)
- val folderSpecs = FolderSpecs.create(resourceHelper)
- folderSpecs.getCalculatedWidthSpec(cells, availableSpace, calculatedWorkspaceSpec)
- }
-
- @Test(expected = IllegalStateException::class)
- fun parseInvalidFile_missingHeightBreakpoint_throwsError() {
- val availableSpace = 900.dpToPx()
- val cells = 3
-
- val workspaceSpec =
- WorkspaceSpec(
- maxAvailableSize = availableSpace,
- specType = SpecType.HEIGHT,
- startPadding = SizeSpec(fixedSize = 10f),
- endPadding = SizeSpec(fixedSize = 10f),
- gutter = SizeSpec(fixedSize = 10f),
- cellSize = SizeSpec(fixedSize = 10f)
- )
- val calculatedWorkspaceSpec = CalculatedWorkspaceSpec(availableSpace, cells, workspaceSpec)
-
- val resourceHelper = TestResourceHelper(context!!, R.xml.invalid_folders_specs_5)
- val folderSpecs = FolderSpecs.create(resourceHelper)
- folderSpecs.getCalculatedHeightSpec(cells, availableSpace, calculatedWorkspaceSpec)
- }
-
- @Test
- fun retrievesCalculatedWidthSpec() {
- val availableSpace = 800.dpToPx()
- val cells = 3
-
- val workspaceSpec =
- WorkspaceSpec(
- maxAvailableSize = availableSpace,
- specType = SpecType.WIDTH,
- startPadding = SizeSpec(fixedSize = 10f),
- endPadding = SizeSpec(fixedSize = 10f),
- gutter = SizeSpec(fixedSize = 10f),
- cellSize = SizeSpec(fixedSize = 10f)
- )
- val calculatedWorkspaceSpec = CalculatedWorkspaceSpec(availableSpace, cells, workspaceSpec)
-
- val resourceHelper = TestResourceHelper(context!!, R.xml.valid_folders_specs)
- val folderSpecs = FolderSpecs.create(resourceHelper)
- val calculatedWidthSpec =
- folderSpecs.getCalculatedWidthSpec(cells, availableSpace, calculatedWorkspaceSpec)
-
- assertThat(calculatedWidthSpec.cells).isEqualTo(cells)
- assertThat(calculatedWidthSpec.availableSpace).isEqualTo(availableSpace)
- assertThat(calculatedWidthSpec.startPaddingPx).isEqualTo(16.dpToPx())
- assertThat(calculatedWidthSpec.endPaddingPx).isEqualTo(16.dpToPx())
- assertThat(calculatedWidthSpec.gutterPx).isEqualTo(16.dpToPx())
- assertThat(calculatedWidthSpec.cellSizePx).isEqualTo(calculatedWorkspaceSpec.cellSizePx)
- }
-
- @Test(expected = IllegalStateException::class)
- fun retrievesCalculatedWidthSpec_invalidCalculatedWorkspaceSpecType_throwsError() {
- val availableSpace = 10.dpToPx()
- val cells = 3
-
- val workspaceSpec =
- WorkspaceSpec(
- maxAvailableSize = availableSpace,
- specType = SpecType.HEIGHT,
- startPadding = SizeSpec(fixedSize = 10f),
- endPadding = SizeSpec(fixedSize = 10f),
- gutter = SizeSpec(fixedSize = 10f),
- cellSize = SizeSpec(fixedSize = 10f)
- )
- val calculatedWorkspaceSpec = CalculatedWorkspaceSpec(availableSpace, cells, workspaceSpec)
-
- val resourceHelper = TestResourceHelper(context!!, R.xml.valid_folders_specs)
- val folderSpecs = FolderSpecs.create(resourceHelper)
- folderSpecs.getCalculatedWidthSpec(cells, availableSpace, calculatedWorkspaceSpec)
- }
-
- @Test
- fun retrievesCalculatedHeightSpec() {
- val availableSpace = 700.dpToPx()
- val cells = 3
-
- val workspaceSpec =
- WorkspaceSpec(
- maxAvailableSize = availableSpace,
- specType = SpecType.HEIGHT,
- startPadding = SizeSpec(fixedSize = 10f),
- endPadding = SizeSpec(fixedSize = 10f),
- gutter = SizeSpec(fixedSize = 10f),
- cellSize = SizeSpec(fixedSize = 10f)
- )
- val calculatedWorkspaceSpec = CalculatedWorkspaceSpec(availableSpace, cells, workspaceSpec)
-
- val resourceHelper = TestResourceHelper(context!!, R.xml.valid_folders_specs)
- val folderSpecs = FolderSpecs.create(resourceHelper)
- val calculatedHeightSpec =
- folderSpecs.getCalculatedHeightSpec(cells, availableSpace, calculatedWorkspaceSpec)
-
- assertThat(calculatedHeightSpec.cells).isEqualTo(cells)
- assertThat(calculatedHeightSpec.availableSpace).isEqualTo(availableSpace)
- assertThat(calculatedHeightSpec.startPaddingPx).isEqualTo(24.dpToPx())
- assertThat(calculatedHeightSpec.endPaddingPx).isEqualTo(64.dpToPx())
- assertThat(calculatedHeightSpec.gutterPx).isEqualTo(16.dpToPx())
- assertThat(calculatedHeightSpec.cellSizePx).isEqualTo(calculatedWorkspaceSpec.cellSizePx)
- }
-
- @Test(expected = IllegalStateException::class)
- fun retrievesCalculatedHeightSpec_invalidCalculatedWorkspaceSpecType_throwsError() {
- val availableSpace = 10.dpToPx()
- val cells = 3
-
- val workspaceSpec =
- WorkspaceSpec(
- maxAvailableSize = availableSpace,
- specType = SpecType.WIDTH,
- startPadding = SizeSpec(fixedSize = 10f),
- endPadding = SizeSpec(fixedSize = 10f),
- gutter = SizeSpec(fixedSize = 10f),
- cellSize = SizeSpec(fixedSize = 10f)
- )
- val calculatedWorkspaceSpec = CalculatedWorkspaceSpec(availableSpace, cells, workspaceSpec)
-
- val resourceHelper = TestResourceHelper(context!!, R.xml.valid_folders_specs)
- val folderSpecs = FolderSpecs.create(resourceHelper)
- folderSpecs.getCalculatedHeightSpec(cells, availableSpace, calculatedWorkspaceSpec)
- }
-}
diff --git a/tests/src/com/android/launcher3/responsive/HotseatSpecsProviderTest.kt b/tests/src/com/android/launcher3/responsive/HotseatSpecsProviderTest.kt
new file mode 100644
index 0000000..32249e0
--- /dev/null
+++ b/tests/src/com/android/launcher3/responsive/HotseatSpecsProviderTest.kt
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.responsive
+
+import android.content.Context
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
+import com.android.launcher3.tests.R as TestR
+import com.android.launcher3.util.TestResourceHelper
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class HotseatSpecsProviderTest : AbstractDeviceProfileTest() {
+ override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
+ val deviceSpec = deviceSpecs["phone"]!!
+ val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
+
+ @Before
+ fun setup() {
+ initializeVarsForPhone(deviceSpec)
+ }
+
+ @Test
+ fun parseValidFile() {
+ val hotseatSpecsProvider =
+ HotseatSpecsProvider.create(TestResourceHelper(context, TestR.xml.valid_hotseat_file))
+ val specs = hotseatSpecsProvider.getSpecsByAspectRatio(aspectRatio)
+
+ val expectedHeightSpecs =
+ listOf(
+ HotseatSpec(
+ maxAvailableSize = 847.dpToPx(),
+ dimensionType = ResponsiveSpec.DimensionType.HEIGHT,
+ specType = ResponsiveSpecType.Hotseat,
+ hotseatQsbSpace = SizeSpec(24f.dpToPx()),
+ edgePadding = SizeSpec(48f.dpToPx())
+ ),
+ HotseatSpec(
+ maxAvailableSize = 9999.dpToPx(),
+ dimensionType = ResponsiveSpec.DimensionType.HEIGHT,
+ specType = ResponsiveSpecType.Hotseat,
+ hotseatQsbSpace = SizeSpec(36f.dpToPx()),
+ edgePadding = SizeSpec(48f.dpToPx())
+ ),
+ )
+
+ assertThat(specs.heightSpecs.size).isEqualTo(expectedHeightSpecs.size)
+ assertThat(specs.heightSpecs[0]).isEqualTo(expectedHeightSpecs[0])
+ assertThat(specs.heightSpecs[1]).isEqualTo(expectedHeightSpecs[1])
+
+ assertThat(specs.widthSpecs.size).isEqualTo(0)
+ }
+
+ @Test
+ fun parseValidLandscapeFile() {
+ val hotseatSpecsProvider =
+ HotseatSpecsProvider.create(
+ TestResourceHelper(context, TestR.xml.valid_hotseat_land_file)
+ )
+ val specs = hotseatSpecsProvider.getSpecsByAspectRatio(aspectRatio)
+ assertThat(specs.heightSpecs.size).isEqualTo(0)
+
+ val expectedWidthSpecs =
+ listOf(
+ HotseatSpec(
+ maxAvailableSize = 743.dpToPx(),
+ dimensionType = ResponsiveSpec.DimensionType.WIDTH,
+ specType = ResponsiveSpecType.Hotseat,
+ hotseatQsbSpace = SizeSpec(0f),
+ edgePadding = SizeSpec(48f.dpToPx())
+ ),
+ HotseatSpec(
+ maxAvailableSize = 9999.dpToPx(),
+ dimensionType = ResponsiveSpec.DimensionType.WIDTH,
+ specType = ResponsiveSpecType.Hotseat,
+ hotseatQsbSpace = SizeSpec(0f),
+ edgePadding = SizeSpec(64f.dpToPx())
+ ),
+ )
+
+ assertThat(specs.widthSpecs.size).isEqualTo(expectedWidthSpecs.size)
+ assertThat(specs.widthSpecs[0]).isEqualTo(expectedWidthSpecs[0])
+ assertThat(specs.widthSpecs[1]).isEqualTo(expectedWidthSpecs[1])
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun parseInvalidFile_spaceIsNotFixedSize_throwsError() {
+ HotseatSpecsProvider.create(
+ TestResourceHelper(context, TestR.xml.invalid_hotseat_file_case_1)
+ )
+ }
+}
diff --git a/tests/src/com/android/launcher3/responsive/HotseatSpecsTest.kt b/tests/src/com/android/launcher3/responsive/HotseatSpecsTest.kt
deleted file mode 100644
index f650e91..0000000
--- a/tests/src/com/android/launcher3/responsive/HotseatSpecsTest.kt
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.responsive
-
-import android.content.Context
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.launcher3.AbstractDeviceProfileTest
-import com.android.launcher3.tests.R as TestR
-import com.android.launcher3.util.TestResourceHelper
-import com.google.common.truth.Truth.assertThat
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class HotseatSpecsTest : AbstractDeviceProfileTest() {
- override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
-
- @Before
- fun setup() {
- initializeVarsForPhone(deviceSpecs["phone"]!!)
- }
-
- @Test
- fun parseValidFile() {
- val hotseatSpecs =
- HotseatSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_hotseat_file))
-
- val expectedHeightSpecs =
- listOf(
- HotseatSpec(
- maxAvailableSize = 847.dpToPx(),
- specType = ResponsiveSpec.SpecType.HEIGHT,
- hotseatQsbSpace = SizeSpec(24f.dpToPx()),
- edgePadding = SizeSpec(48f.dpToPx())
- ),
- HotseatSpec(
- maxAvailableSize = 9999.dpToPx(),
- specType = ResponsiveSpec.SpecType.HEIGHT,
- hotseatQsbSpace = SizeSpec(36f.dpToPx()),
- edgePadding = SizeSpec(48f.dpToPx())
- ),
- )
-
- assertThat(hotseatSpecs.heightSpecs.size).isEqualTo(expectedHeightSpecs.size)
- assertThat(hotseatSpecs.heightSpecs[0]).isEqualTo(expectedHeightSpecs[0])
- assertThat(hotseatSpecs.heightSpecs[1]).isEqualTo(expectedHeightSpecs[1])
-
- assertThat(hotseatSpecs.widthSpecs.size).isEqualTo(0)
- }
-
- @Test
- fun parseValidLandscapeFile() {
- val hotseatSpecs =
- HotseatSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_hotseat_land_file))
- assertThat(hotseatSpecs.heightSpecs.size).isEqualTo(0)
-
- val expectedWidthSpecs =
- listOf(
- HotseatSpec(
- maxAvailableSize = 743.dpToPx(),
- specType = ResponsiveSpec.SpecType.WIDTH,
- hotseatQsbSpace = SizeSpec(0f),
- edgePadding = SizeSpec(48f.dpToPx())
- ),
- HotseatSpec(
- maxAvailableSize = 9999.dpToPx(),
- specType = ResponsiveSpec.SpecType.WIDTH,
- hotseatQsbSpace = SizeSpec(0f),
- edgePadding = SizeSpec(64f.dpToPx())
- ),
- )
-
- assertThat(hotseatSpecs.widthSpecs.size).isEqualTo(expectedWidthSpecs.size)
- assertThat(hotseatSpecs.widthSpecs[0]).isEqualTo(expectedWidthSpecs[0])
- assertThat(hotseatSpecs.widthSpecs[1]).isEqualTo(expectedWidthSpecs[1])
- }
-
- @Test(expected = IllegalStateException::class)
- fun parseInvalidFile_spaceIsNotFixedSize_throwsError() {
- HotseatSpecs.create(TestResourceHelper(context!!, TestR.xml.invalid_hotseat_file_case_1))
- }
-}
diff --git a/tests/src/com/android/launcher3/responsive/ResponsiveSpecsProviderTest.kt b/tests/src/com/android/launcher3/responsive/ResponsiveSpecsProviderTest.kt
new file mode 100644
index 0000000..7af0823
--- /dev/null
+++ b/tests/src/com/android/launcher3/responsive/ResponsiveSpecsProviderTest.kt
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.responsive
+
+import android.content.Context
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
+import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
+import com.android.launcher3.tests.R
+import com.android.launcher3.util.TestResourceHelper
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ResponsiveSpecsProviderTest : AbstractDeviceProfileTest() {
+ override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
+ val deviceSpec = deviceSpecs["tablet"]!!
+ var aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
+
+ @Before
+ fun setup() {
+ initializeVarsForPhone(deviceSpec)
+ }
+
+ @Test
+ fun parseValidFile() {
+ val resourceHelper = TestResourceHelper(context, R.xml.valid_responsive_spec_unsorted)
+ val provider = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Workspace)
+
+ // Validate Portrait
+ val aspectRatioPortrait = 1.0f
+ val portraitSpecs = provider.getSpecsByAspectRatio(aspectRatioPortrait)
+
+ val (expectedPortWidthSpecs, expectedPortHeightSpecs) = expectedPortraitSpecs()
+ validateSpecs(
+ portraitSpecs,
+ aspectRatioPortrait,
+ expectedPortWidthSpecs,
+ expectedPortHeightSpecs
+ )
+
+ // Validate Landscape
+ val aspectRatioLandscape = 1.051f
+ val landscapeSpecs = provider.getSpecsByAspectRatio(aspectRatioLandscape)
+
+ val (expectedLandWidthSpecs, expectedLandHeightSpecs) = expectedLandscapeSpecs()
+ validateSpecs(
+ landscapeSpecs,
+ aspectRatioLandscape,
+ expectedLandWidthSpecs,
+ expectedLandHeightSpecs
+ )
+
+ // Validate Extra Spec
+ val aspectRatioExtra = 10.1f
+ val extraSpecs = provider.getSpecsByAspectRatio(aspectRatioExtra)
+
+ val expectedOtherWidthSpecs =
+ listOf(
+ ResponsiveSpec(
+ maxAvailableSize = 9999.dpToPx(),
+ dimensionType = DimensionType.WIDTH,
+ specType = ResponsiveSpecType.Workspace,
+ startPadding = SizeSpec(1f.dpToPx()),
+ endPadding = SizeSpec(1f.dpToPx()),
+ gutter = SizeSpec(8f.dpToPx()),
+ cellSize = SizeSpec(ofRemainderSpace = .25f)
+ )
+ )
+
+ val expectedOtherHeightSpecs =
+ listOf(
+ ResponsiveSpec(
+ maxAvailableSize = 9999.dpToPx(),
+ dimensionType = DimensionType.HEIGHT,
+ specType = ResponsiveSpecType.Workspace,
+ startPadding = SizeSpec(2f.dpToPx()),
+ endPadding = SizeSpec(2f.dpToPx()),
+ gutter = SizeSpec(8f.dpToPx()),
+ cellSize = SizeSpec(ofRemainderSpace = .25f)
+ ),
+ )
+
+ validateSpecs(
+ extraSpecs,
+ aspectRatioExtra,
+ expectedOtherWidthSpecs,
+ expectedOtherHeightSpecs
+ )
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun parseValidFile_invalidAspectRatio_throwsError() {
+ val resourceHelper = TestResourceHelper(context, R.xml.valid_responsive_spec_unsorted)
+ val provider = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Workspace)
+ provider.getSpecsByAspectRatio(0f)
+ }
+
+ @Test(expected = InvalidResponsiveGridSpec::class)
+ fun parseInvalidFile_missingGroups_throwsError() {
+ val resourceHelper = TestResourceHelper(context, R.xml.invalid_responsive_spec_1)
+ ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Workspace)
+ }
+
+ @Test(expected = InvalidResponsiveGridSpec::class)
+ fun parseInvalidFile_partialGroups_throwsError() {
+ val resourceHelper = TestResourceHelper(context, R.xml.invalid_responsive_spec_2)
+ ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Workspace)
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun parseInvalidFile_invalidAspectRatio_throwsError() {
+ val resourceHelper = TestResourceHelper(context, R.xml.invalid_responsive_spec_3)
+ ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Workspace)
+ }
+
+ private fun validateSpecs(
+ specs: ResponsiveSpecGroup<ResponsiveSpec>,
+ expectedAspectRatio: Float,
+ expectedWidthSpecs: List<ResponsiveSpec>,
+ expectedHeightSpecs: List<ResponsiveSpec>
+ ) {
+ assertThat(specs.aspectRatio).isAtLeast(expectedAspectRatio)
+
+ assertThat(specs.widthSpecs.size).isEqualTo(expectedWidthSpecs.size)
+ specs.widthSpecs.forEachIndexed { index, responsiveSpec ->
+ assertThat(responsiveSpec).isEqualTo(expectedWidthSpecs[index])
+ }
+
+ assertThat(specs.heightSpecs.size).isEqualTo(expectedHeightSpecs.size)
+ specs.heightSpecs.forEachIndexed { index, responsiveSpec ->
+ assertThat(responsiveSpec).isEqualTo(expectedHeightSpecs[index])
+ }
+ }
+
+ private fun expectedPortraitSpecs(): Pair<List<ResponsiveSpec>, List<ResponsiveSpec>> {
+ val sizeSpec16 = SizeSpec(16f.dpToPx())
+ val expectedWidthSpecs =
+ listOf(
+ ResponsiveSpec(
+ maxAvailableSize = 9999.dpToPx(),
+ dimensionType = DimensionType.WIDTH,
+ specType = ResponsiveSpecType.Workspace,
+ startPadding = SizeSpec(22f.dpToPx()),
+ endPadding = SizeSpec(22f.dpToPx()),
+ gutter = sizeSpec16,
+ cellSize = SizeSpec(ofRemainderSpace = .25f)
+ )
+ )
+
+ val expectedHeightSpecs =
+ listOf(
+ ResponsiveSpec(
+ maxAvailableSize = 584.dpToPx(),
+ dimensionType = DimensionType.HEIGHT,
+ specType = ResponsiveSpecType.Workspace,
+ startPadding = SizeSpec(0f),
+ endPadding = SizeSpec(32f.dpToPx()),
+ gutter = sizeSpec16,
+ cellSize = SizeSpec(ofAvailableSpace = .15808f)
+ ),
+ ResponsiveSpec(
+ maxAvailableSize = 612.dpToPx(),
+ dimensionType = DimensionType.HEIGHT,
+ specType = ResponsiveSpecType.Workspace,
+ startPadding = SizeSpec(0f),
+ endPadding = SizeSpec(ofRemainderSpace = 1f),
+ gutter = sizeSpec16,
+ cellSize = SizeSpec(104f.dpToPx())
+ ),
+ ResponsiveSpec(
+ maxAvailableSize = 9999.dpToPx(),
+ dimensionType = DimensionType.HEIGHT,
+ specType = ResponsiveSpecType.Workspace,
+ startPadding = SizeSpec(8f.dpToPx()),
+ endPadding = SizeSpec(ofRemainderSpace = 1f),
+ gutter = sizeSpec16,
+ cellSize = SizeSpec(104f.dpToPx())
+ ),
+ )
+
+ return Pair(expectedWidthSpecs, expectedHeightSpecs)
+ }
+
+ private fun expectedLandscapeSpecs(): Pair<List<ResponsiveSpec>, List<ResponsiveSpec>> {
+ val sizeSpec12 = SizeSpec(12f.dpToPx())
+ val expectedWidthSpecs =
+ listOf(
+ ResponsiveSpec(
+ maxAvailableSize = 602.dpToPx(),
+ dimensionType = DimensionType.WIDTH,
+ specType = ResponsiveSpecType.Workspace,
+ startPadding = SizeSpec(0f.dpToPx()),
+ endPadding = SizeSpec(36f.dpToPx()),
+ gutter = sizeSpec12,
+ cellSize = SizeSpec(ofRemainderSpace = .25f)
+ ),
+ ResponsiveSpec(
+ maxAvailableSize = 716.dpToPx(),
+ dimensionType = DimensionType.WIDTH,
+ specType = ResponsiveSpecType.Workspace,
+ startPadding = SizeSpec(16f.dpToPx()),
+ endPadding = SizeSpec(64f.dpToPx()),
+ gutter = sizeSpec12,
+ cellSize = SizeSpec(ofRemainderSpace = .25f)
+ ),
+ ResponsiveSpec(
+ maxAvailableSize = 9999.dpToPx(),
+ dimensionType = DimensionType.WIDTH,
+ specType = ResponsiveSpecType.Workspace,
+ startPadding = SizeSpec(36f.dpToPx()),
+ endPadding = SizeSpec(80f.dpToPx()),
+ gutter = sizeSpec12,
+ cellSize = SizeSpec(ofRemainderSpace = .25f)
+ )
+ )
+
+ val expectedHeightSpecs =
+ listOf(
+ ResponsiveSpec(
+ maxAvailableSize = 371.dpToPx(),
+ dimensionType = DimensionType.HEIGHT,
+ specType = ResponsiveSpecType.Workspace,
+ startPadding = SizeSpec(0f),
+ endPadding = SizeSpec(24f.dpToPx()),
+ gutter = sizeSpec12,
+ cellSize = SizeSpec(ofRemainderSpace = .25f)
+ ),
+ ResponsiveSpec(
+ maxAvailableSize = 9999.dpToPx(),
+ dimensionType = DimensionType.HEIGHT,
+ specType = ResponsiveSpecType.Workspace,
+ startPadding = SizeSpec(0f),
+ endPadding = SizeSpec(34f.dpToPx()),
+ gutter = sizeSpec12,
+ cellSize = SizeSpec(ofRemainderSpace = .25f)
+ ),
+ )
+
+ return Pair(expectedWidthSpecs, expectedHeightSpecs)
+ }
+}
diff --git a/tests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt b/tests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt
index 0364069..9781645 100644
--- a/tests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt
+++ b/tests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt
@@ -21,6 +21,7 @@
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
import com.android.launcher3.tests.R as TestR
import com.android.launcher3.util.TestResourceHelper
import com.google.common.truth.Truth.assertThat
@@ -32,22 +33,30 @@
@RunWith(AndroidJUnit4::class)
class WorkspaceSpecsTest : AbstractDeviceProfileTest() {
override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context
+ val deviceSpec = deviceSpecs["phone"]!!
+ val aspectRatio = deviceSpec.naturalSize.first.toFloat() / deviceSpec.naturalSize.second
@Before
fun setup() {
- initializeVarsForPhone(deviceSpecs["phone"]!!)
+ initializeVarsForPhone(deviceSpec)
}
@Test
fun parseValidFile() {
val workspaceSpecs =
- WorkspaceSpecs.create(TestResourceHelper(context!!, TestR.xml.valid_workspace_file))
- assertThat(workspaceSpecs.heightSpecs.size).isEqualTo(3)
- assertThat(workspaceSpecs.heightSpecs[0].toString())
+ ResponsiveSpecsProvider.create(
+ TestResourceHelper(context, TestR.xml.valid_workspace_file),
+ ResponsiveSpecType.Workspace
+ )
+
+ val specs = workspaceSpecs.getSpecsByAspectRatio(aspectRatio)
+ assertThat(specs.heightSpecs.size).isEqualTo(3)
+ assertThat(specs.heightSpecs[0].toString())
.isEqualTo(
- "WorkspaceSpec(" +
+ "ResponsiveSpec(" +
"maxAvailableSize=1533, " +
- "specType=HEIGHT, " +
+ "dimensionType=HEIGHT, " +
+ "specType=Workspace, " +
"startPadding=SizeSpec(fixedSize=0.0, " +
"ofAvailableSpace=0.0, " +
"ofRemainderSpace=0.0, " +
@@ -70,11 +79,12 @@
"maxSize=2147483647)" +
")"
)
- assertThat(workspaceSpecs.heightSpecs[1].toString())
+ assertThat(specs.heightSpecs[1].toString())
.isEqualTo(
- "WorkspaceSpec(" +
+ "ResponsiveSpec(" +
"maxAvailableSize=1607, " +
- "specType=HEIGHT, " +
+ "dimensionType=HEIGHT, " +
+ "specType=Workspace, " +
"startPadding=SizeSpec(fixedSize=0.0, " +
"ofAvailableSpace=0.0, " +
"ofRemainderSpace=0.0, " +
@@ -97,11 +107,12 @@
"maxSize=2147483647)" +
")"
)
- assertThat(workspaceSpecs.heightSpecs[2].toString())
+ assertThat(specs.heightSpecs[2].toString())
.isEqualTo(
- "WorkspaceSpec(" +
+ "ResponsiveSpec(" +
"maxAvailableSize=26247, " +
- "specType=HEIGHT, " +
+ "dimensionType=HEIGHT, " +
+ "specType=Workspace, " +
"startPadding=SizeSpec(fixedSize=21.0, " +
"ofAvailableSpace=0.0, " +
"ofRemainderSpace=0.0, " +
@@ -124,12 +135,13 @@
"maxSize=2147483647)" +
")"
)
- assertThat(workspaceSpecs.widthSpecs.size).isEqualTo(1)
- assertThat(workspaceSpecs.widthSpecs[0].toString())
+ assertThat(specs.widthSpecs.size).isEqualTo(1)
+ assertThat(specs.widthSpecs[0].toString())
.isEqualTo(
- "WorkspaceSpec(" +
+ "ResponsiveSpec(" +
"maxAvailableSize=26247, " +
- "specType=WIDTH, " +
+ "dimensionType=WIDTH, " +
+ "specType=Workspace, " +
"startPadding=SizeSpec(fixedSize=58.0, " +
"ofAvailableSpace=0.0, " +
"ofRemainderSpace=0.0, " +
@@ -156,29 +168,33 @@
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_missingTag_throwsError() {
- WorkspaceSpecs.create(
- TestResourceHelper(context!!, TestR.xml.invalid_workspace_file_case_1)
+ ResponsiveSpecsProvider.create(
+ TestResourceHelper(context, TestR.xml.invalid_workspace_file_case_1),
+ ResponsiveSpecType.Workspace
)
}
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_moreThanOneValuePerTag_throwsError() {
- WorkspaceSpecs.create(
- TestResourceHelper(context!!, TestR.xml.invalid_workspace_file_case_2)
+ ResponsiveSpecsProvider.create(
+ TestResourceHelper(context, TestR.xml.invalid_workspace_file_case_2),
+ ResponsiveSpecType.Workspace
)
}
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_valueBiggerThan1_throwsError() {
- WorkspaceSpecs.create(
- TestResourceHelper(context!!, TestR.xml.invalid_workspace_file_case_3)
+ ResponsiveSpecsProvider.create(
+ TestResourceHelper(context, TestR.xml.invalid_workspace_file_case_3),
+ ResponsiveSpecType.Workspace
)
}
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_matchWorkspace_true_throwsError() {
- WorkspaceSpecs.create(
- TestResourceHelper(context!!, TestR.xml.invalid_workspace_file_case_4)
+ ResponsiveSpecsProvider.create(
+ TestResourceHelper(context, TestR.xml.invalid_workspace_file_case_4),
+ ResponsiveSpecType.Workspace
)
}
}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 9bfafcf..688f418 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -45,6 +45,7 @@
import android.system.OsConstants;
import android.util.Log;
+import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.BySelector;
@@ -104,12 +105,20 @@
private static boolean sDumpWasGenerated = false;
private static boolean sActivityLeakReported = false;
private static boolean sSeenKeyguard = false;
+ private static boolean sFirstTimeWaitingForWizard = true;
private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
protected LooperExecutor mMainThreadExecutor = MAIN_EXECUTOR;
- protected final UiDevice mDevice = UiDevice.getInstance(getInstrumentation());
- protected final LauncherInstrumentation mLauncher = new LauncherInstrumentation();
+ protected final UiDevice mDevice = getUiDevice();
+ protected final LauncherInstrumentation mLauncher = createLauncherInstrumentation();
+
+ @NonNull
+ private static LauncherInstrumentation createLauncherInstrumentation() {
+ waitForSetupWizardDismissal(); // precondition for creating LauncherInstrumentation
+ return new LauncherInstrumentation();
+ }
+
protected Context mTargetContext;
protected String mTargetPackage;
private int mLauncherPid;
@@ -121,7 +130,10 @@
/** Detects activity leaks and throws an exception if a leak is found. */
public static void checkDetectedLeaks(LauncherInstrumentation launcher,
- boolean requireOneActiveActivity) {
+ boolean requireOneActiveActivityUnused) {
+ final boolean requireOneActiveActivity =
+ false; // workaround for leaks when there is an unexpected Recents activity
+
if (sActivityLeakReported) return;
// Check whether activity leak detector has found leaked activities.
@@ -160,7 +172,7 @@
if (TestHelpers.isInLauncherProcess()) {
Debug.dumpHprofData(fileName);
} else {
- final UiDevice device = UiDevice.getInstance(getInstrumentation());
+ final UiDevice device = getUiDevice();
device.executeShellCommand(
"am dumpheap " + device.getLauncherPackageName() + " " + fileName);
}
@@ -248,13 +260,6 @@
public void setUp() throws Exception {
mLauncher.onTestStart();
- waitForSetupWizardDismissal();
- if (TestStabilityRule.isPresubmit()) {
- aggressivelyUnlockSysUi();
- } else {
- verifyKeyguardInvisible();
- }
-
final String launcherPackageName = mDevice.getLauncherPackageName();
try {
final Context context = InstrumentationRegistry.getContext();
@@ -285,23 +290,40 @@
}
}
- verifyKeyguardInvisible();
+ onTestStart();
}
- private boolean hasSystemUiObject(String resId) {
- return mDevice.hasObject(By.res(SYSTEMUI_PACKAGE, resId));
+ /** Method that should be called when a test starts. */
+ public static void onTestStart() {
+ waitForSetupWizardDismissal();
+
+ if (TestStabilityRule.isPresubmit()) {
+ aggressivelyUnlockSysUi();
+ } else {
+ verifyKeyguardInvisible();
+ }
}
- // Seeing if this will decrease: b/303755862
- void aggressivelyUnlockSysUi() {
+ private static boolean hasSystemUiObject(String resId) {
+ return getUiDevice().hasObject(
+ By.res(SYSTEMUI_PACKAGE, resId));
+ }
+
+ @NonNull
+ private static UiDevice getUiDevice() {
+ return UiDevice.getInstance(getInstrumentation());
+ }
+
+ private static void aggressivelyUnlockSysUi() {
+ final UiDevice device = getUiDevice();
for (int i = 0; i < 10 && hasSystemUiObject("keyguard_status_view"); ++i) {
Log.d(TAG, "Before attempting to unlock the phone");
try {
- mDevice.executeShellCommand("input keyevent 82");
+ device.executeShellCommand("input keyevent 82");
} catch (IOException e) {
throw new RuntimeException(e);
}
- mDevice.waitForIdle();
+ device.waitForIdle();
}
Assert.assertTrue("Keyguard still visible",
TestHelpers.wait(
@@ -309,21 +331,13 @@
Log.d(TAG, "Keyguard is not visible");
}
- // b/309008042
- private static boolean sFirstTimeWaitingForWizard = true;
-
- // b/309008042
- static {
- waitForSetupWizardDismissal();
- }
-
- // b/309008042
- // TODO(309471958) Productize killing/dismissal of setup wizard.
/** Waits for setup wizard to go away. */
- public static void waitForSetupWizardDismissal() {
- if (sFirstTimeWaitingForWizard && TestStabilityRule.isPresubmit()) {
+ private static void waitForSetupWizardDismissal() {
+ if (!TestStabilityRule.isPresubmit()) return;
+
+ if (sFirstTimeWaitingForWizard) {
try {
- UiDevice.getInstance(getInstrumentation()).executeShellCommand(
+ getUiDevice().executeShellCommand(
"am force-stop com.google.android.setupwizard");
} catch (IOException e) {
throw new RuntimeException(e);
@@ -334,12 +348,10 @@
Until.gone(By.pkg("com.google.android.setupwizard").depth(0)),
sFirstTimeWaitingForWizard ? 120000 : 0);
sFirstTimeWaitingForWizard = false;
- // b/309496273
-// Assert.assertTrue("Setup wizard is still visible",
-// wizardDismissed);
+ Assert.assertTrue("Setup wizard is still visible", wizardDismissed);
}
- public static void verifyKeyguardInvisible() {
+ private static void verifyKeyguardInvisible() {
final boolean keyguardAlreadyVisible = sSeenKeyguard;
sSeenKeyguard = sSeenKeyguard
@@ -453,7 +465,6 @@
// flakiness.
protected void waitForLauncherCondition(
String message, Function<Launcher, Boolean> condition, long timeout) {
- waitForSetupWizardDismissal();
verifyKeyguardInvisible();
if (!TestHelpers.isInLauncherProcess()) return;
Wait.atMost(message, () -> getFromLauncher(condition), timeout, mLauncher);
diff --git a/tests/src/com/android/launcher3/ui/ActivityAllAppsContainerViewTest.java b/tests/src/com/android/launcher3/ui/ActivityAllAppsContainerViewTest.java
index ba416ae..3411fc1 100644
--- a/tests/src/com/android/launcher3/ui/ActivityAllAppsContainerViewTest.java
+++ b/tests/src/com/android/launcher3/ui/ActivityAllAppsContainerViewTest.java
@@ -18,14 +18,19 @@
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -34,15 +39,20 @@
import com.android.launcher3.allapps.WorkProfileManager;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.pm.UserCache;
import com.android.launcher3.util.ActivityContextWrapper;
+import com.android.launcher3.util.UserIconInfo;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.Arrays;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class ActivityAllAppsContainerViewTest {
@@ -50,19 +60,38 @@
private static final UserHandle WORK_HANDLE = new UserHandle(13);
@Mock
private StatsLogManager mStatsLogManager;
+ @Mock
+ private UserCache mUserCache;
+ @Mock
+ private UserManager mUserManager;
private AppInfo[] mWorkAppInfo;
private ActivityAllAppsContainerView<?> mActivityAllAppsContainerView;
private WorkProfileManager mWorkManager;
+ private Context mContext;
+
+ @Rule public final SetFlagsRule mSetFlagsRule = getFlagsRule();
+
+ private SetFlagsRule getFlagsRule() {
+ SetFlagsRule flagsRule = new SetFlagsRule();
+ flagsRule.initAllFlagsToReleaseConfigDefault();
+ return flagsRule;
+ }
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- Context context = new ActivityContextWrapper(getApplicationContext());
- mActivityAllAppsContainerView = new ActivityAllAppsContainerView(context);
- mWorkManager = new WorkProfileManager(context.getSystemService(UserManager.class),
- mActivityAllAppsContainerView, mStatsLogManager);
+ mContext = new ActivityContextWrapper(getApplicationContext());
+ mActivityAllAppsContainerView = new ActivityAllAppsContainerView(mContext);
+ when(mUserCache.getUserProfiles())
+ .thenReturn(Arrays.asList(Process.myUserHandle(), WORK_HANDLE));
+ when(mUserCache.getUserInfo(Process.myUserHandle()))
+ .thenReturn(new UserIconInfo(Process.myUserHandle(), 0));
+ when(mUserCache.getUserInfo(WORK_HANDLE))
+ .thenReturn(new UserIconInfo(WORK_HANDLE, 1));
+ mWorkManager = new WorkProfileManager(mUserManager, mActivityAllAppsContainerView,
+ mStatsLogManager, mUserCache);
mActivityAllAppsContainerView.setWorkManager(mWorkManager);
- ComponentName componentName = new ComponentName(context,
+ ComponentName componentName = new ComponentName(mContext,
"com.android.launcher3.tests.Activity" + "Gmail");
AppInfo gmailWorkAppInfo = new AppInfo(componentName, "Gmail", WORK_HANDLE, new Intent());
mWorkAppInfo = new AppInfo[]{gmailWorkAppInfo};
@@ -85,4 +114,22 @@
assertThat(mActivityAllAppsContainerView.shouldShowTabs()).isEqualTo(true);
}
+
+ @Test
+ public void testWorkProfileEnabled_requestQuietModeCalledCorrectly() throws Exception {
+ /* Setup */
+ when(mUserManager.requestQuietModeEnabled(false, WORK_HANDLE))
+ .thenReturn(true);
+
+ /* Execution */
+ mWorkManager.setWorkProfileEnabled(true);
+
+ /* Assertion */
+ awaitTasksCompleted();
+ Mockito.verify(mUserManager).requestQuietModeEnabled(false, WORK_HANDLE);
+ }
+
+ private static void awaitTasksCompleted() throws Exception {
+ UI_HELPER_EXECUTOR.submit(() -> null).get();
+ }
}
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index 7db3161..32793cc 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -23,6 +23,8 @@
import static com.android.launcher3.provider.LauncherDbUtils.itemIdMatch;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.WidgetUtils.createWidgetInfo;
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -53,6 +55,7 @@
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.TestViewHelpers;
import com.android.launcher3.util.rule.ShellCommandRule;
+import com.android.launcher3.util.rule.TestStabilityRule;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.WidgetManagerHelper;
@@ -139,6 +142,7 @@
}
@Test
+ @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/310242894
public void testPendingWidget_withConfigScreen() {
// A non-restored widget with config screen get bound and shows a 'Click to setup' UI.
// Do not bind the widget
@@ -188,6 +192,7 @@
}
@Test
+ @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/310242894
public void testPendingWidget_notRestored_brokenInstall() {
// A widget which is was being installed once, even if its not being
// installed at the moment is not removed.
diff --git a/tests/src/com/android/launcher3/util/TestResourceHelper.kt b/tests/src/com/android/launcher3/util/TestResourceHelper.kt
index cf80ece..b4d3ba8 100644
--- a/tests/src/com/android/launcher3/util/TestResourceHelper.kt
+++ b/tests/src/com/android/launcher3/util/TestResourceHelper.kt
@@ -32,6 +32,8 @@
styleId.contentEquals(R.styleable.WorkspaceSpec) -> TestR.styleable.WorkspaceSpec
styleId.contentEquals(R.styleable.FolderSpec) -> TestR.styleable.FolderSpec
styleId.contentEquals(R.styleable.AllAppsSpec) -> TestR.styleable.AllAppsSpec
+ styleId.contentEquals(R.styleable.ResponsiveSpecGroup) ->
+ TestR.styleable.ResponsiveSpecGroup
else -> styleId.clone()
}
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
index 62d70ad..10b428a 100644
--- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -59,8 +59,9 @@
throw new AssertionError(
"Launcher received events not sent by the test. This may mean "
+ "that the touch screen of the lab device has sent false"
- + " events. See the logcat for TaplEvents tag and look "
- + "for events with deviceId != -1");
+ + " events. See the logcat for "
+ + "TaplEvents|LauncherEvents|TaplTarget tag and look for "
+ + "events with deviceId != -1");
}
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 17169b3..e30885b 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -564,6 +564,9 @@
if (hasSystemLauncherObject(OVERVIEW_RES_ID)) return "Overview";
if (hasLauncherObject(WORKSPACE_RES_ID)) return "Workspace";
if (hasLauncherObject(APPS_RES_ID)) return "AllApps";
+ if (mDevice.hasObject(By.pkg(getLauncherPackageName()).depth(0))) {
+ return "<Launcher in invalid state>";
+ }
return "LaunchedApp (" + getVisiblePackages() + ")";
}
@@ -2063,6 +2066,7 @@
}
// TODO(b/270393900): Remove with ENABLE_ALL_APPS_SEARCH_IN_TASKBAR flag cleanup.
+
/** Refreshes the known overview target in TIS. */
public void refreshOverviewTarget() {
getTestInfo(TestProtocol.REQUEST_REFRESH_OVERVIEW_TARGET);