Merge "Ensure the overflow is added first to the bubble bar" into udc-qpr-dev
diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml
index 63f192c..1b5b0ee 100644
--- a/quickstep/res/values/colors.xml
+++ b/quickstep/res/values/colors.xml
@@ -25,9 +25,17 @@
<!-- Taskbar -->
<color name="taskbar_nav_icon_selection_ripple">#E0E0E0</color>
+ <color name="taskbar_nav_icon_light_color_on_home">#ffffff</color>
+ <!-- The dark navigation button color is only used in the rare cases that taskbar isn't drawing
+ its background and the underlying app has requested dark buttons. -->
+ <color name="taskbar_nav_icon_dark_color_on_home">#99000000</color>
<color name="taskbar_stashed_handle_light_color">#EBffffff</color>
<color name="taskbar_stashed_handle_dark_color">#99000000</color>
+ <!-- Floating rotation button -->
+ <color name="floating_rotation_button_light_color">#ffffff</color>
+ <color name="floating_rotation_button_dark_color">#99000000</color>
+
<!-- Gesture navigation tutorial -->
<color name="gesture_tutorial_back_arrow_color">#FFFFFFFF</color>
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index ba6f165..35b9957 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -312,6 +312,8 @@
.getTaskbarNavButtonTranslationYForInAppDisplay()
.updateValue(mLauncher.getDeviceProfile().getTaskbarOffsetY()
* mTaskbarInAppDisplayProgress.value);
+ mControllers.navbarButtonsViewController
+ .getOnTaskbarBackgroundNavButtonColorOverride().updateValue(progress);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 9a9e0ba..10ae97b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -148,8 +148,8 @@
// Used for IME+A11Y buttons
private final ViewGroup mEndContextualContainer;
private final ViewGroup mStartContextualContainer;
- private final int mLightIconColor;
- private final int mDarkIconColor;
+ private final int mLightIconColorOnHome;
+ private final int mDarkIconColorOnHome;
/** Color to use for navigation bar buttons, if they are on on a Taskbar surface background. */
private final int mOnBackgroundIconColor;
@@ -205,9 +205,11 @@
mEndContextualContainer = mNavButtonsView.findViewById(R.id.end_contextual_buttons);
mStartContextualContainer = mNavButtonsView.findViewById(R.id.start_contextual_buttons);
- mLightIconColor = context.getColor(R.color.taskbar_nav_icon_light_color);
- mDarkIconColor = context.getColor(R.color.taskbar_nav_icon_dark_color);
- mOnBackgroundIconColor = Utilities.isDarkTheme(context) ? mLightIconColor : mDarkIconColor;
+ mLightIconColorOnHome = context.getColor(R.color.taskbar_nav_icon_light_color_on_home);
+ mDarkIconColorOnHome = context.getColor(R.color.taskbar_nav_icon_dark_color_on_home);
+ mOnBackgroundIconColor = Utilities.isDarkTheme(context)
+ ? context.getColor(R.color.taskbar_nav_icon_light_color)
+ : context.getColor(R.color.taskbar_nav_icon_dark_color);
}
/**
@@ -630,18 +632,20 @@
private void updateNavButtonColor() {
final ArgbEvaluator argbEvaluator = ArgbEvaluator.getInstance();
- final int sysUiNavButtonIconColor = (int) argbEvaluator.evaluate(
+ final int sysUiNavButtonIconColorOnHome = (int) argbEvaluator.evaluate(
mTaskbarNavButtonDarkIntensity.value,
- mLightIconColor,
- mDarkIconColor);
+ mLightIconColorOnHome,
+ mDarkIconColorOnHome);
+
// Override the color from framework if nav buttons are over an opaque Taskbar surface.
final int iconColor = (int) argbEvaluator.evaluate(
mOnBackgroundNavButtonColorOverrideMultiplier.value
* Math.max(
mOnTaskbarBackgroundNavButtonColorOverride.value,
mSlideInViewVisibleNavButtonColorOverride.value),
- sysUiNavButtonIconColor,
+ sysUiNavButtonIconColorOnHome,
mOnBackgroundIconColor);
+
for (ImageView button : mAllButtons) {
button.setImageTintList(ColorStateList.valueOf(iconColor));
}
@@ -928,8 +932,6 @@
pw.println(prefix + "NavbarButtonsViewController:");
pw.println(prefix + "\tmState=" + getStateString(mState));
- pw.println(prefix + "\tmLightIconColor=" + Integer.toHexString(mLightIconColor));
- pw.println(prefix + "\tmDarkIconColor=" + Integer.toHexString(mDarkIconColor));
pw.println(prefix + "\tmFloatingRotationButtonBounds=" + mFloatingRotationButtonBounds);
pw.println(prefix + "\tmSysuiStateFlags=" + QuickStepContract.getSystemUiStateString(
mSysuiStateFlags));
@@ -940,6 +942,14 @@
+ mTaskbarNavButtonTranslationYForInAppDisplay.value);
pw.println(prefix + "\t\tmTaskbarNavButtonTranslationYForIme="
+ mTaskbarNavButtonTranslationYForIme.value);
+ pw.println(prefix + "\t\tmTaskbarNavButtonDarkIntensity="
+ + mTaskbarNavButtonDarkIntensity.value);
+ pw.println(prefix + "\t\tmSlideInViewVisibleNavButtonColorOverride="
+ + mSlideInViewVisibleNavButtonColorOverride.value);
+ pw.println(prefix + "\t\tmOnTaskbarBackgroundNavButtonColorOverride="
+ + mOnTaskbarBackgroundNavButtonColorOverride.value);
+ pw.println(prefix + "\t\tmOnBackgroundNavButtonColorOverrideMultiplier="
+ + mOnBackgroundNavButtonColorOverrideMultiplier.value);
}
private static String getStateString(int flags) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 6fddd4b..31af1ce 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -49,7 +49,6 @@
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.Process;
-import android.os.SystemProperties;
import android.os.Trace;
import android.provider.Settings;
import android.util.Log;
@@ -128,8 +127,6 @@
private static final String IME_DRAWS_IME_NAV_BAR_RES_NAME = "config_imeDrawsImeNavBar";
- private static final boolean ENABLE_THREE_BUTTON_TASKBAR =
- SystemProperties.getBoolean("persist.debug.taskbar_three_button", false);
private static final String TAG = "TaskbarActivityContext";
private static final String WINDOW_TITLE = "Taskbar";
@@ -169,30 +166,27 @@
TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider
unfoldTransitionProgressProvider) {
super(windowContext);
+
+ applyDeviceProfile(launcherDp);
+
final Resources resources = getResources();
- matchDeviceProfile(launcherDp, getResources());
-
- mNavMode = DisplayController.getNavigationMode(windowContext);
mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, resources, false);
mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
() -> getPackageManager().isSafeMode());
+
+ // TODO(b/244231596) For shared Taskbar window, update this value in applyDeviceProfile()
+ // instead so to get correct value when recreating the taskbar
SettingsCache settingsCache = SettingsCache.INSTANCE.get(this);
mIsUserSetupComplete = settingsCache.getValue(
Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), 0);
- mIsNavBarForceVisible = settingsCache.getValue(
- Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE), 0);
-
- // TODO(b/244231596) For shared Taskbar window, update this value in init() instead so
- // to get correct value when recreating the taskbar
mIsNavBarKidsMode = settingsCache.getValue(
Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE), 0);
+ mIsNavBarForceVisible = mIsNavBarKidsMode;
// Get display and corners first, as views might use them in constructor.
Display display = windowContext.getDisplay();
- Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY
- ? windowContext.getApplicationContext()
- : windowContext.getApplicationContext().createDisplayContext(display);
+ Context c = getApplicationContext();
mWindowManager = c.getSystemService(WindowManager.class);
mLeftCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT);
mRightCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT);
@@ -232,8 +226,8 @@
? new DesktopNavbarButtonsViewController(this, navButtonsView)
: new NavbarButtonsViewController(this, navButtonsView),
new RotationButtonController(this,
- c.getColor(R.color.taskbar_nav_icon_light_color),
- c.getColor(R.color.taskbar_nav_icon_dark_color),
+ c.getColor(R.color.floating_rotation_button_light_color),
+ c.getColor(R.color.floating_rotation_button_dark_color),
R.drawable.ic_sysbar_rotate_button_ccw_start_0,
R.drawable.ic_sysbar_rotate_button_ccw_start_90,
R.drawable.ic_sysbar_rotate_button_cw_start_0,
@@ -267,6 +261,38 @@
bubbleControllersOptional);
}
+ /** Updates {@link DeviceProfile} instances for any Taskbar windows. */
+ public void updateDeviceProfile(DeviceProfile launcherDp) {
+ applyDeviceProfile(launcherDp);
+
+ mControllers.taskbarOverlayController.updateLauncherDeviceProfile(launcherDp);
+ AbstractFloatingView.closeAllOpenViewsExcept(this, false, TYPE_REBIND_SAFE);
+ // Reapply fullscreen to take potential new screen size into account.
+ setTaskbarWindowFullscreen(mIsFullscreen);
+
+ dispatchDeviceProfileChanged();
+ }
+
+ /**
+ * Copy the original DeviceProfile, match the number of hotseat icons and qsb width and update
+ * the icon size
+ */
+ private void applyDeviceProfile(DeviceProfile originDeviceProfile) {
+ mDeviceProfile = originDeviceProfile.toBuilder(this)
+ .withDimensionsOverride(deviceProfile -> {
+ // Taskbar should match the number of icons of hotseat
+ deviceProfile.numShownHotseatIcons = originDeviceProfile.numShownHotseatIcons;
+ // Same QSB width to have a smooth animation
+ deviceProfile.hotseatQsbWidth = originDeviceProfile.hotseatQsbWidth;
+
+ // Update icon size
+ deviceProfile.iconSizePx = deviceProfile.taskbarIconSize;
+ deviceProfile.updateIconSize(1f, getResources());
+ }).build();
+ mNavMode = DisplayController.getNavigationMode(this);
+ }
+
+
public void init(@NonNull TaskbarSharedState sharedState) {
mLastRequestedNonFullscreenHeight = getDefaultTaskbarWindowHeight();
mWindowLayoutParams =
@@ -308,19 +334,6 @@
return mDeviceProfile;
}
- /** Updates {@link DeviceProfile} instances for any Taskbar windows. */
- public void updateDeviceProfile(DeviceProfile launcherDp, NavigationMode navMode) {
- mNavMode = navMode;
- mControllers.taskbarOverlayController.updateLauncherDeviceProfile(launcherDp);
- matchDeviceProfile(launcherDp, getResources());
-
- AbstractFloatingView.closeAllOpenViewsExcept(this, false, TYPE_REBIND_SAFE);
- // Reapply fullscreen to take potential new screen size into account.
- setTaskbarWindowFullscreen(mIsFullscreen);
-
- dispatchDeviceProfileChanged();
- }
-
@Override
public void dispatchDeviceProfileChanged() {
super.dispatchDeviceProfileChanged();
@@ -329,24 +342,6 @@
}
/**
- * Copy the original DeviceProfile, match the number of hotseat icons and qsb width and update
- * the icon size
- */
- private void matchDeviceProfile(DeviceProfile originDeviceProfile, Resources resources) {
- mDeviceProfile = originDeviceProfile.toBuilder(this)
- .withDimensionsOverride(deviceProfile -> {
- // Taskbar should match the number of icons of hotseat
- deviceProfile.numShownHotseatIcons = originDeviceProfile.numShownHotseatIcons;
- // Same QSB width to have a smooth animation
- deviceProfile.hotseatQsbWidth = originDeviceProfile.hotseatQsbWidth;
-
- // Update icon size
- deviceProfile.iconSizePx = deviceProfile.taskbarIconSize;
- deviceProfile.updateIconSize(1f, resources);
- }).build();
- }
-
- /**
* Returns the View bounds of transient taskbar.
*/
public Rect getTransientTaskbarBounds() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
index 2517ff6..70999e7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
@@ -41,8 +41,10 @@
public static final int FLAG_AUTOHIDE_SUSPEND_TOUCHING = 1 << 2;
// Taskbar EDU overlay is open above the Taskbar. */
public static final int FLAG_AUTOHIDE_SUSPEND_EDU_OPEN = 1 << 3;
- // Taskbar in immersive mode in overview
+ // Taskbar is in immersive mode in overview
public static final int FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER = 1 << 4;
+ // Transient Taskbar is temporarily unstashed (pending a timeout).
+ public static final int FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR = 1 << 5;
@IntDef(flag = true, value = {
FLAG_AUTOHIDE_SUSPEND_FULLSCREEN,
@@ -50,6 +52,7 @@
FLAG_AUTOHIDE_SUSPEND_TOUCHING,
FLAG_AUTOHIDE_SUSPEND_EDU_OPEN,
FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER,
+ FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AutohideSuspendFlag {}
@@ -85,20 +88,30 @@
boolean isSuspended = isSuspended();
mSystemUiProxy.notifyTaskbarAutohideSuspend(isSuspended);
- mActivity.onTransientAutohideSuspendFlagChanged(isSuspended);
+ mActivity.onTransientAutohideSuspendFlagChanged(isTransientTaskbarStashingSuspended());
}
/**
* Returns true iff taskbar autohide is currently suspended.
*/
- public boolean isSuspended() {
+ private boolean isSuspended() {
return mAutohideSuspendFlags != 0;
}
- public boolean isSuspendedForTransientTaskbarInOverview() {
+ /**
+ * Returns whether Transient Taskbar should avoid auto-stashing in Launcher(Overview).
+ */
+ public boolean isSuspendedForTransientTaskbarInLauncher() {
return (mAutohideSuspendFlags & FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER) != 0;
}
+ /**
+ * Returns whether Transient Taskbar should avoid auto-stashing.
+ */
+ public boolean isTransientTaskbarStashingSuspended() {
+ return (mAutohideSuspendFlags & ~FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR) != 0;
+ }
+
@Override
public void dumpLogs(String prefix, PrintWriter pw) {
pw.println(prefix + "TaskbarAutohideSuspendController:");
@@ -115,6 +128,8 @@
appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_EDU_OPEN, "FLAG_AUTOHIDE_SUSPEND_EDU_OPEN");
appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER,
"FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER");
+ appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR,
+ "FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR");
return str.toString();
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 38d34fd..8f3898f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -22,8 +22,6 @@
import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING;
import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING_KEY;
-import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
-import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
import static com.android.launcher3.util.DisplayController.TASKBAR_NOT_DESTROYED_TAG;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
@@ -51,6 +49,7 @@
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.InvariantDeviceProfile.OnIDPChangeListener;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.anim.AnimatorPlaybackController;
@@ -58,8 +57,6 @@
import com.android.launcher3.taskbar.unfold.NonDestroyableScopedUnfoldTransitionProgressProvider;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
-import com.android.launcher3.util.DisplayController;
-import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.util.SimpleBroadcastReceiver;
import com.android.quickstep.RecentsActivity;
@@ -79,6 +76,22 @@
private static final String TAG = "TaskbarManager";
private static final boolean DEBUG = false;
+ /**
+ * All the configurations which do not initiate taskbar recreation.
+ * This includes all the configurations defined in Launcher's manifest entry and
+ * ActivityController#filterConfigChanges
+ */
+ private static final int SKIP_RECREATE_CONFIG_CHANGES = ActivityInfo.CONFIG_WINDOW_CONFIGURATION
+ | ActivityInfo.CONFIG_KEYBOARD
+ | ActivityInfo.CONFIG_KEYBOARD_HIDDEN
+ | ActivityInfo.CONFIG_MCC
+ | ActivityInfo.CONFIG_MNC
+ | ActivityInfo.CONFIG_NAVIGATION
+ | ActivityInfo.CONFIG_ORIENTATION
+ | ActivityInfo.CONFIG_SCREEN_SIZE
+ | 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);
@@ -89,12 +102,11 @@
Settings.Secure.NAV_BAR_KIDS_MODE);
private final Context mContext;
- private final DisplayController mDisplayController;
private final TaskbarNavButtonController mNavButtonController;
- private final SettingsCache.OnChangeListener mUserSetupCompleteListener;
- private final SettingsCache.OnChangeListener mNavBarKidsModeListener;
private final ComponentCallbacks mComponentCallbacks;
- private final SimpleBroadcastReceiver mShutdownReceiver;
+
+ private final SimpleBroadcastReceiver mShutdownReceiver =
+ new SimpleBroadcastReceiver(i -> destroyExistingTaskbar());
// The source for this provider is set when Launcher is available
// We use 'non-destroyable' version here so the original provider won't be destroyed
@@ -102,7 +114,6 @@
// It's destruction/creation will be managed by the activity.
private final ScopedUnfoldTransitionProgressProvider mUnfoldProgressProvider =
new NonDestroyableScopedUnfoldTransitionProgressProvider();
- private NavigationMode mNavMode;
private TaskbarActivityContext mTaskbarActivityContext;
private StatefulActivity mActivity;
@@ -113,19 +124,11 @@
private final TaskbarSharedState mSharedState = new TaskbarSharedState();
/**
- * We use WindowManager's ComponentCallbacks() for most of the config changes, however for
- * navigation mode, that callback gets called too soon, before it's internal navigation mode
- * reflects the current one.
- * DisplayController's callback is delayed enough to get the correct nav mode value
- *
- * We also use density change here because DeviceProfile has had a chance to update it's state
- * whereas density for component callbacks registered in this class don't update DeviceProfile.
- * Confused? Me too. Make it less confusing (TODO: b/227669780)
- *
- * Flags used with {@link #mDispInfoChangeListener}
+ * We use WindowManager's ComponentCallbacks() for internal UI changes (similar to an Activity)
+ * which comes via a different channel
*/
- private static final int CHANGE_FLAGS = CHANGE_NAVIGATION_MODE | CHANGE_DENSITY;
- private final DisplayController.DisplayInfoChangeListener mDispInfoChangeListener;
+ private final OnIDPChangeListener mIdpChangeListener = c -> recreateTaskbar();
+ private final SettingsCache.OnChangeListener mOnSettingsChangeListener = c -> recreateTaskbar();
private boolean mUserUnlocked = false;
@@ -167,15 +170,11 @@
@SuppressLint("WrongConstant")
public TaskbarManager(TouchInteractionService service) {
- mDisplayController = DisplayController.INSTANCE.get(service);
Display display =
service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
mContext = service.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null);
mNavButtonController = new TaskbarNavButtonController(service,
SystemUiProxy.INSTANCE.get(mContext), new Handler());
- mUserSetupCompleteListener = isUserSetupComplete -> recreateTaskbar();
- mNavBarKidsModeListener = isNavBarKidsMode -> recreateTaskbar();
- // TODO(b/227669780): Consolidate this w/ DisplayController callbacks
mComponentCallbacks = new ComponentCallbacks() {
private Configuration mOldConfig = mContext.getResources().getConfiguration();
@@ -186,80 +185,42 @@
DeviceProfile dp = mUserUnlocked
? LauncherAppState.getIDP(mContext).getDeviceProfile(mContext)
: null;
- int configDiff = mOldConfig.diff(newConfig);
- int configDiffForRecreate = configDiff;
- int configsRequiringRecreate = ActivityInfo.CONFIG_ASSETS_PATHS
- | ActivityInfo.CONFIG_LAYOUT_DIRECTION | ActivityInfo.CONFIG_UI_MODE
- | ActivityInfo.CONFIG_SCREEN_SIZE;
- if ((configDiff & ActivityInfo.CONFIG_SCREEN_SIZE) != 0
- && mTaskbarActivityContext != null && dp != null
- && !isPhoneMode(dp)) {
- // Additional check since this callback gets fired multiple times w/o
- // screen size changing, or when simply rotating the device.
- // In the case of phone device rotation, we do want to call recreateTaskbar()
- DeviceProfile oldDp = mTaskbarActivityContext.getDeviceProfile();
- boolean isOrientationChange =
- (configDiff & ActivityInfo.CONFIG_ORIENTATION) != 0;
+ int configDiff = mOldConfig.diff(newConfig) & ~SKIP_RECREATE_CONFIG_CHANGES;
- int newOrientation = newConfig.windowConfiguration.getRotation();
- int oldOrientation = mOldConfig.windowConfiguration.getRotation();
- int oldWidth = isOrientationChange ? oldDp.heightPx : oldDp.widthPx;
- int oldHeight = isOrientationChange ? oldDp.widthPx : oldDp.heightPx;
-
- if ((dp.widthPx == oldWidth && dp.heightPx == oldHeight)
- || (newOrientation == oldOrientation)) {
- configDiffForRecreate &= ~ActivityInfo.CONFIG_SCREEN_SIZE;
- }
- }
if ((configDiff & ActivityInfo.CONFIG_UI_MODE) != 0) {
// Only recreate for theme changes, not other UI mode changes such as docking.
int oldUiNightMode = (mOldConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK);
int newUiNightMode = (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK);
if (oldUiNightMode == newUiNightMode) {
- configDiffForRecreate &= ~ActivityInfo.CONFIG_UI_MODE;
+ configDiff &= ~ActivityInfo.CONFIG_UI_MODE;
}
}
debugWhyTaskbarNotDestroyed("ComponentCallbacks#onConfigurationChanged() "
- + "configDiffForRecreate="
- + Configuration.configurationDiffToString(configDiffForRecreate));
- if ((configDiffForRecreate & configsRequiringRecreate) != 0) {
+ + "configDiff=" + Configuration.configurationDiffToString(configDiff));
+ if (configDiff != 0 || mTaskbarActivityContext == null) {
recreateTaskbar();
} else {
// Config change might be handled without re-creating the taskbar
- if (mTaskbarActivityContext != null) {
- if (dp != null && !isTaskbarPresent(dp)) {
- destroyExistingTaskbar();
- } else {
- if (dp != null && isTaskbarPresent(dp)) {
- mTaskbarActivityContext.updateDeviceProfile(dp, mNavMode);
- }
- mTaskbarActivityContext.onConfigurationChanged(configDiff);
+ if (dp != null && !isTaskbarPresent(dp)) {
+ destroyExistingTaskbar();
+ } else {
+ if (dp != null && isTaskbarPresent(dp)) {
+ mTaskbarActivityContext.updateDeviceProfile(dp);
}
+ mTaskbarActivityContext.onConfigurationChanged(configDiff);
}
}
- mOldConfig = newConfig;
+ mOldConfig = new Configuration(newConfig);
}
@Override
public void onLowMemory() { }
};
- mShutdownReceiver = new SimpleBroadcastReceiver(i ->
- destroyExistingTaskbar());
- mDispInfoChangeListener = (context, info, flags) -> {
- if ((flags & CHANGE_FLAGS) != 0) {
- mNavMode = info.navigationMode;
- recreateTaskbar();
- }
- debugWhyTaskbarNotDestroyed("DisplayInfoChangeListener#"
- + mDisplayController.getChangeFlagsString(flags));
- };
- mNavMode = mDisplayController.getInfo().navigationMode;
- mDisplayController.addChangeListener(mDispInfoChangeListener);
- SettingsCache.INSTANCE.get(mContext).register(USER_SETUP_COMPLETE_URI,
- mUserSetupCompleteListener);
- SettingsCache.INSTANCE.get(mContext).register(NAV_BAR_KIDS_MODE,
- mNavBarKidsModeListener);
+ SettingsCache.INSTANCE.get(mContext)
+ .register(USER_SETUP_COMPLETE_URI, mOnSettingsChangeListener);
+ SettingsCache.INSTANCE.get(mContext)
+ .register(NAV_BAR_KIDS_MODE, mOnSettingsChangeListener);
mContext.registerComponentCallbacks(mComponentCallbacks);
mShutdownReceiver.register(mContext, Intent.ACTION_SHUTDOWN);
UI_HELPER_EXECUTOR.execute(() -> {
@@ -315,6 +276,7 @@
*/
public void onUserUnlocked() {
mUserUnlocked = true;
+ LauncherAppState.getIDP(mContext).addOnChangeListener(mIdpChangeListener);
recreateTaskbar();
}
@@ -398,7 +360,7 @@
mTaskbarActivityContext = new TaskbarActivityContext(mContext, dp, mNavButtonController,
mUnfoldProgressProvider);
} else {
- mTaskbarActivityContext.updateDeviceProfile(dp, mNavMode);
+ mTaskbarActivityContext.updateDeviceProfile(dp);
}
mTaskbarActivityContext.init(mSharedState);
@@ -501,11 +463,13 @@
UI_HELPER_EXECUTOR.execute(
() -> mTaskbarBroadcastReceiver.unregisterReceiverSafely(mContext));
destroyExistingTaskbar();
- mDisplayController.removeChangeListener(mDispInfoChangeListener);
- SettingsCache.INSTANCE.get(mContext).unregister(USER_SETUP_COMPLETE_URI,
- mUserSetupCompleteListener);
- SettingsCache.INSTANCE.get(mContext).unregister(NAV_BAR_KIDS_MODE,
- mNavBarKidsModeListener);
+ if (mUserUnlocked) {
+ LauncherAppState.getIDP(mContext).removeOnChangeListener(mIdpChangeListener);
+ }
+ SettingsCache.INSTANCE.get(mContext)
+ .unregister(USER_SETUP_COMPLETE_URI, mOnSettingsChangeListener);
+ SettingsCache.INSTANCE.get(mContext)
+ .unregister(NAV_BAR_KIDS_MODE, mOnSettingsChangeListener);
mContext.unregisterComponentCallbacks(mComponentCallbacks);
mContext.unregisterReceiver(mShutdownReceiver);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index fab70d3..5e37cf4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -522,9 +522,12 @@
return;
}
- if (stash && mControllers.taskbarAutohideSuspendController.isSuspended()
+ if (
+ stash
&& !mControllers.taskbarAutohideSuspendController
- .isSuspendedForTransientTaskbarInOverview()) {
+ .isSuspendedForTransientTaskbarInLauncher()
+ && mControllers.taskbarAutohideSuspendController
+ .isTransientTaskbarStashingSuspended()) {
// Avoid stashing if autohide is currently suspended.
return;
}
@@ -1088,6 +1091,9 @@
mActivity.getStatsLogManager().logger().log(hasAnyFlag(FLAG_STASHED_IN_APP_AUTO)
? LAUNCHER_TRANSIENT_TASKBAR_HIDE
: LAUNCHER_TRANSIENT_TASKBAR_SHOW);
+ mControllers.taskbarAutohideSuspendController.updateFlag(
+ TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR,
+ !hasAnyFlag(FLAG_STASHED_IN_APP_AUTO));
}
}
@@ -1180,7 +1186,7 @@
}
private void onTaskbarTimeout(Alarm alarm) {
- if (mControllers.taskbarAutohideSuspendController.isSuspended()) {
+ if (mControllers.taskbarAutohideSuspendController.isTransientTaskbarStashingSuspended()) {
return;
}
updateAndAnimateTransientTaskbarForTimeout();
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarItem.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarItem.kt
index 942a0a1..582dcc7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarItem.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarItem.kt
@@ -34,4 +34,4 @@
) : BubbleBarItem(info.key, view)
/** Represents the overflow bubble in the bubble bar. */
-data class BubbleBarOverflow(override val view: BubbleView) : BubbleBarItem("overflow", view)
+data class BubbleBarOverflow(override val view: BubbleView) : BubbleBarItem("Overflow", view)
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 0e1e0e1..8d20705 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -150,7 +150,9 @@
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
if (getChildCount() + 1 > MAX_BUBBLES) {
- removeViewInLayout(getChildAt(getChildCount() - 1));
+ // the last child view is the overflow bubble and we shouldn't remove that. remove the
+ // second to last child view.
+ removeViewInLayout(getChildAt(getChildCount() - 2));
}
super.addView(child, index, params);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index 8c8e267..d241260 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -46,6 +46,7 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
@@ -113,7 +114,9 @@
setter.setFloat(mRecentsView, TASK_SECONDARY_TRANSLATION, 0f,
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
- if (mRecentsView.isSplitSelectionActive()) {
+ boolean exitingOverview = !FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()
+ || !toState.overviewUi;
+ if (mRecentsView.isSplitSelectionActive() && exitingOverview) {
// TODO (b/238651489): Refactor state management to avoid need for double check
FloatingTaskView floatingTask = mRecentsView.getFirstFloatingTaskView();
if (floatingTask != null) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
index e61599f..2064fe2 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
@@ -189,7 +189,7 @@
} else {
float[] hctPlateColor = new float[3];
ColorUtils.colorToM3HCT(mDotParams.appColor, hctPlateColor);
- newPlateColor = ColorUtils.M3HCTtoColor(hctPlateColor[0], 36, 85);
+ newPlateColor = ColorUtils.M3HCTToColor(hctPlateColor[0], 36, 85);
}
if (!animate) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index ecc8e19..512d5f4 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -615,9 +615,10 @@
mSplitSelectStateController.findLastActiveTaskAndRunCallback(
splitSelectSource.itemInfo.getComponentKey(),
foundTask -> {
- splitSelectSource.alreadyRunningTaskId = foundTask == null
- ? INVALID_TASK_ID
- : foundTask.key.id;
+ boolean taskWasFound = foundTask != null;
+ splitSelectSource.alreadyRunningTaskId = taskWasFound
+ ? foundTask.key.id
+ : INVALID_TASK_ID;
if (ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
startSplitToHome(splitSelectSource);
} else {
@@ -1295,7 +1296,7 @@
groupTask.task1.key.id,
groupTask.task2.key.id,
SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT,
- /* callback= */ success -> {},
+ /* callback= */ success -> mSplitSelectStateController.resetState(),
/* freezeTaskList= */ true,
groupTask.mSplitBounds == null
? DEFAULT_SPLIT_RATIO
@@ -1304,6 +1305,13 @@
: groupTask.mSplitBounds.leftTaskPercent);
}
+ @Override
+ public boolean isCommandQueueEmpty() {
+ OverviewCommandHelper overviewCommandHelper = mTISBindHelper.getOverviewCommandHelper();
+ return super.isCommandQueueEmpty()
+ && (overviewCommandHelper == null || overviewCommandHelper.isCommandQueueEmpty());
+ }
+
private static final class LauncherTaskViewController extends
TaskViewTouchController<Launcher> {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 9f9cb00..d3ef589 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -16,6 +16,7 @@
package com.android.launcher3.uioverrides.touchcontrollers;
import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
import static com.android.app.animation.Interpolators.ACCELERATE_0_75;
import static com.android.app.animation.Interpolators.DECELERATE_3;
@@ -261,7 +262,7 @@
xAnim.setFloat(mRecentsView, ADJACENT_PAGE_HORIZONTAL_OFFSET, scaleAndOffset[1], LINEAR);
// Use QuickSwitchState instead of OverviewState to determine scrim color,
// since we need to take potential taskbar into account.
- xAnim.setScrimViewBackgroundColor(mLauncher.getScrimView(),
+ xAnim.setViewBackgroundColor(mLauncher.getScrimView(),
QUICK_SWITCH_FROM_HOME.getWorkspaceScrimColor(mLauncher), LINEAR);
if (mRecentsView.getTaskViewCount() == 0) {
xAnim.addFloat(mRecentsView, CONTENT_ALPHA, 0f, 1f, LINEAR);
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 6ab3bbe..95672f3 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1530,6 +1530,21 @@
if (mSwipePipToHomeReleaseCheck != null) {
mSwipePipToHomeReleaseCheck.setCanRelease(false);
}
+
+ // grab a screenshot before the PipContentOverlay gets parented on top of the task
+ UI_HELPER_EXECUTOR.execute(() -> {
+ final int taskId = mGestureState.getRunningTaskId();
+ mTaskSnapshotCache.put(taskId,
+ mRecentsAnimationController.screenshotTask(taskId));
+ });
+
+ // let SystemUi reparent the overlay leash as soon as possible
+ SystemUiProxy.INSTANCE.get(mContext).stopSwipePipToHome(
+ mSwipePipToHomeAnimator.getTaskId(),
+ mSwipePipToHomeAnimator.getComponentName(),
+ mSwipePipToHomeAnimator.getDestinationBounds(),
+ mSwipePipToHomeAnimator.getContentOverlay());
+
windowAnim = mSwipePipToHomeAnimators;
} else {
mSwipePipToHomeAnimator = null;
@@ -2108,11 +2123,6 @@
*/
private void maybeFinishSwipePipToHome() {
if (mIsSwipingPipToHome && mSwipePipToHomeAnimators[0] != null) {
- SystemUiProxy.INSTANCE.get(mContext).stopSwipePipToHome(
- mSwipePipToHomeAnimator.getTaskId(),
- mSwipePipToHomeAnimator.getComponentName(),
- mSwipePipToHomeAnimator.getDestinationBounds(),
- mSwipePipToHomeAnimator.getContentOverlay());
mRecentsAnimationController.setFinishTaskTransaction(
mSwipePipToHomeAnimator.getTaskId(),
mSwipePipToHomeAnimator.getFinishTransaction(),
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index a0d49a4..4a60566 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -140,6 +140,11 @@
mPendingCommands.clear();
}
+ @UiThread
+ public boolean isCommandQueueEmpty() {
+ return mPendingCommands.isEmpty();
+ }
+
@Nullable
private TaskView getNextTask(RecentsView view) {
final TaskView runningTaskView = view.getRunningTaskView();
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index bf96690..e282d1f 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -466,4 +466,11 @@
}
};
}
+
+ @Override
+ public boolean isCommandQueueEmpty() {
+ OverviewCommandHelper overviewCommandHelper = mTISBindHelper.getOverviewCommandHelper();
+ return super.isCommandQueueEmpty()
+ && (overviewCommandHelper == null || overviewCommandHelper.isCommandQueueEmpty());
+ }
}
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index 27fb476..84246e9 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -19,6 +19,7 @@
import android.app.WindowConfiguration;
import android.content.Context;
import android.graphics.Rect;
+import android.util.Log;
import android.view.RemoteAnimationTarget;
import androidx.annotation.Nullable;
@@ -37,6 +38,8 @@
* {@link TaskViewSimulator}
*/
public class RemoteTargetGluer {
+ private static final String TAG = "RemoteTargetGluer";
+
private static final int DEFAULT_NUM_HANDLES = 2;
private RemoteTargetHandle[] mRemoteTargetHandles;
@@ -118,7 +121,9 @@
long appCount = Arrays.stream(targets.apps)
.filter(app -> app.mode == targets.targetMode)
.count();
+ Log.d(TAG, "appCount: " + appCount + " handleLength: " + mRemoteTargetHandles.length);
if (appCount < mRemoteTargetHandles.length) {
+ Log.d(TAG, "resizing handles");
RemoteTargetHandle[] newHandles = new RemoteTargetHandle[(int) appCount];
System.arraycopy(mRemoteTargetHandles, 0/*src*/, newHandles, 0/*dst*/, (int) appCount);
mRemoteTargetHandles = newHandles;
@@ -128,6 +133,8 @@
.anyMatch(remoteAnimationTarget ->
remoteAnimationTarget.windowConfiguration.getWindowingMode()
== WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW);
+ Log.d(TAG, "containsSplitTargets? " + containsSplitTargets + " handleLength: " +
+ mRemoteTargetHandles.length + " appsLength: " + targets.apps.length);
if (mRemoteTargetHandles.length == 1) {
// Single fullscreen app
diff --git a/quickstep/src/com/android/quickstep/SplitSelectionListener.kt b/quickstep/src/com/android/quickstep/SplitSelectionListener.kt
new file mode 100644
index 0000000..5025c1c
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/SplitSelectionListener.kt
@@ -0,0 +1,17 @@
+package com.android.quickstep
+
+interface SplitSelectionListener {
+ /** Called when the first app has been selected with the intention to launch split screen */
+ fun onSplitSelectionActive()
+
+ /** Called when the second app has been selected with the intention to launch split screen */
+ fun onSplitSelectionConfirmed()
+
+ /**
+ * Called when the user no longer is in the process of selecting apps for split screen.
+ * [launchedSplit] will be true if selected apps have launched successfully (either in
+ * split screen or fullscreen), false if the user canceled/exited the selection process
+ */
+ fun onSplitSelectionExit(launchedSplit: Boolean) {
+ }
+}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index d40558c..dd6499b 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -563,9 +563,9 @@
}
/**
- * Notifies WM Shell that launcher has finished all the animation for swipe to home. WM Shell
- * can choose to fade out the overlay when entering PIP is finished, and WM Shell should be
- * responsible for cleaning up the overlay.
+ * Notifies WM Shell that launcher has finished the preparation of the animation for swipe to
+ * home. WM Shell can choose to fade out the overlay when entering PIP is finished, and WM Shell
+ * should be responsible for cleaning up the overlay.
*/
public void stopSwipePipToHome(int taskId, ComponentName componentName, Rect destinationBounds,
SurfaceControl overlay) {
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
index ca8381b..8a9e04e 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -114,7 +114,7 @@
setter.setFloat(mRecentsView, TASK_THUMBNAIL_SPLASH_ALPHA,
state.showTaskThumbnailSplash() ? 1f : 0f, INSTANT);
- setter.setScrimViewBackgroundColor(mActivity.getScrimView(), state.getScrimColor(mActivity),
+ setter.setViewBackgroundColor(mActivity.getScrimView(), state.getScrimColor(mActivity),
config.getInterpolator(ANIM_SCRIM_FADE, LINEAR));
RecentsState currentState = mActivity.getStateManager().getState();
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 074aedd..a9a57c6 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -35,6 +35,7 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.SplitConfigurationOptions;
@@ -79,11 +80,16 @@
}
@Override
- public void startHome(boolean animated) {
+ protected void handleStartHome(boolean animated) {
mActivity.startHome();
AbstractFloatingView.closeAllOpenViews(mActivity, mActivity.isStarted());
}
+ @Override
+ public boolean isCommandQueueEmpty() {
+ return mActivity.isCommandQueueEmpty();
+ }
+
/**
* When starting gesture interaction from home, we add a temporary invisible tile corresponding
* to the home task. This allows us to handle quick-switch similarly to a quick-switching
@@ -246,7 +252,11 @@
setOverviewSelectEnabled(false);
}
if (finalState != OVERVIEW_SPLIT_SELECT) {
- resetFromSplitSelectionState();
+ if (FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ mSplitSelectStateController.resetState();
+ } else {
+ resetFromSplitSelectionState();
+ }
}
if (isOverlayEnabled) {
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 2123253..e063b44 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -73,16 +73,18 @@
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
import com.android.quickstep.RecentsModel;
+import com.android.quickstep.SplitSelectionListener;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskAnimationManager;
import com.android.quickstep.TaskViewUtils;
import com.android.quickstep.views.FloatingTaskView;
import com.android.quickstep.views.GroupedTaskView;
-import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
import java.util.function.Consumer;
/**
@@ -138,6 +140,8 @@
private FloatingTaskView mFirstFloatingTaskView;
+ private final List<SplitSelectionListener> mSplitSelectionListeners = new ArrayList<>();
+
public SplitSelectStateController(Context context, Handler handler, StateManager stateManager,
DepthController depthController, StatsLogManager statsLogManager,
SystemUiProxy systemUiProxy, RecentsModel recentsModel) {
@@ -248,6 +252,27 @@
}
/**
+ * Listener will only get callbacks going forward from the point of registration. No
+ * methods will be fired upon registering.
+ */
+ public void registerSplitListener(@NonNull SplitSelectionListener listener) {
+ if (mSplitSelectionListeners.contains(listener)) {
+ return;
+ }
+ mSplitSelectionListeners.add(listener);
+ }
+
+ public void unregisterSplitListener(@NonNull SplitSelectionListener listener) {
+ mSplitSelectionListeners.remove(listener);
+ }
+
+ private void dispatchOnSplitSelectionExit() {
+ for (SplitSelectionListener listener : mSplitSelectionListeners) {
+ listener.onSplitSelectionExit(false);
+ }
+ }
+
+ /**
* To be called when the actual tasks ({@link #mInitialTaskId}, {@link #mSecondTaskId}) are
* to be launched. Call after launcher side animations are complete.
*/
@@ -790,12 +815,16 @@
}
/**
- * To be called if split select was cancelled
+ * To be called whenever we exit split selection state. If
+ * {@link FeatureFlags#ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE} is set, this should be the
+ * central way split is getting reset, which should then go through the callbacks to reset
+ * other state.
*/
public void resetState() {
if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
mSplitSelectDataHolder.resetState();
}
+ dispatchOnSplitSelectionExit();
mInitialTaskId = INVALID_TASK_ID;
mInitialTaskIntent = null;
mSecondTaskId = INVALID_TASK_ID;
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index 6813857..19ac1f8 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -16,6 +16,8 @@
package com.android.quickstep.views;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW;
+
import android.content.Context;
import android.util.AttributeSet;
import android.util.FloatProperty;
@@ -248,8 +250,15 @@
*/
private float getOriginalTranslationY() {
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
- return deviceProfile.isTablet
- ? deviceProfile.overviewRowSpacing
- : deviceProfile.overviewTaskThumbnailTopMarginPx / 2.0f;
+ if (deviceProfile.isTablet) {
+ if (ENABLE_GRID_ONLY_OVERVIEW.get()) {
+ return (getRecentsView().getLastComputedTaskSize().height()
+ + deviceProfile.overviewTaskThumbnailTopMarginPx) / 2.0f
+ + deviceProfile.overviewRowSpacing;
+ } else {
+ return deviceProfile.overviewRowSpacing;
+ }
+ }
+ return deviceProfile.overviewTaskThumbnailTopMarginPx / 2.0f;
}
}
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
index 3e79eaf..7bbe36a 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -280,10 +280,6 @@
}
}
- public String getContentDescription() {
- return getContentDescriptionForTask(mTask, mAppUsageLimitTimeMs, mAppRemainingTimeMs);
- }
-
private String getContentDescriptionForTask(
Task task, long appUsageLimitTimeMs, long appRemainingTimeMs) {
return appUsageLimitTimeMs >= 0 && appRemainingTimeMs >= 0 ?
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 4dbf4e3..9e9b22f 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -37,6 +37,7 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statehandlers.DesktopVisibilityController;
@@ -81,7 +82,7 @@
}
@Override
- public void startHome(boolean animated) {
+ protected void handleStartHome(boolean animated) {
StateManager stateManager = mActivity.getStateManager();
animated &= stateManager.shouldAnimateStateChange();
stateManager.goToState(NORMAL, animated);
@@ -89,6 +90,11 @@
}
@Override
+ public boolean isCommandQueueEmpty() {
+ return mActivity.isCommandQueueEmpty();
+ }
+
+ @Override
protected void onTaskLaunchAnimationEnd(boolean success) {
if (success) {
mActivity.getStateManager().moveToRestState();
@@ -218,7 +224,11 @@
@Override
protected boolean canLaunchFullscreenTask() {
- return !mActivity.isInState(OVERVIEW_SPLIT_SELECT);
+ if (FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ return !mSplitSelectStateController.isSplitSelectActive();
+ } else {
+ return !mActivity.isInState(OVERVIEW_SPLIT_SELECT);
+ }
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 4d88a04..f0daf8d 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -173,6 +173,7 @@
import com.android.quickstep.RemoteTargetGluer;
import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
import com.android.quickstep.RotationTouchHelper;
+import com.android.quickstep.SplitSelectionListener;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskOverlayFactory;
import com.android.quickstep.TaskThumbnailCache;
@@ -662,7 +663,8 @@
/**
* Placeholder view indicating where the first split screen selected app will be placed
*/
- private SplitSelectStateController mSplitSelectStateController;
+ protected SplitSelectStateController mSplitSelectStateController;
+
/**
* The first task that split screen selection was initiated with. When split select state is
* initialized, we create a
@@ -685,6 +687,19 @@
@Nullable
private SplitSelectSource mSplitSelectSource;
+ private final SplitSelectionListener mSplitSelectionListener = new SplitSelectionListener() {
+ @Override
+ public void onSplitSelectionConfirmed() { }
+
+ @Override
+ public void onSplitSelectionActive() { }
+
+ @Override
+ public void onSplitSelectionExit(boolean launchedSplit) {
+ resetFromSplitSelectionState();
+ }
+ };
+
/**
* Keeps track of the index of the TaskView that split screen was initialized with so we know
* where to insert it back into list of taskViews in case user backs out of entering split
@@ -1065,6 +1080,9 @@
mIPipAnimationListener);
mOrientationState.initListeners();
mTaskOverlayFactory.initListeners();
+ if (FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ mSplitSelectStateController.registerSplitListener(mSplitSelectionListener);
+ }
}
@Override
@@ -1083,6 +1101,9 @@
mIPipAnimationListener.setActivityAndRecentsView(null, null);
mOrientationState.destroyListeners();
mTaskOverlayFactory.removeListeners();
+ if (FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ mSplitSelectStateController.unregisterSplitListener(mSplitSelectionListener);
+ }
}
@Override
@@ -1660,8 +1681,8 @@
// If we are entering Overview as a result of initiating a split from somewhere else
// (e.g. split from Home), we need to make sure the staged app is not drawn as a thumbnail.
int stagedTaskIdToBeRemovedFromGrid;
- if (mSplitSelectSource != null) {
- stagedTaskIdToBeRemovedFromGrid = mSplitSelectSource.alreadyRunningTaskId;
+ if (isSplitSelectionActive()) {
+ stagedTaskIdToBeRemovedFromGrid = mSplitSelectStateController.getInitialTaskId();
updateCurrentTaskActionsVisibility();
} else {
stagedTaskIdToBeRemovedFromGrid = INVALID_TASK_ID;
@@ -2345,7 +2366,15 @@
startHome(mActivity.isStarted());
}
- public abstract void startHome(boolean animated);
+ public void startHome(boolean animated) {
+ if (!isCommandQueueEmpty()) return;
+ handleStartHome(animated);
+ }
+
+ protected abstract void handleStartHome(boolean animated);
+
+ /** Returns whether the overview command helper queue is empty. */
+ public abstract boolean isCommandQueueEmpty();
public void reset() {
setCurrentTask(-1);
@@ -2367,7 +2396,9 @@
remoteTargetHandle.getTransformParams().setTargetSet(null);
remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false);
});
- resetFromSplitSelectionState();
+ if (!FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ resetFromSplitSelectionState();
+ }
// These are relatively expensive and don't need to be done this frame (RecentsView isn't
// visible anyway), so defer by a frame to get off the critical path, e.g. app to home.
@@ -3251,7 +3282,11 @@
InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER);
} else {
// If transition to split select was interrupted, clean up to prevent glitches
- resetFromSplitSelectionState();
+ if (FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ mSplitSelectStateController.resetState();
+ } else {
+ resetFromSplitSelectionState();
+ }
InteractionJankMonitorWrapper.cancel(
InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER);
}
@@ -3284,8 +3319,13 @@
true /* isStagedTask */);
pendingAnimation.addEndListener(animationSuccess ->
- mSplitSelectStateController.launchInitialAppFullscreen(launchSuccess ->
- resetFromSplitSelectionState()));
+ mSplitSelectStateController.launchInitialAppFullscreen(launchSuccess -> {
+ if (FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ mSplitSelectStateController.resetState();
+ } else {
+ resetFromSplitSelectionState();
+ }
+ }));
pendingAnimation.buildAnim().start();
}
@@ -3766,19 +3806,33 @@
taskViewIdArray.removeValue(
finalNextFocusedTaskView.getTaskViewId());
}
- if (snappedIndex < taskViewIdArray.size()) {
- taskViewIdToSnapTo = taskViewIdArray.get(snappedIndex);
- } else if (snappedIndex == taskViewIdArray.size()) {
- // If the snapped task is the last item from the
- // dismissed row,
- // snap to the same column in the other grid row
- IntArray inverseRowTaskViewIdArray =
- isSnappedTaskInTopRow ? getBottomRowIdArray()
- : getTopRowIdArray();
- if (snappedIndex < inverseRowTaskViewIdArray.size()) {
- taskViewIdToSnapTo = inverseRowTaskViewIdArray.get(
- snappedIndex);
+ try {
+ if (snappedIndex < taskViewIdArray.size()) {
+ taskViewIdToSnapTo = taskViewIdArray.get(snappedIndex);
+ } else if (snappedIndex == taskViewIdArray.size()) {
+ // If the snapped task is the last item from the
+ // dismissed row,
+ // snap to the same column in the other grid row
+ IntArray inverseRowTaskViewIdArray =
+ isSnappedTaskInTopRow ? getBottomRowIdArray()
+ : getTopRowIdArray();
+ if (snappedIndex < inverseRowTaskViewIdArray.size()) {
+ taskViewIdToSnapTo = inverseRowTaskViewIdArray.get(
+ snappedIndex);
+ }
}
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new IllegalStateException(
+ "b/269956477 invalid snappedIndex"
+ + "\nsnappedTaskViewId: "
+ + snappedTaskViewId
+ + "\nfocusedTaskViewId: "
+ + mFocusedTaskViewId
+ + "\ntopRowIdArray: "
+ + getTopRowIdArray().toConcatString()
+ + "\nbottomRowIdArray: "
+ + getBottomRowIdArray().toConcatString(),
+ e);
}
}
}
@@ -4723,7 +4777,13 @@
pendingAnimation.addEndListener(aBoolean -> {
mSplitSelectStateController.launchSplitTasks(
- aBoolean1 -> RecentsView.this.resetFromSplitSelectionState());
+ aBoolean1 -> {
+ if (FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ mSplitSelectStateController.resetState();
+ } else {
+ resetFromSplitSelectionState();
+ }
+ });
InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER);
});
@@ -4745,7 +4805,8 @@
@SuppressLint("WrongCall")
protected void resetFromSplitSelectionState() {
- if (mSplitSelectSource != null || mSplitHiddenTaskViewIndex != -1) {
+ if (mSplitSelectSource != null || mSplitHiddenTaskViewIndex != -1 ||
+ FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
safeRemoveDragLayerView(mSplitSelectStateController.getFirstFloatingTaskView());
safeRemoveDragLayerView(mSecondFloatingTaskView);
safeRemoveDragLayerView(mSplitInstructionsView);
@@ -4764,7 +4825,11 @@
setTaskViewsPrimarySplitTranslation(0);
setTaskViewsSecondarySplitTranslation(0);
- mSplitSelectStateController.resetState();
+ if (!FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ // When flag is on, this method gets called from resetState() call below, let's avoid
+ // infinite recursion today
+ mSplitSelectStateController.resetState();
+ }
if (mSplitHiddenTaskViewIndex == -1) {
return;
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index ea45f9d..40e3dca 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -1021,7 +1021,10 @@
}
if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
mIconLoadRequest = iconCache.updateIconInBackground(mTask,
- (task) -> setIcon(mIconView, task.icon));
+ (task) -> {
+ setIcon(mIconView, task.icon);
+ mDigitalWellBeingToast.initialize(task);
+ });
}
} else {
if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
@@ -1343,7 +1346,6 @@
protected void refreshTaskThumbnailSplash() {
mSnapshotView.refreshSplashView();
- setContentDescription(mDigitalWellBeingToast.getContentDescription());
}
private void setSplitSelectTranslationX(float x) {
diff --git a/res/color-night-v31/taskbar_background.xml b/res/color-night-v31/taskbar_background.xml
index 074db20..ec7a682 100644
--- a/res/color-night-v31/taskbar_background.xml
+++ b/res/color-night-v31/taskbar_background.xml
@@ -13,6 +13,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+<!-- Make sure to align any changes to
+ frameworks/base/libs/WindowManager/Shell/res/color/taskbar_background_dark.xml -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@android:color/system_neutral1_500" android:lStar="6" />
</selector>
diff --git a/res/layout/widget_cell.xml b/res/layout/widget_cell.xml
index 9868e20..55dd1de 100644
--- a/res/layout/widget_cell.xml
+++ b/res/layout/widget_cell.xml
@@ -19,7 +19,6 @@
android:layout_height="wrap_content"
android:paddingHorizontal="@dimen/widget_cell_horizontal_padding"
android:paddingVertical="@dimen/widget_cell_vertical_padding"
- android:layout_marginHorizontal="@dimen/widget_cell_horizontal_padding"
android:layout_weight="1"
android:orientation="vertical"
android:focusable="true"
diff --git a/res/layout/widgets_table_container.xml b/res/layout/widgets_table_container.xml
index 4a32672..c41d0bb 100644
--- a/res/layout/widgets_table_container.xml
+++ b/res/layout/widgets_table_container.xml
@@ -16,6 +16,7 @@
<com.android.launcher3.widget.picker.WidgetsListTableView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/widgets_table"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin"
android:background="@drawable/bg_widgets_content"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 1bb4025..76a1239 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -208,6 +208,10 @@
Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled -->
<attr name="allAppsSpecsId" format="reference" />
+ <!-- File that contains the specs for the workspace.
+ Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled -->
+ <attr name="folderSpecsId" format="reference" />
+
<!-- By default all categories are enabled -->
<attr name="deviceCategory" format="integer">
<!-- Enable on phone only -->
diff --git a/res/values/config.xml b/res/values/config.xml
index 27211fd..8f9731c 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -217,4 +217,28 @@
<!-- Whether the floating rotation button should be on the left/right in the device's natural
orientation -->
<bool name="floating_rotation_button_position_left">true</bool>
+
+ <!-- Mapping of visual icon size to XML value http://b/235886078 -->
+ <dimen name="iconSize48dp">52dp</dimen>
+ <dimen name="iconSize50dp">55dp</dimen>
+ <dimen name="iconSize52dp">57dp</dimen>
+ <dimen name="iconSize54dp">59dp</dimen>
+ <dimen name="iconSize56dp">61dp</dimen>
+ <dimen name="iconSize58dp">63dp</dimen>
+ <dimen name="iconSize60dp">66dp</dimen>
+ <dimen name="iconSize66dp">72dp</dimen>
+ <dimen name="iconSize72dp">79dp</dimen>
+
+ <!-- Icon size steps in dp -->
+ <integer-array name="icon_size_steps">
+ <item>@dimen/iconSize48dp</item>
+ <item>@dimen/iconSize50dp</item>
+ <item>@dimen/iconSize52dp</item>
+ <item>@dimen/iconSize54dp</item>
+ <item>@dimen/iconSize56dp</item>
+ <item>@dimen/iconSize58dp</item>
+ <item>@dimen/iconSize60dp</item>
+ <item>@dimen/iconSize66dp</item>
+ <item>@dimen/iconSize72dp</item>
+ </integer-array>
</resources>
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 32421a4..64ac841 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -382,8 +382,7 @@
private void resetCellSizeInternal(DeviceProfile deviceProfile) {
switch (mContainerType) {
case FOLDER:
- mBorderSpace = new Point(deviceProfile.folderCellLayoutBorderSpacePx,
- deviceProfile.folderCellLayoutBorderSpacePx);
+ mBorderSpace = new Point(deviceProfile.folderCellLayoutBorderSpacePx);
break;
case HOTSEAT:
mBorderSpace = new Point(deviceProfile.hotseatBorderSpace,
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 0498032..bd47fca 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -55,9 +55,12 @@
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.FolderSpecs;
import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
+import com.android.launcher3.util.IconSizeSteps;
import com.android.launcher3.util.ResourceHelper;
import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.workspace.CalculatedWorkspaceSpec;
@@ -77,12 +80,12 @@
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;
private final DisplayMetrics mMetrics;
+ private final IconSizeSteps mIconSizeSteps;
// Device properties
public final boolean isTablet;
@@ -118,6 +121,9 @@
private AllAppsSpecs mAllAppsSpecs;
private CalculatedAllAppsSpec mAllAppsResponsiveWidthSpec;
private CalculatedAllAppsSpec mAllAppsResponsiveHeightSpec;
+ private FolderSpecs mFolderSpecs;
+ private CalculatedFolderSpec mResponsiveFolderWidthSpec;
+ private CalculatedFolderSpec mResponsiveFolderHeightSpec;
/**
* The maximum amount of left/right workspace padding as a percentage of the screen width.
@@ -176,7 +182,7 @@
public int folderIconOffsetYPx;
// Folder content
- public int folderCellLayoutBorderSpacePx;
+ public Point folderCellLayoutBorderSpacePx;
public int folderContentPaddingLeftRight;
public int folderContentPaddingTop;
@@ -312,7 +318,8 @@
// TODO(b/241386436): shouldn't change any launcher behaviour
mIsResponsiveGrid = inv.workspaceSpecsId != INVALID_RESOURCE_HANDLE
- && inv.allAppsSpecsId != INVALID_RESOURCE_HANDLE;
+ && inv.allAppsSpecsId != INVALID_RESOURCE_HANDLE
+ && inv.folderSpecsId != INVALID_RESOURCE_HANDLE;
mIsScalableGrid = inv.isScalable && !isVerticalBarLayout() && !isMultiWindowMode;
// Determine device posture.
@@ -330,6 +337,8 @@
final Resources res = context.getResources();
mMetrics = res.getDisplayMetrics();
+ mIconSizeSteps = mIsResponsiveGrid ? new IconSizeSteps(res) : null;
+
// Determine sizes.
widthPx = windowBounds.bounds.width();
heightPx = windowBounds.bounds.height();
@@ -416,13 +425,15 @@
folderContentPaddingTop = folderStyle.getDimensionPixelSize(
R.styleable.FolderStyle_folderTopPadding, 0);
- folderCellLayoutBorderSpacePx = folderStyle.getDimensionPixelSize(
+
+ int gutter = folderStyle.getDimensionPixelSize(
R.styleable.FolderStyle_folderBorderSpace, 0);
+ folderCellLayoutBorderSpacePx = new Point(gutter, gutter);
folderFooterHeightPx = folderStyle.getDimensionPixelSize(
R.styleable.FolderStyle_folderFooterHeight, 0);
folderStyle.recycle();
- } else {
- folderCellLayoutBorderSpacePx = 0;
+ } else if (!mIsResponsiveGrid) {
+ folderCellLayoutBorderSpacePx = new Point(0, 0);
folderFooterHeightPx = res.getDimensionPixelSize(R.dimen.folder_footer_height_default);
folderContentPaddingTop = res.getDimensionPixelSize(R.dimen.folder_top_padding_default);
}
@@ -535,12 +546,16 @@
// for the available height to be correct
if (mIsResponsiveGrid) {
mWorkspaceSpecs = new WorkspaceSpecs(new ResourceHelper(context, inv.workspaceSpecsId));
+ int availableResponsiveWidth =
+ availableWidthPx - (isVerticalBarLayout() ? hotseatBarSizePx : 0);
+ // don't use availableHeightPx because it subtracts bottom padding,
+ // but the workspace go behind it
+ int availableResponsiveHeight =
+ heightPx - mInsets.top - (isVerticalBarLayout() ? 0 : hotseatBarSizePx);
mResponsiveWidthSpec = mWorkspaceSpecs.getCalculatedWidthSpec(inv.numColumns,
- availableWidthPx);
+ availableResponsiveWidth);
mResponsiveHeightSpec = mWorkspaceSpecs.getCalculatedHeightSpec(inv.numRows,
- // don't use availableHeightPx because it subtracts bottom padding,
- // but the hotseat go behind it
- heightPx - mInsets.top - hotseatBarSizePx);
+ availableResponsiveHeight);
mAllAppsSpecs = new AllAppsSpecs(new ResourceHelper(context, inv.allAppsSpecsId));
mAllAppsResponsiveWidthSpec = mAllAppsSpecs.getCalculatedWidthSpec(inv.numColumns,
@@ -548,6 +563,12 @@
mAllAppsResponsiveHeightSpec = mAllAppsSpecs.getCalculatedHeightSpec(inv.numRows,
mResponsiveHeightSpec.getAvailableSpace(),
mResponsiveHeightSpec);
+
+ mFolderSpecs = new FolderSpecs(new ResourceHelper(context, inv.folderSpecsId));
+ mResponsiveFolderWidthSpec = mFolderSpecs.getWidthSpec(inv.numFolderColumns,
+ mResponsiveWidthSpec.getAvailableSpace(), mResponsiveWidthSpec);
+ mResponsiveFolderHeightSpec = mFolderSpecs.getHeightSpec(inv.numFolderRows,
+ mResponsiveHeightSpec.getAvailableSpace(), mResponsiveHeightSpec);
}
desiredWorkspaceHorizontalMarginPx = getHorizontalMarginPx(inv, res);
@@ -926,9 +947,32 @@
cellWidthPx = mResponsiveWidthSpec.getCellSizePx();
cellHeightPx = mResponsiveHeightSpec.getCellSizePx();
- cellYPaddingPx = Math.max(0, cellHeightPx - cellContentHeight) / 2;
- // TODO(b/283929701): decrease icon size if content doesn't fit on cell
+ if (cellWidthPx < iconSizePx) {
+ // get a smaller icon size
+ iconSizePx = mIconSizeSteps.getIconSmallerThan(cellWidthPx);
+ // calculate new cellContentHeight
+ cellContentHeight = iconSizePx + cellTextAndPaddingHeight;
+ }
+
+ while (iconSizePx > mIconSizeSteps.minimumIconSize()
+ && cellContentHeight > cellHeightPx) {
+ int extraHeightRequired = cellContentHeight - cellHeightPx;
+ int newPadding = iconDrawablePaddingPx - extraHeightRequired;
+ if (newPadding >= 0) {
+ // Responsive uses the padding without scaling
+ iconDrawablePaddingPx = iconDrawablePaddingOriginalPx = newPadding;
+ cellTextAndPaddingHeight =
+ iconDrawablePaddingPx + Utilities.calculateTextHeight(iconTextSizePx);
+ } else {
+ // get a smaller icon size
+ iconSizePx = mIconSizeSteps.getNextLowerIconSize(iconSizePx);
+ }
+ // calculate new cellContentHeight
+ cellContentHeight = iconSizePx + cellTextAndPaddingHeight;
+ }
+
+ cellYPaddingPx = Math.max(0, cellHeightPx - cellContentHeight) / 2;
} else if (mIsScalableGrid) {
cellWidthPx = pxFromDp(inv.minCellSize[mTypeIndex].x, mMetrics, scale);
cellHeightPx = pxFromDp(inv.minCellSize[mTypeIndex].y, mMetrics, scale);
@@ -1148,15 +1192,19 @@
allAppsStyle.recycle();
}
+ // TODO(b/288075868): Resize the icon size to make sure it will fit inside the cell size
private void updateAvailableFolderCellDimensions(Resources res) {
updateFolderCellSize(1f, res);
+ // Responsive grid doesn't need to scale the folder
+ if (mIsResponsiveGrid) return;
+
// For usability we can't have the folder use the whole width of the screen
Point totalWorkspacePadding = getTotalWorkspacePadding();
// Check if the folder fit within the available height.
float contentUsedHeight = folderCellHeightPx * inv.numFolderRows
- + ((inv.numFolderRows - 1) * folderCellLayoutBorderSpacePx)
+ + ((inv.numFolderRows - 1) * folderCellLayoutBorderSpacePx.y)
+ folderFooterHeightPx
+ folderContentPaddingTop;
int contentMaxHeight = availableHeightPx - totalWorkspacePadding.y;
@@ -1164,7 +1212,7 @@
// Check if the folder fit within the available width.
float contentUsedWidth = folderCellWidthPx * inv.numFolderColumns
- + ((inv.numFolderColumns - 1) * folderCellLayoutBorderSpacePx)
+ + ((inv.numFolderColumns - 1) * folderCellLayoutBorderSpacePx.x)
+ folderContentPaddingLeftRight * 2;
int contentMaxWidth = availableWidthPx - totalWorkspacePadding.x;
float scaleX = contentMaxWidth / contentUsedWidth;
@@ -1184,7 +1232,19 @@
int textHeight = Utilities.calculateTextHeight(folderChildTextSizePx);
- if (mIsScalableGrid) {
+ if (mIsResponsiveGrid) {
+ folderCellWidthPx = mResponsiveFolderWidthSpec.getCellSizePx();
+
+ // Height
+ folderCellHeightPx = mResponsiveFolderHeightSpec.getCellSizePx();
+ folderContentPaddingTop = mResponsiveFolderHeightSpec.getStartPaddingPx();
+ folderFooterHeightPx = mResponsiveFolderHeightSpec.getEndPaddingPx();
+
+ folderCellLayoutBorderSpacePx = new Point(mResponsiveFolderWidthSpec.getGutterPx(),
+ mResponsiveHeightSpec.getGutterPx());
+
+ folderContentPaddingLeftRight = mResponsiveFolderWidthSpec.getStartPaddingPx();
+ } else if (mIsScalableGrid) {
if (inv.folderStyle == INVALID_RESOURCE_HANDLE) {
folderCellWidthPx = roundPxValueFromFloat(getCellSize().x * scale);
folderCellHeightPx = roundPxValueFromFloat(getCellSize().y * scale);
@@ -1194,11 +1254,13 @@
}
folderContentPaddingTop = roundPxValueFromFloat(folderContentPaddingTop * scale);
- folderCellLayoutBorderSpacePx = roundPxValueFromFloat(
- folderCellLayoutBorderSpacePx * scale);
+ folderCellLayoutBorderSpacePx = new Point(
+ roundPxValueFromFloat(folderCellLayoutBorderSpacePx.x * scale),
+ roundPxValueFromFloat(folderCellLayoutBorderSpacePx.y * scale)
+ );
folderFooterHeightPx = roundPxValueFromFloat(folderFooterHeightPx * scale);
- folderContentPaddingLeftRight = folderCellLayoutBorderSpacePx;
+ folderContentPaddingLeftRight = folderCellLayoutBorderSpacePx.x;
} else {
int cellPaddingX = (int) (res.getDimensionPixelSize(R.dimen.folder_cell_x_padding)
* scale);
@@ -1719,8 +1781,10 @@
writer.println(prefix + pxToDpStr("folderChildTextSizePx", folderChildTextSizePx));
writer.println(prefix + pxToDpStr("folderChildDrawablePaddingPx",
folderChildDrawablePaddingPx));
- writer.println(prefix + pxToDpStr("folderCellLayoutBorderSpacePx",
- folderCellLayoutBorderSpacePx));
+ writer.println(prefix + pxToDpStr("folderCellLayoutBorderSpacePx.x",
+ folderCellLayoutBorderSpacePx.x));
+ writer.println(prefix + pxToDpStr("folderCellLayoutBorderSpacePx.y",
+ folderCellLayoutBorderSpacePx.y));
writer.println(prefix + pxToDpStr("folderContentPaddingLeftRight",
folderContentPaddingLeftRight));
writer.println(prefix + pxToDpStr("folderTopPadding", folderContentPaddingTop));
@@ -1840,6 +1904,8 @@
+ mAllAppsResponsiveHeightSpec.toString());
writer.println(prefix + "\tmAllAppsResponsiveWidthSpec:"
+ mAllAppsResponsiveWidthSpec.toString());
+ writer.println(prefix + "\tmResponsiveFolderHeightSpec:" + mResponsiveFolderHeightSpec);
+ writer.println(prefix + "\tmResponsiveFolderWidthSpec:" + mResponsiveFolderWidthSpec);
}
}
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 81aa2b2..4eaacdc 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -181,6 +181,8 @@
public int workspaceSpecsId = INVALID_RESOURCE_HANDLE;
@XmlRes
public int allAppsSpecsId = INVALID_RESOURCE_HANDLE;
+ @XmlRes
+ public int folderSpecsId = INVALID_RESOURCE_HANDLE;
public String dbFile;
public int defaultLayoutId;
@@ -356,6 +358,7 @@
devicePaddingId = closestProfile.devicePaddingId;
workspaceSpecsId = closestProfile.mWorkspaceSpecsId;
allAppsSpecsId = closestProfile.mAllAppsSpecsId;
+ folderSpecsId = closestProfile.mFolderSpecsId;
this.deviceType = deviceType;
inlineNavButtonsEndSpacing = closestProfile.inlineNavButtonsEndSpacing;
@@ -803,6 +806,7 @@
private final int devicePaddingId;
private final int mWorkspaceSpecsId;
private final int mAllAppsSpecsId;
+ private final int mFolderSpecsId;
public GridOption(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(
@@ -869,9 +873,12 @@
R.styleable.GridDisplayOption_workspaceSpecsId, INVALID_RESOURCE_HANDLE);
mAllAppsSpecsId = a.getResourceId(
R.styleable.GridDisplayOption_allAppsSpecsId, INVALID_RESOURCE_HANDLE);
+ mFolderSpecsId = a.getResourceId(
+ R.styleable.GridDisplayOption_folderSpecsId, INVALID_RESOURCE_HANDLE);
} else {
mWorkspaceSpecsId = INVALID_RESOURCE_HANDLE;
mAllAppsSpecsId = INVALID_RESOURCE_HANDLE;
+ mFolderSpecsId = INVALID_RESOURCE_HANDLE;
}
int inlineForRotation = a.getInt(R.styleable.GridDisplayOption_inlineQsb,
diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java
index 51abfd3..c20f323 100644
--- a/src/com/android/launcher3/LauncherAnimUtils.java
+++ b/src/com/android/launcher3/LauncherAnimUtils.java
@@ -30,7 +30,6 @@
import android.widget.TextView;
import com.android.launcher3.util.MultiScalePropertyFactory;
-import com.android.launcher3.views.ScrimView;
public class LauncherAnimUtils {
/**
@@ -195,10 +194,6 @@
@Override
public Integer get(View view) {
- if (view instanceof ScrimView) {
- return ((ScrimView) view).getBackgroundColor();
- }
-
if (!(view.getBackground() instanceof ColorDrawable)) {
return Color.TRANSPARENT;
}
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index ba6dc26..f921d1d 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -162,7 +162,7 @@
// No need to add padding when cell layout border spacing is present.
boolean noPaddingX =
(dp.cellLayoutBorderSpacePx.x > 0 && mContainerType == WORKSPACE)
- || (dp.folderCellLayoutBorderSpacePx > 0 && mContainerType == FOLDER)
+ || (dp.folderCellLayoutBorderSpacePx.x > 0 && mContainerType == FOLDER)
|| (dp.hotseatBorderSpace > 0 && mContainerType == HOTSEAT);
int cellPaddingX = noPaddingX
? 0
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 1404a92..e4f34ae 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -199,7 +199,7 @@
propertySetter.setFloat(sysUiScrim.getSysUIProgress(), AnimatedFloat.VALUE,
state.hasFlag(FLAG_HAS_SYS_UI_SCRIM) ? 1 : 0, LINEAR);
- propertySetter.setScrimViewBackgroundColor(mLauncher.getScrimView(),
+ propertySetter.setViewBackgroundColor(mLauncher.getScrimView(),
state.getWorkspaceScrimColor(mLauncher),
config.getInterpolator(ANIM_SCRIM_FADE, ACCELERATE_2));
}
diff --git a/src/com/android/launcher3/anim/AnimatedPropertySetter.java b/src/com/android/launcher3/anim/AnimatedPropertySetter.java
index ff6bdec..82e645a 100644
--- a/src/com/android/launcher3/anim/AnimatedPropertySetter.java
+++ b/src/com/android/launcher3/anim/AnimatedPropertySetter.java
@@ -24,14 +24,13 @@
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
+import android.graphics.drawable.ColorDrawable;
import android.util.FloatProperty;
import android.util.IntProperty;
import android.view.View;
import androidx.annotation.NonNull;
-import com.android.launcher3.views.ScrimView;
-
import java.util.function.Consumer;
/**
@@ -63,9 +62,9 @@
}
@Override
- public Animator setScrimViewBackgroundColor(ScrimView view, int color,
- TimeInterpolator interpolator) {
- if (view == null || view.getBackgroundColor() == color) {
+ public Animator setViewBackgroundColor(View view, int color, TimeInterpolator interpolator) {
+ if (view == null || (view.getBackground() instanceof ColorDrawable
+ && ((ColorDrawable) view.getBackground()).getColor() == color)) {
return NO_OP;
}
ObjectAnimator anim = ObjectAnimator.ofArgb(view, VIEW_BACKGROUND_COLOR, color);
diff --git a/src/com/android/launcher3/anim/PropertySetter.java b/src/com/android/launcher3/anim/PropertySetter.java
index 0b2858d..6ba58b6 100644
--- a/src/com/android/launcher3/anim/PropertySetter.java
+++ b/src/com/android/launcher3/anim/PropertySetter.java
@@ -25,8 +25,6 @@
import androidx.annotation.NonNull;
-import com.android.launcher3.views.ScrimView;
-
import java.util.function.Consumer;
/**
@@ -64,8 +62,7 @@
* Sets the background color of the provided view using the provided interpolator.
*/
@NonNull
- public Animator setScrimViewBackgroundColor(ScrimView view, int color,
- TimeInterpolator interpolator) {
+ public Animator setViewBackgroundColor(View view, int color, TimeInterpolator interpolator) {
if (view != null) {
view.setBackgroundColor(color);
}
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index dd82ecf..b09985c 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -236,9 +236,9 @@
mFolder, startRect, endRect, finalRadius, !mIsOpening));
// Create reveal animator for the folder content (capture the top 4 icons 2x2)
- int width = mDeviceProfile.folderCellLayoutBorderSpacePx
+ int width = mDeviceProfile.folderCellLayoutBorderSpacePx.x
+ mDeviceProfile.folderCellWidthPx * 2;
- int height = mDeviceProfile.folderCellLayoutBorderSpacePx
+ int height = mDeviceProfile.folderCellLayoutBorderSpacePx.y
+ mDeviceProfile.folderCellHeightPx * 2;
int page = mIsOpening ? mContent.getCurrentPage() : mContent.getDestinationPage();
int left = mContent.getPaddingLeft() + page * lp.width;
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index c5c74ac..307052a 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -155,19 +155,19 @@
// Progress color
float[] m3HCT = new float[3];
ColorUtils.colorToM3HCT(primaryIconColor, m3HCT);
- mProgressColor = ColorUtils.M3HCTtoColor(
+ mProgressColor = ColorUtils.M3HCTToColor(
m3HCT[0],
m3HCT[1],
isDarkMode ? Math.max(m3HCT[2], 55) : Math.min(m3HCT[2], 40));
// Track color
- mTrackColor = ColorUtils.M3HCTtoColor(
+ mTrackColor = ColorUtils.M3HCTToColor(
m3HCT[0],
16,
isDarkMode ? 30 : 90
);
// Plate color
- mPlateColor = ColorUtils.M3HCTtoColor(
+ mPlateColor = ColorUtils.M3HCTToColor(
m3HCT[0],
isDarkMode ? 36 : 24,
isDarkMode ? (isThemed() ? 10 : 20) : 80
diff --git a/src/com/android/launcher3/responsive/FolderSpecs.kt b/src/com/android/launcher3/responsive/FolderSpecs.kt
index be97cf8..f4446bc 100644
--- a/src/com/android/launcher3/responsive/FolderSpecs.kt
+++ b/src/com/android/launcher3/responsive/FolderSpecs.kt
@@ -188,12 +188,12 @@
}
data class CalculatedFolderSpec(
+ val availableSpace: Int,
+ val cells: Int,
val startPaddingPx: Int,
val endPaddingPx: Int,
val gutterPx: Int,
- val cellSizePx: Int,
- val availableSpace: Int,
- val cells: Int
+ val cellSizePx: Int
)
/**
@@ -270,11 +270,11 @@
cellSizePx = folderSpec.cellSize.getRemainderSpaceValue(remainderSpace, cellSizePx)
return CalculatedFolderSpec(
+ availableSpace = availableSpace,
+ cells = cells,
startPaddingPx = startPaddingPx,
endPaddingPx = endPaddingPx,
gutterPx = gutterPx,
- cellSizePx = cellSizePx,
- availableSpace = availableSpace,
- cells = cells
+ cellSizePx = cellSizePx
)
}
diff --git a/src/com/android/launcher3/statemanager/StatefulActivity.java b/src/com/android/launcher3/statemanager/StatefulActivity.java
index 520f33c..de5887f 100644
--- a/src/com/android/launcher3/statemanager/StatefulActivity.java
+++ b/src/com/android/launcher3/statemanager/StatefulActivity.java
@@ -237,4 +237,10 @@
* @param leftOrTop if the staged split will be positioned left or top.
*/
public void enterStageSplitFromRunningApp(boolean leftOrTop) { }
+
+
+ /** Returns whether the overview command helper queue is empty. */
+ public boolean isCommandQueueEmpty() {
+ return true;
+ }
}
diff --git a/src/com/android/launcher3/util/IconSizeSteps.kt b/src/com/android/launcher3/util/IconSizeSteps.kt
new file mode 100644
index 0000000..2a5afe0
--- /dev/null
+++ b/src/com/android/launcher3/util/IconSizeSteps.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.util
+
+import android.content.res.Resources
+import androidx.core.content.res.getDimensionOrThrow
+import androidx.core.content.res.use
+import com.android.launcher3.R
+import kotlin.math.max
+
+class IconSizeSteps(res: Resources) {
+ private val steps: List<Int>
+
+ init {
+ steps =
+ res.obtainTypedArray(R.array.icon_size_steps).use {
+ (0 until it.length()).map { step -> it.getDimensionOrThrow(step).toInt() }.sorted()
+ }
+ }
+
+ fun minimumIconSize(): Int = steps[0]
+
+ fun getNextLowerIconSize(iconSizePx: Int): Int {
+ return steps[max(0, getIndexForIconSize(iconSizePx) - 1)]
+ }
+
+ fun getIconSmallerThan(cellWidth: Int): Int {
+ return steps.lastOrNull { it <= cellWidth } ?: steps[0]
+ }
+
+ private fun getIndexForIconSize(iconSizePx: Int): Int {
+ return max(0, steps.indexOfFirst { iconSizePx <= it })
+ }
+}
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index 6a9aedf..ca80c51 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -21,6 +21,7 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
import android.util.AttributeSet;
import android.view.View;
@@ -62,16 +63,18 @@
}
@Override
+ protected boolean onSetAlpha(int alpha) {
+ updateSysUiColors();
+ dispatchVisibilityListenersIfNeeded();
+ return super.onSetAlpha(alpha);
+ }
+
+ @Override
public void setBackgroundColor(int color) {
mBackgroundColor = color;
- dispatchVisibilityListenersIfNeeded();
- if (Color.alpha(color) == 0) {
- setAlpha(0);
- } else {
- setAlpha(1);
- super.setBackgroundColor(color);
- }
updateSysUiColors();
+ dispatchVisibilityListenersIfNeeded();
+ super.setBackgroundColor(color);
}
public int getBackgroundColor() {
@@ -86,7 +89,7 @@
}
public boolean isFullyOpaque() {
- return mIsVisible && getAlpha() == 1;
+ return mIsVisible && getAlpha() == 1 && Color.alpha(mBackgroundColor) == 255;
}
@Override
@@ -117,7 +120,8 @@
// status bar.
final float threshold = STATUS_BAR_COLOR_FORCE_UPDATE_THRESHOLD;
boolean forceChange = getVisibility() == VISIBLE
- && getAlpha() > threshold;
+ && getAlpha() > threshold
+ && (Color.alpha(mBackgroundColor) / 255f) > threshold;
if (forceChange) {
getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, !isScrimDark());
} else {
@@ -144,7 +148,13 @@
}
private boolean isScrimDark() {
- return ColorUtils.calculateLuminance(mBackgroundColor) < 0.5f;
+ if (!(getBackground() instanceof ColorDrawable)) {
+ throw new IllegalStateException(
+ "ScrimView must have a ColorDrawable background, this one has: "
+ + getBackground());
+ }
+ return ColorUtils.calculateLuminance(
+ ((ColorDrawable) getBackground()).getColor()) < 0.5f;
}
/**
diff --git a/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt b/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
index c91a4a9..0a95771 100644
--- a/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
+++ b/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
@@ -84,7 +84,8 @@
"\tfolderChildIconSizePx: 147.0px (56.0dp)\n" +
"\tfolderChildTextSizePx: 38.0px (14.476191dp)\n" +
"\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
- "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
"\tfolderTopPadding: 63.0px (24.0dp)\n" +
"\tfolderFooterHeight: 147.0px (56.0dp)\n" +
@@ -220,7 +221,8 @@
"\tfolderChildIconSizePx: 147.0px (56.0dp)\n" +
"\tfolderChildTextSizePx: 38.0px (14.476191dp)\n" +
"\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
- "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
"\tfolderTopPadding: 63.0px (24.0dp)\n" +
"\tfolderFooterHeight: 147.0px (56.0dp)\n" +
@@ -356,7 +358,8 @@
"\tfolderChildIconSizePx: 131.0px (49.904762dp)\n" +
"\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
"\tfolderChildDrawablePaddingPx: 9.0px (3.4285715dp)\n" +
- "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
"\tfolderTopPadding: 56.0px (21.333334dp)\n" +
"\tfolderFooterHeight: 131.0px (49.904762dp)\n" +
@@ -492,7 +495,8 @@
"\tfolderChildIconSizePx: 123.0px (46.857143dp)\n" +
"\tfolderChildTextSizePx: 32.0px (12.190476dp)\n" +
"\tfolderChildDrawablePaddingPx: 8.0px (3.047619dp)\n" +
- "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
"\tfolderTopPadding: 53.0px (20.190475dp)\n" +
"\tfolderFooterHeight: 123.0px (46.857143dp)\n" +
@@ -629,7 +633,8 @@
"\tfolderChildIconSizePx: 120.0px (60.0dp)\n" +
"\tfolderChildTextSizePx: 28.0px (14.0dp)\n" +
"\tfolderChildDrawablePaddingPx: 16.0px (8.0dp)\n" +
- "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 0.0px (0.0dp)\n" +
"\tfolderTopPadding: 48.0px (24.0dp)\n" +
"\tfolderFooterHeight: 112.0px (56.0dp)\n" +
@@ -766,7 +771,8 @@
"\tfolderChildIconSizePx: 120.0px (60.0dp)\n" +
"\tfolderChildTextSizePx: 28.0px (14.0dp)\n" +
"\tfolderChildDrawablePaddingPx: 16.0px (8.0dp)\n" +
- "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 0.0px (0.0dp)\n" +
"\tfolderTopPadding: 48.0px (24.0dp)\n" +
"\tfolderFooterHeight: 112.0px (56.0dp)\n" +
@@ -903,7 +909,8 @@
"\tfolderChildIconSizePx: 120.0px (60.0dp)\n" +
"\tfolderChildTextSizePx: 28.0px (14.0dp)\n" +
"\tfolderChildDrawablePaddingPx: 27.0px (13.5dp)\n" +
- "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 0.0px (0.0dp)\n" +
"\tfolderTopPadding: 48.0px (24.0dp)\n" +
"\tfolderFooterHeight: 112.0px (56.0dp)\n" +
@@ -1040,7 +1047,8 @@
"\tfolderChildIconSizePx: 120.0px (60.0dp)\n" +
"\tfolderChildTextSizePx: 28.0px (14.0dp)\n" +
"\tfolderChildDrawablePaddingPx: 27.0px (13.5dp)\n" +
- "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 0.0px (0.0dp)\n" +
"\tfolderTopPadding: 48.0px (24.0dp)\n" +
"\tfolderFooterHeight: 112.0px (56.0dp)\n" +
@@ -1182,7 +1190,8 @@
"\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
"\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
"\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
- "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
"\tfolderTopPadding: 63.0px (24.0dp)\n" +
"\tfolderFooterHeight: 147.0px (56.0dp)\n" +
@@ -1323,7 +1332,8 @@
"\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
"\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
"\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
- "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
"\tfolderTopPadding: 63.0px (24.0dp)\n" +
"\tfolderFooterHeight: 147.0px (56.0dp)\n" +
@@ -1464,7 +1474,8 @@
"\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
"\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
"\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
- "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
"\tfolderTopPadding: 63.0px (24.0dp)\n" +
"\tfolderFooterHeight: 147.0px (56.0dp)\n" +
@@ -1601,7 +1612,8 @@
"\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
"\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
"\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
- "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.x: 0.0px (0.0dp)\n" +
+ "\tfolderCellLayoutBorderSpacePx.y: 0.0px (0.0dp)\n" +
"\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
"\tfolderTopPadding: 63.0px (24.0dp)\n" +
"\tfolderFooterHeight: 147.0px (56.0dp)\n" +
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index e427560..095b135 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -30,7 +30,6 @@
import android.content.Intent;
import android.graphics.Point;
import android.os.SystemClock;
-import android.platform.test.annotations.IwTest;
import android.platform.test.annotations.PlatinumTest;
import android.util.Log;
@@ -240,7 +239,6 @@
}
@PlatinumTest(focusArea = "launcher")
- @IwTest(focusArea = "launcher")
@Test
@ScreenRecord // b/202433017
public void testWorkspace() throws Exception {
@@ -375,7 +373,6 @@
}
@PlatinumTest(focusArea = "launcher")
- @IwTest(focusArea = "launcher")
@Test
@PortraitLandscape
@ScreenRecord // b/256898879
diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
index b869c9f..435649b 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
@@ -20,7 +20,6 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import android.platform.test.annotations.IwTest;
import android.platform.test.annotations.PlatinumTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -52,7 +51,6 @@
public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
@PlatinumTest(focusArea = "launcher")
- @IwTest(focusArea="launcher")
@Test
@PortraitLandscape
public void testDragIcon() throws Throwable {
diff --git a/tests/src/com/android/launcher3/util/IconSizeStepsTest.kt b/tests/src/com/android/launcher3/util/IconSizeStepsTest.kt
new file mode 100644
index 0000000..d9e3377
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/IconSizeStepsTest.kt
@@ -0,0 +1,67 @@
+/*
+ * 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.util
+
+import android.content.Context
+import android.content.res.Configuration
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.*
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class IconSizeStepsTest {
+ private var context: Context? = null
+ private val runningContext: Context = ApplicationProvider.getApplicationContext()
+ private lateinit var iconSizeSteps: IconSizeSteps
+
+ @Before
+ fun setup() {
+ // 160dp makes 1px = 1dp
+ val config =
+ Configuration(runningContext.resources.configuration).apply { this.densityDpi = 160 }
+ context = runningContext.createConfigurationContext(config)
+ iconSizeSteps = IconSizeSteps(context!!.resources)
+ }
+
+ @Test
+ fun minimumIconSize() {
+ assertThat(iconSizeSteps.minimumIconSize()).isEqualTo(52)
+ }
+
+ @Test
+ fun getNextLowerIconSize() {
+ assertThat(iconSizeSteps.getNextLowerIconSize(66)).isEqualTo(63)
+
+ // Assert that never goes below minimum
+ assertThat(iconSizeSteps.getNextLowerIconSize(52)).isEqualTo(52)
+ assertThat(iconSizeSteps.getNextLowerIconSize(30)).isEqualTo(52)
+ }
+
+ @Test
+ fun getIconSmallerThan() {
+ assertThat(iconSizeSteps.getIconSmallerThan(60)).isEqualTo(59)
+
+ // Assert that never goes below minimum
+ assertThat(iconSizeSteps.getIconSmallerThan(52)).isEqualTo(52)
+ assertThat(iconSizeSteps.getIconSmallerThan(30)).isEqualTo(52)
+ }
+}