Merge changes from topic "windowRecents" into main
* changes:
Cleaning up unusued handlers
Moving RecentsWindowManager away from the singleton pattern
Limited recents in window introductory cl
abstracting fallback views to support container instead of activity
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index bf198b6..57bfb4a 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -54,6 +54,7 @@
android:protectionLevel="signature|privileged" />
<application android:backupAgent="com.android.launcher3.LauncherBackupAgent"
+ android:enableOnBackInvokedCallback="true"
android:fullBackupOnly="true"
android:fullBackupContent="@xml/backupscheme"
android:hardwareAccelerated="true"
diff --git a/quickstep/res/drawable/taskbar_overflow_icon.xml b/quickstep/res/drawable/taskbar_overflow_icon.xml
new file mode 100644
index 0000000..b93a70e
--- /dev/null
+++ b/quickstep/res/drawable/taskbar_overflow_icon.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportHeight="960"
+ android:viewportWidth="960">
+ <path
+ android:fillColor="@color/taskbar_divider_background"
+ android:pathData="M80,605v-250q0,-28.88 20.59,-49.44t49.5,-20.56q28.91,0 49.41,20.56Q220,326.12 220,355v250q0,28.87 -20.59,49.44Q178.82,675 149.91,675t-49.41,-20.56Q80,633.87 80,605ZM340,760q-24,0 -42,-18t-18,-42v-440q0,-24 18,-42t42,-18h280q24,0 42,18t18,42v440q0,24 -18,42t-42,18L340,760ZM740,605v-250q0,-28.88 20.59,-49.44t49.5,-20.56q28.91,0 49.41,20.56Q880,326.12 880,355v250q0,28.87 -20.59,49.44Q838.82,675 809.91,675t-49.41,-20.56Q740,633.87 740,605ZM340,700h280v-440L340,260v440ZM480,480Z"/>
+</vector>
diff --git a/quickstep/res/layout/bubblebar_flyout.xml b/quickstep/res/layout/bubblebar_flyout.xml
index ff5047f..fc1e914 100644
--- a/quickstep/res/layout/bubblebar_flyout.xml
+++ b/quickstep/res/layout/bubblebar_flyout.xml
@@ -20,11 +20,12 @@
<ImageView
android:id="@+id/bubble_flyout_avatar"
- android:layout_width="36dp"
+ android:layout_width="50dp"
android:layout_height="36dp"
- android:padding="@dimen/bubblebar_flyout_avatar_message_space"
+ android:paddingEnd="@dimen/bubblebar_flyout_avatar_message_space"
android:scaleType="centerInside"
app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:src="#ff0000"/>
diff --git a/quickstep/res/layout/taskbar_overflow_button.xml b/quickstep/res/layout/taskbar_overflow_button.xml
new file mode 100644
index 0000000..20104f2
--- /dev/null
+++ b/quickstep/res/layout/taskbar_overflow_button.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Note: The actual size will match the taskbar icon sizes in TaskbarView#onLayout(). -->
+<com.android.launcher3.views.IconButtonView xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/BaseIcon.Workspace.Taskbar"
+ android:layout_width="@dimen/taskbar_icon_min_touch_size"
+ android:layout_height="@dimen/taskbar_icon_min_touch_size"
+ android:backgroundTint="@android:color/transparent"
+ android:contentDescription="@string/taskbar_overflow_a11y_title" />
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index e99e9b5..8957e0d 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -480,11 +480,15 @@
<dimen name="bubble_expanded_view_drop_target_margin">16dp</dimen>
<!-- Bubble bar flyout view -->
- <dimen name="bubblebar_flyout_padding_horizontal">14dp</dimen>
- <dimen name="bubblebar_flyout_padding_vertical">10dp</dimen>
+ <dimen name="bubblebar_flyout_padding">16dp</dimen>
<dimen name="bubblebar_flyout_elevation">4dp</dimen>
- <dimen name="bubblebar_flyout_avatar_message_space">6dp</dimen>
- <dimen name="bubblebar_flyout_max_width">96dp</dimen>
+ <dimen name="bubblebar_flyout_avatar_message_space">14dp</dimen>
+ <dimen name="bubblebar_flyout_min_width">238dp</dimen>
+ <dimen name="bubblebar_flyout_max_width">276dp</dimen>
+ <dimen name="bubblebar_flyout_triangle_width">12dp</dimen>
+ <dimen name="bubblebar_flyout_triangle_height">10dp</dimen>
+ <dimen name="bubblebar_flyout_triangle_overlap_amount">1dp</dimen>
+ <dimen name="bubblebar_flyout_triangle_radius">2dp</dimen>
<!-- Launcher splash screen -->
<!-- Note: keep this value in sync with the WindowManager/Shell dimens.xml -->
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index f72f3c5..008766b 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -320,6 +320,8 @@
<string name="change_navigation_mode">Change navigation mode</string>
<!-- Accessibility title for the Taskbar vertical divider icon. [CHAR_LIMIT=NONE] -->
<string name="taskbar_divider_a11y_title">Taskbar Divider</string>
+ <!-- Accessibility title for the Taskbar Overflow icon. [CHAR_LIMIT=NONE] -->
+ <string name="taskbar_overflow_a11y_title">Taskbar Overflow</string>
<!-- Label for moving drop target to the top or left side of the screen, depending on orientation (from the Taskbar only). -->
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index 4e6d00a..3dcb2ac 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -253,7 +253,7 @@
for (DesktopVisibilityListener listener : mDesktopVisibilityListeners) {
listener.onDesktopVisibilityChanged(areDesktopTasksVisible);
}
- DisplayController.handleInfoChangeForDesktopMode(mContext);
+ DisplayController.INSTANCE.get(mContext).notifyConfigChange();
}
private void notifyTaskbarDesktopModeListeners(boolean doesAnyTaskRequireTaskbarRounding) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
index b4102a9..fc8204a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
@@ -58,8 +58,12 @@
import java.util.Locale;
/**
- * View that allows quick switching between recent tasks through keyboard alt-tab and alt-shift-tab
- * commands.
+ * View that allows quick switching between recent tasks.
+ *
+ * Can be access via:
+ * - keyboard alt-tab
+ * - alt-shift-tab
+ * - taskbar overflow button
*/
public class KeyboardQuickSwitchView extends ConstraintLayout {
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 02201c0..477f90c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -24,7 +24,6 @@
import android.animation.Animator;
import android.animation.AnimatorSet;
-import android.graphics.Rect;
import android.window.RemoteTransition;
import androidx.annotation.NonNull;
@@ -128,7 +127,7 @@
@Override
protected void onDestroy() {
- onLauncherVisibilityChanged(false);
+ onLauncherVisibilityChanged(false /* isVisible */, true /* fromInitOrDestroy */);
super.onDestroy();
mTaskbarLauncherStateController.onDestroy();
@@ -190,38 +189,20 @@
}
/**
- * Returns the bounds of launcher's hotseat.
- */
- public void getHotseatBounds(Rect hotseatBoundsOut) {
- DeviceProfile launcherDP = mLauncher.getDeviceProfile();
- if (launcherDP.isQsbInline) {
- // Not currently supported.
- hotseatBoundsOut.setEmpty();
- return;
- }
- int left = (launcherDP.widthPx - launcherDP.getHotseatWidthPx()
- - mLauncher.getHotseat().getUnusedHorizontalSpace()) / 2;
- int right = left + launcherDP.getHotseatWidthPx();
- int bottom = launcherDP.getHotseatLayoutPadding(mLauncher).bottom;
- int top = bottom - launcherDP.hotseatCellHeightPx;
- hotseatBoundsOut.set(left, top, right, bottom);
- }
-
- /**
* Should be called from onResume() and onPause(), and animates the Taskbar accordingly.
*/
@Override
public void onLauncherVisibilityChanged(boolean isVisible) {
if (DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(mLauncher)) {
- DisplayController.handleInfoChangeForLauncherVisibilityChanged(mLauncher);
+ DisplayController.INSTANCE.get(mLauncher).notifyConfigChange();
}
onLauncherVisibilityChanged(isVisible, false /* fromInit */);
}
- private void onLauncherVisibilityChanged(boolean isVisible, boolean fromInit) {
+ private void onLauncherVisibilityChanged(boolean isVisible, boolean fromInitOrDestroy) {
onLauncherVisibilityChanged(
isVisible,
- fromInit,
+ fromInitOrDestroy,
/* startAnimation= */ true,
DisplayController.isTransientTaskbar(mLauncher)
? TRANSIENT_TASKBAR_TRANSITION_DURATION
@@ -232,7 +213,7 @@
@Nullable
private Animator onLauncherVisibilityChanged(
- boolean isVisible, boolean fromInit, boolean startAnimation, int duration) {
+ boolean isVisible, boolean fromInitOrDestroy, boolean startAnimation, int duration) {
// Launcher is resumed during the swipe-to-overview gesture under shell-transitions, so
// avoid updating taskbar state in that situation (when it's non-interactive -- or
// "background") to avoid premature animations.
@@ -250,7 +231,7 @@
}
mTaskbarLauncherStateController.updateStateForFlag(FLAG_VISIBLE, isVisible);
- if (fromInit || mControllers == null) {
+ if (fromInitOrDestroy) {
duration = 0;
}
return mTaskbarLauncherStateController.applyState(duration, startAnimation);
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index e9bd30a..2ac5793 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -400,12 +400,6 @@
}
};
mSeparateWindowParent.recreateControllers();
- if (com.android.wm.shell.Flags.enableBubbleBarInPersistentTaskBar()
- && mControllers.bubbleControllers.isPresent()) {
- BubbleBarLocation bubblesLocation = mControllers.bubbleControllers.get()
- .bubbleBarViewController.getBubbleBarLocation();
- onBubbleBarLocationUpdated(bubblesLocation);
- }
}
private void initButtons(ViewGroup navContainer, ViewGroup endContainer,
@@ -1223,6 +1217,16 @@
return (int) navBarTargetStartX - mNavButtonContainer.getLeft();
}
+ /** Adjusts the navigation buttons layout position according to the bubble bar location. */
+ public void onTaskbarLayoutChange() {
+ if (com.android.wm.shell.Flags.enableBubbleBarInPersistentTaskBar()
+ && mControllers.bubbleControllers.isPresent()) {
+ BubbleBarLocation bubblesLocation = mControllers.bubbleControllers.get()
+ .bubbleBarViewController.getBubbleBarLocation();
+ onBubbleBarLocationUpdated(bubblesLocation);
+ }
+ }
+
private class RotationButtonListener implements RotationButton.RotationButtonUpdatesCallback {
@Override
public void onVisibilityChanged(boolean isVisible) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/NewWindowTaskbarShortcut.kt b/quickstep/src/com/android/launcher3/taskbar/NewWindowTaskbarShortcut.kt
new file mode 100644
index 0000000..dc66e0b
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/NewWindowTaskbarShortcut.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import android.content.Context
+import android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK
+import android.view.View
+import com.android.launcher3.AbstractFloatingView
+import com.android.launcher3.R
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.popup.SystemShortcut
+import com.android.launcher3.views.ActivityContext
+
+/**
+ * A single menu item shortcut to execute creating a new instance of an app. Default interaction for
+ * [onClick] is to launch the app in full screen or as a floating window in Desktop Mode.
+ */
+class NewWindowTaskbarShortcut<T>(target: T, itemInfo: ItemInfo?, originalView: View?) :
+ SystemShortcut<T>(
+ R.drawable.desktop_mode_ic_taskbar_menu_new_window,
+ R.string.new_window_option_taskbar,
+ target,
+ itemInfo,
+ originalView
+ ) where T : Context?, T : ActivityContext? {
+
+ override fun onClick(v: View?) {
+ val intent = mItemInfo.intent ?: return
+ intent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK)
+ mTarget?.startActivitySafely(v, intent, mItemInfo)
+ AbstractFloatingView.closeAllOpenViews(mTarget)
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index fabf3a5..7273fac 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -208,11 +208,8 @@
* Creates and returns a {@link RevealOutlineAnimation} Animator that updates the stashed handle
* shape and size. When stashed, the shape is a thin rounded pill. When unstashed, the shape
* morphs into the size of where the taskbar icons will be.
- *
- * @param taskbarToHotseatOffsets A Rect of offsets used to transform the bounds of the
- * stashed handle to wrap around the hotseat items.
*/
- public Animator createRevealAnimToIsStashed(boolean isStashed, Rect taskbarToHotseatOffsets) {
+ public Animator createRevealAnimToIsStashed(boolean isStashed) {
Rect visualBounds = mControllers.taskbarViewController.getIconLayoutVisualBounds();
float startRadius = mStashedHandleRadius;
@@ -223,13 +220,6 @@
visualBounds.bottom += heightDiff;
startRadius = visualBounds.height() / 2f;
-
- // We use these offsets to create a larger stashed handle to wrap around the items
- // of the hotseat. This is only used for certain animations.
- visualBounds.top += taskbarToHotseatOffsets.top;
- visualBounds.bottom += taskbarToHotseatOffsets.bottom;
- visualBounds.left += taskbarToHotseatOffsets.left;
- visualBounds.right += taskbarToHotseatOffsets.right;
}
final RevealOutlineAnimation handleRevealProvider = new RoundedRectRevealOutlineProvider(
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index b95c406..c355e46 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -29,6 +29,7 @@
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_OVERLAY_PROXY;
import static com.android.launcher3.Flags.enableCursorHoverStates;
+import static com.android.launcher3.Flags.taskbarOverflow;
import static com.android.launcher3.Utilities.calculateTextHeight;
import static com.android.launcher3.Utilities.isRunningInTestHarness;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
@@ -361,38 +362,6 @@
}
/**
- * Calculate the offsets needed to transform the transient taskbar bounds to the hotseat bounds.
- * @return The offsets will be stored in a Rect
- */
- public Rect calculateTaskbarToHotseatOffsets(Rect hotseatBounds) {
- Rect taskbar = getTransientTaskbarBounds();
- Rect offsets = new Rect();
-
- offsets.left = hotseatBounds.left - taskbar.left;
- offsets.right = hotseatBounds.right - taskbar.right;
-
- int heightDiff = hotseatBounds.height() - taskbar.height();
- offsets.top = (taskbar.height() - heightDiff) / 2;
-
- int gleanedTaskbarPadding = (mDeviceProfile.taskbarHeight
- - getTransientTaskbarBounds().height()) / 2;
- offsets.left -= gleanedTaskbarPadding;
- offsets.top -= gleanedTaskbarPadding;
- offsets.right += gleanedTaskbarPadding;
-
- // Bottom is relative to the bottom of layout, so we can calculate it with padding included.
- offsets.bottom = (hotseatBounds.height() - taskbar.height()) / 2;
-
- // Update bounds in taskbar background
- if (hotseatBounds.isEmpty()) {
- mDragLayer.getTaskbarToHotseatOffsetRect().setEmpty();
- } else {
- mDragLayer.getTaskbarToHotseatOffsetRect().set(offsets);
- }
- return offsets;
- }
-
- /**
* Copy the original DeviceProfile, match the number of hotseat icons and qsb width and update
* the icon size
*/
@@ -1221,6 +1190,11 @@
RecentsView recents = taskbarUIController.getRecentsView();
boolean shouldCloseAllOpenViews = true;
Object tag = view.getTag();
+
+ if (taskbarOverflow()) {
+ mControllers.keyboardQuickSwitchController.closeQuickSwitchView(false);
+ }
+
if (tag instanceof GroupTask groupTask) {
handleGroupTaskLaunch(
groupTask,
@@ -1711,18 +1685,6 @@
}
/**
- * Returns the bounds of launcher's hotseat (if exists).
- */
- public void getHotseatBounds(Rect hotseatBoundsOut) {
- TaskbarUIController uiController = mControllers.uiController;
- if (uiController instanceof LauncherTaskbarUIController launcherController) {
- launcherController.getHotseatBounds(hotseatBoundsOut);
- } else {
- hotseatBoundsOut.setEmpty();
- }
- }
-
- /**
* Called when we determine the touchable region.
*
* @param exclude {@code true} then the magnification region computation will omit the window.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index d6ce3a4..c0e921e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -21,7 +21,6 @@
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
-import android.graphics.Rect
import android.graphics.RectF
import com.android.app.animation.Interpolators
import com.android.internal.policy.ScreenDecorationsUtils
@@ -60,9 +59,6 @@
var translationYForSwipe = 0f
var translationYForStash = 0f
- // When not empty, we can use this to transform transient taskbar background to hotseat bounds.
- val taskbarToHotseatOffsetRect = Rect()
-
private val transientBackgroundBounds = context.transientTaskbarBounds
private val shadowAlpha: Float
@@ -230,12 +226,6 @@
val radius = newBackgroundHeight / 2f
val bottomMarginProgress = bottomMargin * ((1f - progress) / 2f)
- // Used to transform the background so that it wraps around the items on the hotseat.
- val hotseatOffsetLeft = taskbarToHotseatOffsetRect.left * progress
- val hotseatOffsetTop = taskbarToHotseatOffsetRect.top * progress
- val hotseatOffsetRight = taskbarToHotseatOffsetRect.right * progress
- val hotseatOffsetBottom = taskbarToHotseatOffsetRect.bottom * progress
-
// Aligns the bottom with the bottom of the stashed handle.
val bottom =
canvas.height - bottomMargin +
@@ -260,10 +250,10 @@
strokePaint.alpha = (paint.alpha * strokeAlpha) / 255
lastDrawnTransientRect.set(
- transientBackgroundBounds.left + halfWidthDelta + hotseatOffsetLeft,
- bottom - newBackgroundHeight + hotseatOffsetTop,
- transientBackgroundBounds.right - halfWidthDelta + hotseatOffsetRight,
- bottom + hotseatOffsetBottom,
+ transientBackgroundBounds.left + halfWidthDelta,
+ bottom - newBackgroundHeight,
+ transientBackgroundBounds.right - halfWidthDelta,
+ bottom
)
val horizontalInset = fullWidth * widthInsetPercentage
lastDrawnTransientRect.inset(horizontalInset, 0f)
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index 53bd3d7..e16c76d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -22,7 +22,6 @@
import android.content.Context;
import android.graphics.Canvas;
-import android.graphics.Rect;
import android.graphics.RectF;
import android.media.permission.SafeCloseable;
import android.util.AttributeSet;
@@ -260,11 +259,6 @@
return mBackgroundRenderer.getLastDrawnTransientRect();
}
- /** Returns the rect used to transform transient taskbar to the hotseat */
- public Rect getTaskbarToHotseatOffsetRect() {
- return mBackgroundRenderer.getTaskbarToHotseatOffsetRect();
- }
-
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 5024cd8..bdefea6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -250,6 +250,7 @@
Map<PackageUserKey, Integer> packageUserKeytoUidMap) {
Preconditions.assertUIThread();
mControllers.taskbarAllAppsController.setApps(apps, flags, packageUserKeytoUidMap);
+ mControllers.taskbarPopupController.setApps(apps);
}
protected void dumpLogs(String prefix, PrintWriter pw) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index 2cee77d..70d4bb1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR;
import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition;
import android.content.Intent;
@@ -29,11 +30,13 @@
import com.android.internal.logging.InstanceId;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.Flags;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.dot.FolderDotInfo;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -51,9 +54,11 @@
import com.android.launcher3.views.ActivityContext;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.LogUtils;
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
@@ -79,6 +84,7 @@
// Initialized in init.
private TaskbarControllers mControllers;
private boolean mAllowInitialSplitSelection;
+ private AppInfo[] mAppInfosList;
public TaskbarPopupController(TaskbarActivityContext context) {
mContext = context;
@@ -195,6 +201,10 @@
if (com.android.wm.shell.Flags.enableBubbleAnything()) {
shortcuts.add(BUBBLE);
}
+ if (Flags.enableMultiInstanceMenuTaskbar()
+ && DesktopModeStatus.canEnterDesktopMode(mContext)) {
+ shortcuts.addAll(getMultiInstanceMenuOptions().toList());
+ }
return shortcuts.stream();
}
@@ -258,7 +268,55 @@
originalView, position, mAllowInitialSplitSelection);
}
- /**
+ /**
+ * Set the list of AppInfos to be able to pull from later
+ */
+ public void setApps(AppInfo[] apps) {
+ mAppInfosList = apps;
+ }
+
+ /**
+ * Finds and returns an AppInfo object from a list, using its ComponentKey for identification.
+ * Based off of {@link com.android.launcher3.allapps.AllAppsStore#getApp(ComponentKey)}
+ * since we cannot access AllAppsStore from here.
+ */
+ public AppInfo getApp(ComponentKey key) {
+ if (key == null) {
+ return null;
+ }
+ AppInfo tempInfo = new AppInfo();
+ tempInfo.componentName = key.componentName;
+ tempInfo.user = key.user;
+ int index = Arrays.binarySearch(mAppInfosList, tempInfo, COMPONENT_KEY_COMPARATOR);
+ return index < 0 ? null : mAppInfosList[index];
+ }
+
+ /**
+ * Returns a stream of Multi Instance menu options if an app supports it.
+ */
+ Stream<SystemShortcut.Factory<BaseTaskbarContext>> getMultiInstanceMenuOptions() {
+ SystemShortcut.Factory<BaseTaskbarContext> factory = createNewWindowShortcutFactory();
+ return factory != null ? Stream.of(factory) : Stream.empty();
+
+ }
+
+ /**
+ * Creates a factory function representing a "New Window" menu item only if the calling app
+ * supports multi-instance.
+ * @return A factory function to be used in populating the long-press menu.
+ */
+ SystemShortcut.Factory<BaseTaskbarContext> createNewWindowShortcutFactory() {
+ return (context, itemInfo, originalView) -> {
+ ComponentKey key = itemInfo.getComponentKey();
+ AppInfo app = getApp(key);
+ if (app != null && app.supportsMultiInstance()) {
+ return new NewWindowTaskbarShortcut<>(context, itemInfo, originalView);
+ }
+ return null;
+ };
+ }
+
+ /**
* A single menu item ("Split left," "Split right," or "Split top") that executes a split
* from the taskbar, as if the user performed a drag and drop split.
* Includes an onClick method that initiates the actual split.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 7624afb..266f384 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -42,7 +42,6 @@
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.app.RemoteAction;
-import android.graphics.Rect;
import android.graphics.drawable.Icon;
import android.os.SystemClock;
import android.util.Log;
@@ -209,7 +208,6 @@
* by not scaling the height of the taskbar background.
*/
private static final int TRANSITION_UNSTASH_SUW_MANUAL = 3;
- private static final Rect EMPTY_RECT = new Rect();
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
@@ -771,7 +769,7 @@
}
fullLengthAnimatorSet.play(mControllers.stashedHandleViewController
- .createRevealAnimToIsStashed(isStashed, EMPTY_RECT));
+ .createRevealAnimToIsStashed(isStashed));
// Return the stashed handle to its default scale in case it was changed as part of the
// feedforward hint. Note that the reveal animation above also visually scales it.
fullLengthAnimatorSet.play(mTaskbarStashedHandleHintScale.animateToValue(1f));
@@ -821,19 +819,6 @@
}
}
-
- Rect taskbarToHotseatOffsets = new Rect();
- if (enableScalingRevealHomeAnimation() && animationType == TRANSITION_HOME_TO_APP) {
- Rect hotseatRect = new Rect();
- mActivity.getHotseatBounds(hotseatRect);
-
- // Calculate and store offsets so that we can sync with the taskbar stashed handle
- taskbarToHotseatOffsets.set(
- mActivity.calculateTaskbarToHotseatOffsets(hotseatRect));
- as.addListener(AnimatorListeners.forEndCallback(
- () -> mActivity.calculateTaskbarToHotseatOffsets(EMPTY_RECT)));
- }
-
play(as, mTaskbarStashedHandleAlpha.animateToValue(stashedHandleAlphaTarget),
backgroundAndHandleAlphaStartDelay,
backgroundAndHandleAlphaDuration, LINEAR);
@@ -882,12 +867,10 @@
}
mControllers.taskbarViewController.addRevealAnimToIsStashed(skippable, isStashed, duration,
- EMPHASIZED, animationType == TRANSITION_UNSTASH_SUW_MANUAL,
- animationType == TRANSITION_HOME_TO_APP);
+ EMPHASIZED, animationType == TRANSITION_UNSTASH_SUW_MANUAL);
play(skippable, mControllers.stashedHandleViewController
- .createRevealAnimToIsStashed(isStashed, taskbarToHotseatOffsets), 0, duration,
- EMPHASIZED);
+ .createRevealAnimToIsStashed(isStashed), 0, duration, EMPHASIZED);
// Return the stashed handle to its default scale in case it was changed as part of the
// feedforward hint. Note that the reveal animation above also visually scales it.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 0389a11..2734137 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -46,6 +46,7 @@
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -63,6 +64,7 @@
import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.views.IconButtonView;
import com.android.quickstep.util.DesktopTask;
import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
@@ -100,9 +102,12 @@
// Only non-null when device supports having an All Apps button.
@Nullable private final TaskbarAllAppsButtonContainer mAllAppsButtonContainer;
- // Only non-null when device supports having an All Apps button.
+ // Only non-null when device supports having a Divider button.
@Nullable private TaskbarDividerContainer mTaskbarDividerContainer;
+ // Only non-null when device supports having a Taskbar Overflow button.
+ @Nullable private IconButtonView mTaskbarOverflowView;
+
/**
* Whether the divider is between Hotseat icons and Recents,
* instead of between All Apps button and Hotseat.
@@ -171,6 +176,13 @@
mTaskbarDividerContainer = new TaskbarDividerContainer(context);
}
+ if (Flags.taskbarOverflow()) {
+ mTaskbarOverflowView = (IconButtonView) LayoutInflater.from(context)
+ .inflate(R.layout.taskbar_overflow_button, this, false);
+ mTaskbarOverflowView.setIconDrawable(
+ resources.getDrawable(R.drawable.taskbar_overflow_icon));
+ mTaskbarOverflowView.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
+ }
// TODO: Disable touch events on QSB otherwise it can crash.
mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
}
@@ -263,6 +275,12 @@
if (mTaskbarDividerContainer != null && callbacks.supportsDividerLongPress()) {
mTaskbarDividerContainer.setUpCallbacks(callbacks);
}
+ if (mTaskbarOverflowView != null) {
+ mTaskbarOverflowView.setOnClickListener(
+ mControllerCallbacks.getOverflowOnClickListener());
+ mTaskbarOverflowView.setOnLongClickListener(
+ mControllerCallbacks.getOverflowOnLongClickListener());
+ }
}
private void removeAndRecycle(View view) {
@@ -290,6 +308,9 @@
removeView(mTaskbarDividerContainer);
}
}
+ if (mTaskbarOverflowView != null) {
+ removeView(mTaskbarOverflowView);
+ }
removeView(mQsb);
// Add Hotseat icons.
@@ -377,6 +398,9 @@
if (mTaskbarDividerContainer != null && !recentTasks.isEmpty()) {
addView(mTaskbarDividerContainer, nextViewIndex++);
mAddedDividerForRecents = true;
+ if (mTaskbarOverflowView != null) {
+ addView(mTaskbarOverflowView, nextViewIndex++);
+ }
}
// Add Recent/Running icons.
@@ -699,6 +723,14 @@
}
/**
+ * Returns the taskbar overflow view in the taskbar.
+ */
+ @Nullable
+ public IconButtonView getTaskbarOverflowView() {
+ return mTaskbarOverflowView;
+ }
+
+ /**
* Returns whether the divider is between Hotseat icons and Recents,
* instead of between All Apps button and Hotseat.
*/
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
index 5c8d439..d108d8c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
@@ -134,4 +134,25 @@
return Flags.enableBubbleBarInPersistentTaskBar()
&& mControllers.bubbleControllers.isPresent();
}
+
+ /** Returns on click listener for the taskbar overflow view. */
+ public View.OnClickListener getOverflowOnClickListener() {
+ return new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mControllers.keyboardQuickSwitchController.openQuickSwitchView();
+ }
+ };
+ }
+
+ /** Returns on long click listener for the taskbar overflow view. */
+ public View.OnLongClickListener getOverflowOnLongClickListener() {
+ return new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ mControllers.keyboardQuickSwitchController.openQuickSwitchView();
+ return true;
+ }
+ };
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index b663ccb..b207b37 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -36,7 +36,6 @@
import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_ALIGNMENT_ANIM;
import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_PINNING_ANIM;
import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_REVEAL_ANIM;
-import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
import android.animation.Animator;
import android.animation.AnimatorSet;
@@ -140,10 +139,6 @@
private final AnimatedFloat mTaskbarIconTranslationYForPinning = new AnimatedFloat(
this::updateTranslationY);
- private final View.OnLayoutChangeListener mTaskbarViewLayoutChangeListener =
- (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
- -> updateTaskbarIconTranslationXForPinning();
-
private AnimatedFloat mTaskbarNavButtonTranslationY;
private AnimatedFloat mTaskbarNavButtonTranslationYForInAppDisplay;
@@ -158,6 +153,12 @@
// Initialized in init.
private TaskbarControllers mControllers;
+ private final View.OnLayoutChangeListener mTaskbarViewLayoutChangeListener =
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+ updateTaskbarIconTranslationXForPinning();
+ mControllers.navbarButtonsViewController.onTaskbarLayoutChange();
+ };
+
// Animation to align icons with Launcher, created lazily. This allows the controller to be
// active only during the animation and does not need to worry about layout changes.
private AnimatorPlaybackController mIconAlignControllerLazy = null;
@@ -669,8 +670,7 @@
* @param interpolator The interpolator to use for all animations.
*/
public void addRevealAnimToIsStashed(AnimatorSet as, boolean isStashed, long duration,
- Interpolator interpolator, boolean dispatchOnAnimationStart,
- boolean isHomeToAppAnimation) {
+ Interpolator interpolator, boolean dispatchOnAnimationStart) {
AnimatorSet reveal = new AnimatorSet();
Rect stashedBounds = new Rect();
@@ -719,21 +719,8 @@
reveal.play(ObjectAnimator.ofFloat(mtd.getTranslationX(INDEX_TASKBAR_REVEAL_ANIM),
MULTI_PROPERTY_VALUE, transX)
.setDuration(duration));
-
- if (enableScalingRevealHomeAnimation()) {
- // Delay y-translation by 1 frame to keep icons within the bounds of the bg.
- int delay = isHomeToAppAnimation ? getSingleFrameMs(mActivity) : 0;
- ObjectAnimator yAnimator =
- ObjectAnimator.ofFloat(mtd.getTranslationY(INDEX_TASKBAR_REVEAL_ANIM),
- MULTI_PROPERTY_VALUE, transY)
- .setDuration(Math.max(0, duration - delay));
- yAnimator.setStartDelay(delay);
- reveal.play(yAnimator);
- } else {
- reveal.play(
- ObjectAnimator.ofFloat(mtd.getTranslationY(INDEX_TASKBAR_REVEAL_ANIM),
- MULTI_PROPERTY_VALUE, transY));
- }
+ reveal.play(ObjectAnimator.ofFloat(mtd.getTranslationY(INDEX_TASKBAR_REVEAL_ANIM),
+ MULTI_PROPERTY_VALUE, transY));
as.addListener(forEndCallback(() ->
mtd.setTranslation(INDEX_TASKBAR_REVEAL_ANIM, 0, 0)));
} else {
@@ -829,6 +816,7 @@
View child = mTaskbarView.getChildAt(i);
boolean isAllAppsButton = child == mTaskbarView.getAllAppsButtonContainer();
boolean isTaskbarDividerView = child == mTaskbarView.getTaskbarDividerViewContainer();
+ boolean isTaskbarOverflowView = child == mTaskbarView.getTaskbarOverflowView();
boolean isRecentTask = child.getTag() instanceof GroupTask;
// TODO(b/343522351): show recents on the home screen.
final boolean isRecentsInHotseat = false;
@@ -839,7 +827,8 @@
setter.setViewAlpha(child, 0, Interpolators.clampToProgress(LINEAR, 0.8f, 1f));
} else if ((isAllAppsButton && !FeatureFlags.enableAllAppsButtonInHotseat())
|| (isTaskbarDividerView && enableTaskbarPinning())
- || (isRecentTask && !isRecentsInHotseat)) {
+ || (isRecentTask && !isRecentsInHotseat)
+ || isTaskbarOverflowView) {
if (!isToHome
&& mIsHotseatIconOnTopWhenAligned
&& mIsStashed) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
index 152dcf7..4939c99 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
@@ -28,12 +28,12 @@
) {
private var flyout: BubbleBarFlyoutView? = null
- val horizontalMargin =
+ private val horizontalMargin =
container.context.resources.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin)
fun setUpFlyout(message: BubbleBarFlyoutMessage) {
flyout?.let(container::removeView)
- val flyout = BubbleBarFlyoutView(container.context)
+ val flyout = BubbleBarFlyoutView(container.context, onLeft = positioner.isOnLeft)
flyout.translationY = positioner.targetTy
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
index d3dc3f8..4b91f46 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
@@ -21,14 +21,17 @@
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
+import android.graphics.Path
import android.view.LayoutInflater
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import com.android.launcher3.R
+import com.android.launcher3.popup.RoundedArrowDrawable
/** The flyout view used to notify the user of a new bubble notification. */
-class BubbleBarFlyoutView(context: Context) : ConstraintLayout(context) {
+class BubbleBarFlyoutView(context: Context, private val onLeft: Boolean) :
+ ConstraintLayout(context) {
private val sender: TextView by
lazy(LazyThreadSafetyMode.NONE) { findViewById(R.id.bubble_flyout_name) }
@@ -39,9 +42,36 @@
private val message: TextView by
lazy(LazyThreadSafetyMode.NONE) { findViewById(R.id.bubble_flyout_text) }
- private val flyoutHorizontalPadding by
+ private val flyoutPadding by
lazy(LazyThreadSafetyMode.NONE) {
- context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding_horizontal)
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding)
+ }
+
+ private val triangleHeight by
+ lazy(LazyThreadSafetyMode.NONE) {
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_triangle_height)
+ }
+
+ private val triangleOverlap by
+ lazy(LazyThreadSafetyMode.NONE) {
+ context.resources.getDimensionPixelSize(
+ R.dimen.bubblebar_flyout_triangle_overlap_amount
+ )
+ }
+
+ private val triangleWidth by
+ lazy(LazyThreadSafetyMode.NONE) {
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_triangle_width)
+ }
+
+ private val triangleRadius by
+ lazy(LazyThreadSafetyMode.NONE) {
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_triangle_radius)
+ }
+
+ private val minFlyoutWidth by
+ lazy(LazyThreadSafetyMode.NONE) {
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_min_width)
}
private val maxFlyoutWidth by
@@ -50,6 +80,7 @@
}
private val cornerRadius: Float
+ private val triangle: Path = Path()
private var backgroundColor = Color.BLACK
/**
@@ -69,13 +100,19 @@
clipChildren = false
clipToPadding = false
- val horizontalPadding =
- context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding_horizontal)
- val verticalPadding =
- context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding_vertical)
- setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding)
+ val padding = context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding)
+ // add extra padding to the bottom of the view to include the triangle
+ setPadding(padding, padding, padding, padding + triangleHeight - triangleOverlap)
translationZ =
context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_elevation).toFloat()
+
+ RoundedArrowDrawable.addDownPointingRoundedTriangleToPath(
+ triangleWidth.toFloat(),
+ triangleHeight.toFloat(),
+ triangleRadius.toFloat(),
+ triangle,
+ )
+
applyConfigurationColors(resources.configuration)
}
@@ -88,15 +125,28 @@
avatar.visibility = GONE
}
- val maxTextViewWidth = maxFlyoutWidth - flyoutHorizontalPadding * 2
+ val minTextViewWidth: Int
+ val maxTextViewWidth: Int
+ if (avatar.visibility == VISIBLE) {
+ minTextViewWidth = minFlyoutWidth - avatar.width - flyoutPadding * 2
+ maxTextViewWidth = maxFlyoutWidth - avatar.width - flyoutPadding * 2
+ } else {
+ // when there's no avatar, the width of the text view is constant, so we're setting the
+ // min and max to the same value
+ minTextViewWidth = minFlyoutWidth - flyoutPadding * 2
+ maxTextViewWidth = minTextViewWidth
+ }
+
if (flyoutMessage.senderName.isEmpty()) {
sender.visibility = GONE
} else {
+ sender.minWidth = minTextViewWidth
sender.maxWidth = maxTextViewWidth
sender.text = flyoutMessage.senderName
sender.visibility = VISIBLE
}
+ message.minWidth = minTextViewWidth
message.maxWidth = maxTextViewWidth
message.text = flyoutMessage.message
}
@@ -106,14 +156,23 @@
0f,
0f,
width.toFloat(),
- height.toFloat(),
+ height.toFloat() - triangleHeight + triangleOverlap,
cornerRadius,
cornerRadius,
backgroundPaint,
)
+ drawTriangle(canvas)
super.onDraw(canvas)
}
+ private fun drawTriangle(canvas: Canvas) {
+ canvas.save()
+ val triangleX = if (onLeft) cornerRadius else width - cornerRadius - triangleWidth
+ canvas.translate(triangleX, (height - triangleHeight).toFloat())
+ canvas.drawPath(triangle, backgroundPaint)
+ canvas.restore()
+ }
+
private fun applyConfigurationColors(configuration: Configuration) {
val nightModeFlags = configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
val isNightModeOn = nightModeFlags == Configuration.UI_MODE_NIGHT_YES
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 32d8396..5082c11 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -681,10 +681,6 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
- // Back dispatcher is registered in {@link BaseActivity#onCreate}. For predictive back to
- // work, we must opt-in BEFORE registering back dispatcher. So we need to call
- // setEnableOnBackInvokedCallback() before super.onCreate()
- getApplicationInfo().setEnableOnBackInvokedCallback(true);
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mPendingSplitSelectInfo = ObjectWrapper.unwrap(
diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java
index 3cf0542..23a1ec7 100644
--- a/quickstep/src/com/android/quickstep/TopTaskTracker.java
+++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java
@@ -206,12 +206,17 @@
Collections.addAll(mOrderedTaskList, tasks);
}
- // Strip the pinned task
ArrayList<RunningTaskInfo> tasks = new ArrayList<>(mOrderedTaskList);
- tasks.removeIf(t -> t.taskId == mPinnedTaskId);
+ // Strip the pinned task and recents task
+ tasks.removeIf(t -> t.taskId == mPinnedTaskId || isRecentsTask(t));
return new CachedTaskInfo(tasks);
}
+ private static boolean isRecentsTask(RunningTaskInfo task) {
+ return task != null && task.configuration.windowConfiguration
+ .getActivityType() == ACTIVITY_TYPE_RECENTS;
+ }
+
/**
* Class to provide information about a task which can be safely cached and do not change
* during the lifecycle of the task.
@@ -267,8 +272,7 @@
}
public boolean isRecentsTask() {
- return mTopTask != null && mTopTask.configuration.windowConfiguration
- .getActivityType() == ACTIVITY_TYPE_RECENTS;
+ return TopTaskTracker.isRecentsTask(mTopTask);
}
/**
diff --git a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
index 658975c..88ef0a8 100644
--- a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
+++ b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
@@ -453,6 +453,10 @@
}
}
+ /**
+ * @param inSplitSelection Whether user currently has a task from this task group staged for
+ * split screen. Currently this state is not reachable in fake landscape.
+ */
override fun measureGroupedTaskViewThumbnailBounds(
primarySnapshot: View,
secondarySnapshot: View,
@@ -460,7 +464,8 @@
parentHeight: Int,
splitBoundsConfig: SplitBounds,
dp: DeviceProfile,
- isRtl: Boolean
+ isRtl: Boolean,
+ inSplitSelection: Boolean
) {
val primaryParams = primarySnapshot.layoutParams as FrameLayout.LayoutParams
val secondaryParams = secondarySnapshot.layoutParams as FrameLayout.LayoutParams
@@ -569,6 +574,10 @@
iconAppChipView.setRotation(degreesRotated)
}
+ /**
+ * @param inSplitSelection Whether user currently has a task from this task group staged for
+ * split screen. Currently this state is not reachable in fake landscape.
+ */
override fun setSplitIconParams(
primaryIconView: View,
secondaryIconView: View,
@@ -579,7 +588,8 @@
groupedTaskViewWidth: Int,
isRtl: Boolean,
deviceProfile: DeviceProfile,
- splitConfig: SplitBounds
+ splitConfig: SplitBounds,
+ inSplitSelection: Boolean
) {
val spaceAboveSnapshot = deviceProfile.overviewTaskThumbnailTopMarginPx
val totalThumbnailHeight = groupedTaskViewHeight - spaceAboveSnapshot
diff --git a/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
index cc022b2..c0b697d 100644
--- a/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
+++ b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
@@ -530,10 +530,16 @@
}
}
+ /**
+ * @param inSplitSelection Whether user currently has a task from this task group staged for
+ * split screen. If true, we have custom translations/scaling in place
+ * for the remaining snapshot, so we'll skip setting translation/scale
+ * here.
+ */
@Override
public void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot,
int parentWidth, int parentHeight, SplitBounds splitBoundsConfig,
- DeviceProfile dp, boolean isRtl) {
+ DeviceProfile dp, boolean isRtl, boolean inSplitSelection) {
int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx;
FrameLayout.LayoutParams primaryParams =
@@ -541,11 +547,10 @@
FrameLayout.LayoutParams secondaryParams =
(FrameLayout.LayoutParams) secondarySnapshot.getLayoutParams();
- // Reset margin and translations that aren't used in this method, but are used in other
+ // Reset margins that aren't used in this method, but are used in other
// `RecentsPagedOrientationHandler` variants.
secondaryParams.topMargin = 0;
primaryParams.topMargin = spaceAboveSnapshot;
- primarySnapshot.setTranslationY(0);
int totalThumbnailHeight = parentHeight - spaceAboveSnapshot;
float dividerScale = splitBoundsConfig.appsStackedVertically
@@ -553,28 +558,35 @@
: splitBoundsConfig.dividerWidthPercent;
Pair<Point, Point> taskViewSizes =
getGroupedTaskViewSizes(dp, splitBoundsConfig, parentWidth, parentHeight);
- if (dp.isLeftRightSplit) {
- int scaledDividerBar = Math.round(parentWidth * dividerScale);
- if (isRtl) {
- int translationX = taskViewSizes.second.x + scaledDividerBar;
- primarySnapshot.setTranslationX(-translationX);
- secondarySnapshot.setTranslationX(0);
+ if (!inSplitSelection) {
+ // Reset translations that aren't used in this method, but are used in other
+ // `RecentsPagedOrientationHandler` variants.
+ primarySnapshot.setTranslationY(0);
+
+ if (dp.isLeftRightSplit) {
+ int scaledDividerBar = Math.round(parentWidth * dividerScale);
+ if (isRtl) {
+ int translationX = taskViewSizes.second.x + scaledDividerBar;
+ primarySnapshot.setTranslationX(-translationX);
+ secondarySnapshot.setTranslationX(0);
+ } else {
+ int translationX = taskViewSizes.first.x + scaledDividerBar;
+ secondarySnapshot.setTranslationX(translationX);
+ primarySnapshot.setTranslationX(0);
+ }
+ secondarySnapshot.setTranslationY(spaceAboveSnapshot);
} else {
- int translationX = taskViewSizes.first.x + scaledDividerBar;
- secondarySnapshot.setTranslationX(translationX);
+ float finalDividerHeight = Math.round(totalThumbnailHeight * dividerScale);
+ float translationY =
+ taskViewSizes.first.y + spaceAboveSnapshot + finalDividerHeight;
+ secondarySnapshot.setTranslationY(translationY);
+
+ // Reset unused translations.
+ secondarySnapshot.setTranslationX(0);
primarySnapshot.setTranslationX(0);
}
-
- secondarySnapshot.setTranslationY(spaceAboveSnapshot);
- } else {
- float finalDividerHeight = Math.round(totalThumbnailHeight * dividerScale);
- float translationY = taskViewSizes.first.y + spaceAboveSnapshot + finalDividerHeight;
- secondarySnapshot.setTranslationY(translationY);
-
- // Reset unused translations.
- secondarySnapshot.setTranslationX(0);
- primarySnapshot.setTranslationX(0);
}
+
primarySnapshot.measure(
View.MeasureSpec.makeMeasureSpec(taskViewSizes.first.x, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(taskViewSizes.first.y, View.MeasureSpec.EXACTLY));
@@ -582,10 +594,6 @@
View.MeasureSpec.makeMeasureSpec(taskViewSizes.second.x, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(taskViewSizes.second.y,
View.MeasureSpec.EXACTLY));
- primarySnapshot.setScaleX(1);
- secondarySnapshot.setScaleX(1);
- primarySnapshot.setScaleY(1);
- secondarySnapshot.setScaleY(1);
}
@Override
@@ -662,11 +670,16 @@
iconAppChipView.setRotation(getDegreesRotated());
}
+ /**
+ * @param inSplitSelection Whether user currently has a task from this task group staged for
+ * split screen. If true, we have custom translations in place for the
+ * remaining icon, so we'll skip setting translations here.
+ */
@Override
public void setSplitIconParams(View primaryIconView, View secondaryIconView,
int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
- DeviceProfile deviceProfile, SplitBounds splitConfig) {
+ DeviceProfile deviceProfile, SplitBounds splitConfig, boolean inSplitSelection) {
FrameLayout.LayoutParams primaryIconParams =
(FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
FrameLayout.LayoutParams secondaryIconParams = enableOverviewIconMenu()
@@ -680,20 +693,23 @@
secondaryIconParams.gravity = TOP | START;
secondaryIconParams.topMargin = primaryIconParams.topMargin;
secondaryIconParams.setMarginStart(primaryIconParams.getMarginStart());
- if (deviceProfile.isLeftRightSplit) {
- if (isRtl) {
- int secondarySnapshotWidth = groupedTaskViewWidth - primarySnapshotWidth;
- primaryAppChipView.setSplitTranslationX(-secondarySnapshotWidth);
+ if (!inSplitSelection) {
+ if (deviceProfile.isLeftRightSplit) {
+ if (isRtl) {
+ int secondarySnapshotWidth = groupedTaskViewWidth - primarySnapshotWidth;
+ primaryAppChipView.setSplitTranslationX(-secondarySnapshotWidth);
+ } else {
+ secondaryAppChipView.setSplitTranslationX(primarySnapshotWidth);
+ }
} else {
- secondaryAppChipView.setSplitTranslationX(primarySnapshotWidth);
+ primaryAppChipView.setSplitTranslationX(0);
+ secondaryAppChipView.setSplitTranslationX(0);
+ int dividerThickness = Math.min(splitConfig.visualDividerBounds.width(),
+ splitConfig.visualDividerBounds.height());
+ secondaryAppChipView.setSplitTranslationY(
+ primarySnapshotHeight + (deviceProfile.isTablet ? 0
+ : dividerThickness));
}
- } else {
- primaryAppChipView.setSplitTranslationX(0);
- secondaryAppChipView.setSplitTranslationX(0);
- int dividerThickness = Math.min(splitConfig.visualDividerBounds.width(),
- splitConfig.visualDividerBounds.height());
- secondaryAppChipView.setSplitTranslationY(
- primarySnapshotHeight + (deviceProfile.isTablet ? 0 : dividerThickness));
}
} else if (deviceProfile.isLeftRightSplit) {
// We calculate the "midpoint" of the thumbnail area, and place the icons there.
@@ -716,46 +732,53 @@
if (deviceProfile.isSeascape()) {
primaryIconParams.gravity = TOP | (isRtl ? END : START);
secondaryIconParams.gravity = TOP | (isRtl ? END : START);
- if (splitConfig.initiatedFromSeascape) {
- // if the split was initiated from seascape,
- // the task on the right (secondary) is slightly larger
- primaryIconView.setTranslationX(bottomToMidpointOffset - taskIconHeight);
- secondaryIconView.setTranslationX(bottomToMidpointOffset);
- } else {
- // if not,
- // the task on the left (primary) is slightly larger
- primaryIconView.setTranslationX(bottomToMidpointOffset + insetOffset
- - taskIconHeight);
- secondaryIconView.setTranslationX(bottomToMidpointOffset + insetOffset);
+ if (!inSplitSelection) {
+ if (splitConfig.initiatedFromSeascape) {
+ // if the split was initiated from seascape,
+ // the task on the right (secondary) is slightly larger
+ primaryIconView.setTranslationX(bottomToMidpointOffset - taskIconHeight);
+ secondaryIconView.setTranslationX(bottomToMidpointOffset);
+ } else {
+ // if not,
+ // the task on the left (primary) is slightly larger
+ primaryIconView.setTranslationX(bottomToMidpointOffset + insetOffset
+ - taskIconHeight);
+ secondaryIconView.setTranslationX(bottomToMidpointOffset + insetOffset);
+ }
}
} else {
primaryIconParams.gravity = TOP | (isRtl ? START : END);
secondaryIconParams.gravity = TOP | (isRtl ? START : END);
- if (!splitConfig.initiatedFromSeascape) {
- // if the split was initiated from landscape,
- // the task on the left (primary) is slightly larger
- primaryIconView.setTranslationX(-bottomToMidpointOffset);
- secondaryIconView.setTranslationX(-bottomToMidpointOffset + taskIconHeight);
- } else {
- // if not,
- // the task on the right (secondary) is slightly larger
- primaryIconView.setTranslationX(-bottomToMidpointOffset - insetOffset);
- secondaryIconView.setTranslationX(-bottomToMidpointOffset - insetOffset
- + taskIconHeight);
+ if (!inSplitSelection) {
+ if (!splitConfig.initiatedFromSeascape) {
+ // if the split was initiated from landscape,
+ // the task on the left (primary) is slightly larger
+ primaryIconView.setTranslationX(-bottomToMidpointOffset);
+ secondaryIconView.setTranslationX(-bottomToMidpointOffset + taskIconHeight);
+ } else {
+ // if not,
+ // the task on the right (secondary) is slightly larger
+ primaryIconView.setTranslationX(-bottomToMidpointOffset - insetOffset);
+ secondaryIconView.setTranslationX(-bottomToMidpointOffset - insetOffset
+ + taskIconHeight);
+ }
}
}
} else {
primaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
- // shifts icon half a width left (height is used here since icons are square)
- primaryIconView.setTranslationX(-(taskIconHeight / 2f));
secondaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
- secondaryIconView.setTranslationX(taskIconHeight / 2f);
+ if (!inSplitSelection) {
+ // shifts icon half a width left (height is used here since icons are square)
+ primaryIconView.setTranslationX(-(taskIconHeight / 2f));
+ secondaryIconView.setTranslationX(taskIconHeight / 2f);
+ }
}
- if (!enableOverviewIconMenu()) {
+ if (!enableOverviewIconMenu() && !inSplitSelection) {
primaryIconView.setTranslationY(0);
secondaryIconView.setTranslationY(0);
}
+
primaryIconView.setLayoutParams(primaryIconParams);
secondaryIconView.setLayoutParams(secondaryIconParams);
}
diff --git a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
index 06a0685..b8d0412 100644
--- a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
+++ b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
@@ -184,7 +184,8 @@
parentHeight: Int,
splitBoundsConfig: SplitConfigurationOptions.SplitBounds,
dp: DeviceProfile,
- isRtl: Boolean
+ isRtl: Boolean,
+ inSplitSelection: Boolean
)
/**
@@ -235,7 +236,8 @@
groupedTaskViewWidth: Int,
isRtl: Boolean,
deviceProfile: DeviceProfile,
- splitConfig: SplitConfigurationOptions.SplitBounds
+ splitConfig: SplitConfigurationOptions.SplitBounds,
+ inSplitSelection: Boolean
)
/*
diff --git a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
index a972e8c..bc91911 100644
--- a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
+++ b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
@@ -277,6 +277,10 @@
iconAppChipView.setRotation(degreesRotated)
}
+ /**
+ * @param inSplitSelection Whether user currently has a task from this task group staged for
+ * split screen. Currently this state is not reachable in fake seascape.
+ */
override fun measureGroupedTaskViewThumbnailBounds(
primarySnapshot: View,
secondarySnapshot: View,
@@ -284,7 +288,8 @@
parentHeight: Int,
splitBoundsConfig: SplitBounds,
dp: DeviceProfile,
- isRtl: Boolean
+ isRtl: Boolean,
+ inSplitSelection: Boolean
) {
val primaryParams = primarySnapshot.layoutParams as FrameLayout.LayoutParams
val secondaryParams = secondarySnapshot.layoutParams as FrameLayout.LayoutParams
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index 256e29e..3449cf2 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -42,6 +42,8 @@
import android.window.TransitionInfo.Change
import android.window.WindowContainerToken
import androidx.annotation.VisibleForTesting
+import androidx.core.util.component1
+import androidx.core.util.component2
import com.android.app.animation.Interpolators
import com.android.launcher3.DeviceProfile
import com.android.launcher3.Flags.enableOverviewIconMenu
@@ -225,10 +227,22 @@
ObjectAnimator.ofFloat(iconView.splitTranslationY, MULTI_PROPERTY_VALUE, 0f)
)
}
+
+ val splitBoundsConfig =
+ (taskContainer.taskView as? GroupedTaskView)?.splitBoundsConfig ?: return
+ val (primarySnapshotViewSize, secondarySnapshotViewSize) =
+ taskContainer.taskView.pagedOrientationHandler.getGroupedTaskViewSizes(
+ deviceProfile,
+ splitBoundsConfig,
+ taskViewWidth,
+ taskViewHeight,
+ )
+ val snapshotViewSize =
+ if (isPrimaryTaskSplitting) primarySnapshotViewSize else secondarySnapshotViewSize
if (deviceProfile.isLeftRightSplit) {
// Center view first so scaling happens uniformly, alternatively we can move pivotX to 0
- val centerThumbnailTranslationX: Float = (taskViewWidth - snapshot.width) / 2f
- val finalScaleX: Float = taskViewWidth.toFloat() / snapshot.width
+ val centerThumbnailTranslationX: Float = (taskViewWidth - snapshotViewSize.x) / 2f
+ val finalScaleX: Float = taskViewWidth.toFloat() / snapshotViewSize.x
builder.add(
ObjectAnimator.ofFloat(snapshot, View.TRANSLATION_X, centerThumbnailTranslationX)
)
@@ -262,13 +276,13 @@
// thumbnail needs to take that into account. We should migrate to only using
// translations otherwise this asymmetry causes problems..
if (isPrimaryTaskSplitting) {
- centerThumbnailTranslationY = (thumbnailSize - snapshot.height) / 2f
+ centerThumbnailTranslationY = (thumbnailSize - snapshotViewSize.y) / 2f
centerThumbnailTranslationY +=
deviceProfile.overviewTaskThumbnailTopMarginPx.toFloat()
} else {
- centerThumbnailTranslationY = (thumbnailSize - snapshot.height) / 2f
+ centerThumbnailTranslationY = (thumbnailSize - snapshotViewSize.y) / 2f
}
- val finalScaleY: Float = thumbnailSize.toFloat() / snapshot.height
+ val finalScaleY: Float = thumbnailSize.toFloat() / snapshotViewSize.y
builder.add(
ObjectAnimator.ofFloat(snapshot, View.TRANSLATION_Y, centerThumbnailTranslationY)
)
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
index 3fd1a6b..92c1e93 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
@@ -65,31 +65,18 @@
val heightSize = MeasureSpec.getSize(heightMeasureSpec)
setMeasuredDimension(widthSize, heightSize)
val splitBoundsConfig = splitBoundsConfig ?: return
- val initSplitTaskId = getThisTaskCurrentlyInSplitSelection()
- if (initSplitTaskId == INVALID_TASK_ID) {
- pagedOrientationHandler.measureGroupedTaskViewThumbnailBounds(
- taskContainers[0].snapshotView,
- taskContainers[1].snapshotView,
- widthSize,
- heightSize,
- splitBoundsConfig,
- container.deviceProfile,
- layoutDirection == LAYOUT_DIRECTION_RTL
- )
- } else {
- // Currently being split with this taskView, let the non-split selected thumbnail
- // take up full thumbnail area
- taskContainers
- .firstOrNull { it.task.key.id != initSplitTaskId }
- ?.snapshotView
- ?.measure(
- widthMeasureSpec,
- MeasureSpec.makeMeasureSpec(
- heightSize - container.deviceProfile.overviewTaskThumbnailTopMarginPx,
- MeasureSpec.EXACTLY
- )
- )
- }
+ val inSplitSelection = getThisTaskCurrentlyInSplitSelection() != INVALID_TASK_ID
+ pagedOrientationHandler.measureGroupedTaskViewThumbnailBounds(
+ taskContainers[0].snapshotView,
+ taskContainers[1].snapshotView,
+ widthSize,
+ heightSize,
+ splitBoundsConfig,
+ container.deviceProfile,
+ layoutDirection == LAYOUT_DIRECTION_RTL,
+ inSplitSelection,
+ )
+
if (!enableOverviewIconMenu()) {
updateIconPlacement()
}
@@ -173,6 +160,8 @@
val splitBoundsConfig = splitBoundsConfig ?: return
val taskIconHeight = container.deviceProfile.overviewTaskIconSizePx
val isRtl = layoutDirection == LAYOUT_DIRECTION_RTL
+ val inSplitSelection = getThisTaskCurrentlyInSplitSelection() != INVALID_TASK_ID
+
if (enableOverviewIconMenu()) {
val groupedTaskViewSizes =
pagedOrientationHandler.getGroupedTaskViewSizes(
@@ -191,7 +180,8 @@
layoutParams.width,
isRtl,
container.deviceProfile,
- splitBoundsConfig
+ splitBoundsConfig,
+ inSplitSelection
)
} else {
pagedOrientationHandler.setSplitIconParams(
@@ -204,7 +194,8 @@
measuredWidth,
isRtl,
container.deviceProfile,
- splitBoundsConfig
+ splitBoundsConfig,
+ inSplitSelection
)
}
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index ba38758..da68a03 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -4995,7 +4995,8 @@
mSplitSelectStateController.getSplitAnimationController()
.addInitialSplitFromPair(taskContainer, builder,
mContainer.getDeviceProfile(),
- mSplitHiddenTaskView.getWidth(), mSplitHiddenTaskView.getHeight(),
+ mSplitHiddenTaskView.getLayoutParams().width,
+ mSplitHiddenTaskView.getLayoutParams().height,
primaryTaskSelected);
builder.addOnFrameCallback(() -> {
if (!enableRefactorTaskThumbnail()) {
diff --git a/quickstep/src/com/android/quickstep/views/TaskContainer.kt b/quickstep/src/com/android/quickstep/views/TaskContainer.kt
index 13c4f78..57d68a0 100644
--- a/quickstep/src/com/android/quickstep/views/TaskContainer.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskContainer.kt
@@ -160,6 +160,8 @@
if (enableRefactorTaskThumbnail()) {
taskView.removeView(thumbnailView)
}
+ snapshotView.scaleX = 1f
+ snapshotView.scaleY = 1f
overlay.destroy()
}
diff --git a/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutViewScreenshotTest.kt b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutViewScreenshotTest.kt
index b1ff4a1..537a755 100644
--- a/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutViewScreenshotTest.kt
+++ b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutViewScreenshotTest.kt
@@ -56,10 +56,10 @@
)
@Test
- fun bubbleBarFlyoutView_noAvatar() {
- screenshotRule.screenshotTest("bubbleBarFlyoutView_noAvatar") { activity ->
+ fun bubbleBarFlyoutView_noAvatar_onRight() {
+ screenshotRule.screenshotTest("bubbleBarFlyoutView_noAvatar_onRight") { activity ->
activity.actionBar?.hide()
- val flyout = BubbleBarFlyoutView(context)
+ val flyout = BubbleBarFlyoutView(context, onLeft = false)
flyout.setData(
BubbleBarFlyoutMessage(
senderAvatar = null,
@@ -73,10 +73,44 @@
}
@Test
- fun bubbleBarFlyoutView_avatar() {
- screenshotRule.screenshotTest("bubbleBarFlyoutView_avatar") { activity ->
+ fun bubbleBarFlyoutView_noAvatar_onLeft() {
+ screenshotRule.screenshotTest("bubbleBarFlyoutView_noAvatar_onLeft") { activity ->
activity.actionBar?.hide()
- val flyout = BubbleBarFlyoutView(context)
+ val flyout = BubbleBarFlyoutView(context, onLeft = true)
+ flyout.setData(
+ BubbleBarFlyoutMessage(
+ senderAvatar = null,
+ senderName = "sender",
+ message = "message",
+ isGroupChat = false,
+ )
+ )
+ flyout
+ }
+ }
+
+ @Test
+ fun bubbleBarFlyoutView_noAvatar_longMessage() {
+ screenshotRule.screenshotTest("bubbleBarFlyoutView_noAvatar_longMessage") { activity ->
+ activity.actionBar?.hide()
+ val flyout = BubbleBarFlyoutView(context, onLeft = true)
+ flyout.setData(
+ BubbleBarFlyoutMessage(
+ senderAvatar = null,
+ senderName = "sender",
+ message = "really, really, really, really, really long message. like really.",
+ isGroupChat = false,
+ )
+ )
+ flyout
+ }
+ }
+
+ @Test
+ fun bubbleBarFlyoutView_avatar_onRight() {
+ screenshotRule.screenshotTest("bubbleBarFlyoutView_avatar_onRight") { activity ->
+ activity.actionBar?.hide()
+ val flyout = BubbleBarFlyoutView(context, onLeft = false)
flyout.setData(
BubbleBarFlyoutMessage(
senderAvatar = ColorDrawable(Color.RED),
@@ -88,4 +122,38 @@
flyout
}
}
+
+ @Test
+ fun bubbleBarFlyoutView_avatar_onLeft() {
+ screenshotRule.screenshotTest("bubbleBarFlyoutView_avatar_onLeft") { activity ->
+ activity.actionBar?.hide()
+ val flyout = BubbleBarFlyoutView(context, onLeft = true)
+ flyout.setData(
+ BubbleBarFlyoutMessage(
+ senderAvatar = ColorDrawable(Color.RED),
+ senderName = "sender",
+ message = "message",
+ isGroupChat = true,
+ )
+ )
+ flyout
+ }
+ }
+
+ @Test
+ fun bubbleBarFlyoutView_avatar_longMessage() {
+ screenshotRule.screenshotTest("bubbleBarFlyoutView_avatar_longMessage") { activity ->
+ activity.actionBar?.hide()
+ val flyout = BubbleBarFlyoutView(context, onLeft = true)
+ flyout.setData(
+ BubbleBarFlyoutMessage(
+ senderAvatar = ColorDrawable(Color.RED),
+ senderName = "sender",
+ message = "really, really, really, really, really long message. like really.",
+ isGroupChat = true,
+ )
+ )
+ flyout
+ }
+ }
}
diff --git a/res/drawable/desktop_mode_ic_taskbar_menu_new_window.xml b/res/drawable/desktop_mode_ic_taskbar_menu_new_window.xml
new file mode 100644
index 0000000..b96a596
--- /dev/null
+++ b/res/drawable/desktop_mode_ic_taskbar_menu_new_window.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+ <path
+ android:pathData="M15 16V14H13V12.5H15V10.5H16.5V12.5H18.5V14H16.5V16H15ZM3.5 17C3.09722 17 2.74306 16.8542 2.4375 16.5625C2.14583 16.2569 2 15.9028 2 15.5V4.5C2 4.08333 2.14583 3.72917 2.4375 3.4375C2.74306 3.14583 3.09722 3 3.5 3H14.5C14.9167 3 15.2708 3.14583 15.5625 3.4375C15.8542 3.72917 16 4.08333 16 4.5V9H14.5V7H3.5V15.5H13.625V17H3.5ZM3.5 5.5H14.5V4.5H3.5V5.5ZM3.5 5.5V4.5V5.5Z"
+ android:fillColor="#1C1C14"/>
+</vector>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index fd724a5..9d06021 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -45,6 +45,9 @@
<string name="split_app_info_accessibility">App info for %1$s</string>
<string name="split_app_usage_settings">Usage settings for %1$s</string>
+ <!-- Title for an option to open a new window for a given app -->
+ <string name="new_window_option_taskbar">New Window</string>
+
<!-- App pairs -->
<string name="save_app_pair">Save app pair</string>
<!-- App pair default title -->
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index cc5baea..483f5f8 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -1056,6 +1056,7 @@
return mHotseatColumnSpan;
}
+ @VisibleForTesting
public int getHotseatWidthPx() {
return mHotseatWidthPx;
}
diff --git a/src/com/android/launcher3/model/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
index 8d2a7f9..942b97c 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
@@ -28,8 +28,6 @@
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
@@ -47,7 +45,6 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
import com.android.launcher3.util.ContentWriter;
import com.android.launcher3.util.GridOccupancy;
@@ -100,7 +97,7 @@
@VisibleForTesting
public static List<DbEntry> readAllEntries(SQLiteDatabase db, String tableName,
Context context) {
- DbReader dbReader = new DbReader(db, tableName, context, getValidPackages(context));
+ DbReader dbReader = new DbReader(db, tableName, context);
List<DbEntry> result = dbReader.loadAllWorkspaceEntries();
result.addAll(dbReader.loadHotseatEntries());
return result;
@@ -144,11 +141,10 @@
}
copyTable(source, TABLE_NAME, target.getWritableDatabase(), TMP_TABLE, context);
- HashSet<String> validPackages = getValidPackages(context);
long migrationStartTime = System.currentTimeMillis();
try (SQLiteTransaction t = new SQLiteTransaction(target.getWritableDatabase())) {
- DbReader srcReader = new DbReader(t.getDb(), TMP_TABLE, context, validPackages);
- DbReader destReader = new DbReader(t.getDb(), TABLE_NAME, context, validPackages);
+ DbReader srcReader = new DbReader(t.getDb(), TMP_TABLE, context);
+ DbReader destReader = new DbReader(t.getDb(), TABLE_NAME, context);
Point targetSize = new Point(destDeviceState.getColumns(), destDeviceState.getRows());
migrate(target, srcReader, destReader, destDeviceState.getNumHotseat(),
@@ -348,23 +344,6 @@
Utilities.createDbSelectionQuery(LauncherSettings.Favorites._ID, entryIds), null);
}
- private static HashSet<String> getValidPackages(Context context) {
- // Initialize list of valid packages. This contain all the packages which are already on
- // the device and packages which are being installed. Any item which doesn't belong to
- // this set is removed.
- // Since the loader removes such items anyway, removing these items here doesn't cause
- // any extra data loss and gives us more free space on the grid for better migration.
- HashSet<String> validPackages = new HashSet<>();
- for (PackageInfo info : context.getPackageManager()
- .getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES)) {
- validPackages.add(info.packageName);
- }
- InstallSessionHelper.INSTANCE.get(context)
- .getActiveSessions().keySet()
- .forEach(packageUserKey -> validPackages.add(packageUserKey.mPackageName));
- return validPackages;
- }
-
private static void solveGridPlacement(@NonNull final DatabaseHelper helper,
@NonNull final DbReader srcReader, @NonNull final DbReader destReader,
final int screenId, final int trgX, final int trgY,
@@ -461,18 +440,15 @@
private final SQLiteDatabase mDb;
private final String mTableName;
private final Context mContext;
- private final Set<String> mValidPackages;
private int mLastScreenId = -1;
private final Map<Integer, ArrayList<DbEntry>> mWorkspaceEntriesByScreenId =
new ArrayMap<>();
- public DbReader(SQLiteDatabase db, String tableName, Context context,
- Set<String> validPackages) {
+ public DbReader(SQLiteDatabase db, String tableName, Context context) {
mDb = db;
mTableName = tableName;
mContext = context;
- mValidPackages = validPackages;
}
protected List<DbEntry> loadHotseatEntries() {
@@ -504,7 +480,6 @@
case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: {
entry.mIntent = c.getString(indexIntent);
- verifyIntent(c.getString(indexIntent));
break;
}
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: {
@@ -586,14 +561,12 @@
case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: {
entry.mIntent = c.getString(indexIntent);
- verifyIntent(entry.mIntent);
break;
}
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: {
entry.mProvider = c.getString(indexAppWidgetProvider);
entry.appWidgetId = c.getInt(indexAppWidgetId);
ComponentName cn = ComponentName.unflattenFromString(entry.mProvider);
- verifyPackage(cn.getPackageName());
LauncherAppWidgetProviderInfo pInfo = widgetManagerHelper
.getLauncherAppWidgetInfo(entry.appWidgetId, cn);
@@ -656,7 +629,6 @@
try {
int id = c.getInt(0);
String intent = c.getString(1);
- verifyIntent(intent);
total++;
if (!entry.mFolderItems.containsKey(intent)) {
entry.mFolderItems.put(intent, new HashSet<>());
@@ -673,27 +645,6 @@
private Cursor queryWorkspace(String[] columns, String where) {
return mDb.query(mTableName, columns, where, null, null, null, null);
}
-
- /** Verifies if the mIntent should be restored. */
- private void verifyIntent(String intentStr)
- throws Exception {
- Intent intent = Intent.parseUri(intentStr, 0);
- if (intent.getComponent() != null) {
- verifyPackage(intent.getComponent().getPackageName());
- } else if (intent.getPackage() != null) {
- // Only verify package if the component was null.
- verifyPackage(intent.getPackage());
- }
- }
-
- /** Verifies if the package should be restored */
- private void verifyPackage(String packageName)
- throws Exception {
- if (!mValidPackages.contains(packageName)) {
- // TODO(b/151468819): Handle promise app icon restoration during grid migration.
- throw new Exception("Package not available");
- }
- }
}
public static class DbEntry extends ItemInfo implements Comparable<DbEntry> {
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index afa5075..c59cc81 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -152,7 +152,7 @@
&& mInfo.mIsTaskbarPinnedInDesktopMode != prefs.get(
TASKBAR_PINNING_IN_DESKTOP_MODE);
if (isTaskbarPinningChanged || isTaskbarPinningDesktopModeChanged) {
- handleInfoChange();
+ notifyConfigChange();
}
};
@@ -179,20 +179,6 @@
}
/**
- * Handles info change for desktop mode.
- */
- public static void handleInfoChangeForDesktopMode(Context context) {
- INSTANCE.get(context).handleInfoChange();
- }
-
- /**
- * Handles info change for launcher visibility.
- */
- public static void handleInfoChangeForLauncherVisibilityChanged(Context context) {
- INSTANCE.get(context).handleInfoChange();
- }
-
- /**
* Enables transient taskbar status for tests.
*/
@VisibleForTesting
@@ -259,7 +245,7 @@
}
if (ACTION_OVERLAY_CHANGED.equals(intent.getAction())) {
Log.d(TAG, "Overlay changed, notifying listeners");
- handleInfoChange();
+ notifyConfigChange();
}
}
@@ -272,7 +258,7 @@
|| !mInfo.mScreenSizeDp.equals(
new PortraitSize(config.screenHeightDp, config.screenWidthDp))
|| mWindowContext.getDisplay().getRotation() != mInfo.rotation) {
- handleInfoChange();
+ notifyConfigChange();
}
}
@@ -296,8 +282,7 @@
}
@AnyThread
- @VisibleForTesting
- public void handleInfoChange() {
+ public void notifyConfigChange() {
WindowManagerProxy wmProxy = WindowManagerProxy.INSTANCE.get(mContext);
Info oldInfo = mInfo;
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
index 761f06d..f57e8a1 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
@@ -45,7 +45,6 @@
private lateinit var modelHelper: LauncherModelHelper
private lateinit var context: Context
- private lateinit var validPackages: Set<String>
private lateinit var idp: InvariantDeviceProfile
private lateinit var dbHelper: DatabaseHelper
private lateinit var db: SQLiteDatabase
@@ -68,24 +67,10 @@
DatabaseHelper(
context,
null,
- UserCache.INSTANCE.get(context)::getSerialNumberForUser
+ UserCache.INSTANCE.get(context)::getSerialNumberForUser,
) {}
db = dbHelper.writableDatabase
- validPackages =
- setOf(
- testPackage1,
- testPackage2,
- testPackage3,
- testPackage4,
- testPackage5,
- testPackage6,
- testPackage7,
- testPackage8,
- testPackage9,
- testPackage10
- )
-
idp = InvariantDeviceProfile.INSTANCE[context]
val userSerial = UserCache.INSTANCE[context].getSerialNumberForUser(Process.myUserHandle())
LauncherDbUtils.dropTable(db, TMP_TABLE)
@@ -126,8 +111,8 @@
idp.numDatabaseHotseatIcons = 4
idp.numColumns = 4
idp.numRows = 4
- val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
- val destReader = DbReader(db, TABLE_NAME, context, validPackages)
+ val srcReader = DbReader(db, TMP_TABLE, context)
+ val destReader = DbReader(db, TABLE_NAME, context)
GridSizeMigrationUtil.migrate(
dbHelper,
srcReader,
@@ -135,7 +120,7 @@
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
- DeviceGridState(idp)
+ DeviceGridState(idp),
)
// Check hotseat items
@@ -147,9 +132,8 @@
null,
SCREEN,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
assertThat(c.count).isEqualTo(idp.numDatabaseHotseatIcons)
@@ -178,9 +162,8 @@
null,
null,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
intentIndex = c.getColumnIndex(INTENT)
val cellXIndex = c.getColumnIndex(CELLX)
@@ -238,8 +221,8 @@
idp.numDatabaseHotseatIcons = 4
idp.numColumns = 4
idp.numRows = 4
- val readerGridA = DbReader(db, TMP_TABLE, context, validPackages)
- val readerGridB = DbReader(db, TABLE_NAME, context, validPackages)
+ val readerGridA = DbReader(db, TMP_TABLE, context)
+ val readerGridB = DbReader(db, TABLE_NAME, context)
// migrate from A -> B
GridSizeMigrationUtil.migrate(
dbHelper,
@@ -248,7 +231,7 @@
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
- DeviceGridState(idp)
+ DeviceGridState(idp),
)
// Check hotseat items in grid B
@@ -260,15 +243,14 @@
null,
SCREEN,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
// Expected hotseat items in grid B
// 2 1 3 4
verifyHotseat(
c,
idp,
- mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList()
+ mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList(),
)
// Check workspace items in grid B
@@ -280,9 +262,8 @@
null,
null,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
var locMap = parseLocMap(c)
// Expected items in grid B
// _ _ _ _
@@ -306,7 +287,7 @@
5,
Point(5, 5),
DeviceGridState(idp),
- DeviceGridState(context)
+ DeviceGridState(context),
)
// Check hotseat items in grid A
c =
@@ -317,15 +298,14 @@
null,
SCREEN,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
// Expected hotseat items in grid A
// 1 2 _ 3 4
verifyHotseat(
c,
idp,
- mutableListOf(testPackage1, testPackage2, null, testPackage3, testPackage4).toList()
+ mutableListOf(testPackage1, testPackage2, null, testPackage3, testPackage4).toList(),
)
// Check workspace items in grid A
@@ -337,9 +317,8 @@
null,
null,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
locMap = parseLocMap(c)
// Expected workspace items in grid A
// _ _ _ _ _
@@ -367,7 +346,7 @@
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
- DeviceGridState(idp)
+ DeviceGridState(idp),
)
// Check hotseat items in grid B
@@ -379,15 +358,14 @@
null,
SCREEN,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
// Expected hotseat items in grid B
// 2 1 3 4
verifyHotseat(
c,
idp,
- mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList()
+ mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList(),
)
// Check workspace items in grid B
@@ -399,9 +377,8 @@
null,
null,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
locMap = parseLocMap(c)
// Expected workspace items in grid B
// _ _ _ _
@@ -455,7 +432,7 @@
0,
testPackage1,
1,
- TMP_TABLE
+ TMP_TABLE,
),
addItem(
ITEM_TYPE_DEEP_SHORTCUT,
@@ -465,7 +442,7 @@
0,
testPackage2,
2,
- TMP_TABLE
+ TMP_TABLE,
),
addItem(
ITEM_TYPE_APPLICATION,
@@ -475,7 +452,7 @@
0,
testPackage3,
3,
- TMP_TABLE
+ TMP_TABLE,
),
addItem(
ITEM_TYPE_DEEP_SHORTCUT,
@@ -485,15 +462,15 @@
0,
testPackage4,
4,
- TMP_TABLE
- )
+ TMP_TABLE,
+ ),
)
val numSrcDatabaseHotseatIcons = srcHotseatItems.size
idp.numDatabaseHotseatIcons = 6
idp.numColumns = 4
idp.numRows = 4
- val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
- val destReader = DbReader(db, TABLE_NAME, context, validPackages)
+ val srcReader = DbReader(db, TMP_TABLE, context)
+ val destReader = DbReader(db, TABLE_NAME, context)
GridSizeMigrationUtil.migrate(
dbHelper,
srcReader,
@@ -501,7 +478,7 @@
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
- DeviceGridState(idp)
+ DeviceGridState(idp),
)
// Check hotseat items
@@ -513,9 +490,8 @@
null,
SCREEN,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
assertThat(c.count.toLong()).isEqualTo(numSrcDatabaseHotseatIcons.toLong())
val screenIndex = c.getColumnIndex(SCREEN)
@@ -550,8 +526,8 @@
idp.numDatabaseHotseatIcons = 4
idp.numColumns = 4
idp.numRows = 4
- val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
- val destReader = DbReader(db, TABLE_NAME, context, validPackages)
+ val srcReader = DbReader(db, TMP_TABLE, context)
+ val destReader = DbReader(db, TABLE_NAME, context)
GridSizeMigrationUtil.migrate(
dbHelper,
srcReader,
@@ -559,7 +535,7 @@
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
- DeviceGridState(idp)
+ DeviceGridState(idp),
)
// Check hotseat items
@@ -571,9 +547,8 @@
null,
SCREEN,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
assertThat(c.count.toLong()).isEqualTo(idp.numDatabaseHotseatIcons.toLong())
val screenIndex = c.getColumnIndex(SCREEN)
@@ -617,8 +592,8 @@
idp.numDatabaseHotseatIcons = 4
idp.numColumns = 5
idp.numRows = 5
- val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
- val destReader = DbReader(db, TABLE_NAME, context, validPackages)
+ val srcReader = DbReader(db, TMP_TABLE, context)
+ val destReader = DbReader(db, TABLE_NAME, context)
GridSizeMigrationUtil.migrate(
dbHelper,
srcReader,
@@ -626,7 +601,7 @@
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
- DeviceGridState(idp)
+ DeviceGridState(idp),
)
// Get workspace items
@@ -638,9 +613,8 @@
null,
null,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
val intentIndex = c.getColumnIndex(INTENT)
val screenIndex = c.getColumnIndex(SCREEN)
@@ -678,8 +652,8 @@
idp.numDatabaseHotseatIcons = 4
idp.numColumns = 4
idp.numRows = 4
- val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
- val destReader = DbReader(db, TABLE_NAME, context, validPackages)
+ val srcReader = DbReader(db, TMP_TABLE, context)
+ val destReader = DbReader(db, TABLE_NAME, context)
GridSizeMigrationUtil.migrate(
dbHelper,
srcReader,
@@ -687,7 +661,7 @@
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
- DeviceGridState(idp)
+ DeviceGridState(idp),
)
// Get workspace items
@@ -699,9 +673,8 @@
null,
null,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
val intentIndex = c.getColumnIndex(INTENT)
val screenIndex = c.getColumnIndex(SCREEN)
@@ -732,7 +705,7 @@
container: Int,
x: Int,
y: Int,
- packageName: String?
+ packageName: String?,
): Int {
return addItem(
type,
@@ -742,7 +715,7 @@
y,
packageName,
dbHelper.generateNewItemId(),
- TABLE_NAME
+ TABLE_NAME,
)
}
@@ -754,7 +727,7 @@
y: Int,
packageName: String?,
id: Int,
- tableName: String
+ tableName: String,
): Int {
val values = ContentValues()
values.put(_ID, id)
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
index d2cce12..308f200 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
@@ -178,7 +178,7 @@
@UiThreadTest
fun testTaskbarPinning() {
whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(true)
- displayController.handleInfoChange()
+ displayController.notifyConfigChange()
verify(displayInfoChangeListener)
.onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING))
}
@@ -187,7 +187,7 @@
@UiThreadTest
fun testTaskbarPinningChangeInDesktopMode() {
whenever(launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)).thenReturn(false)
- displayController.handleInfoChange()
+ displayController.notifyConfigChange()
verify(displayInfoChangeListener)
.onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING))
}
@@ -202,7 +202,7 @@
DisplayController.enableTaskbarModePreferenceForTests(true)
assertTrue(displayController.getInfo().isTransientTaskbar())
- displayController.handleInfoChange()
+ displayController.notifyConfigChange()
verify(displayInfoChangeListener)
.onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING))
assertFalse(displayController.getInfo().isTransientTaskbar())
diff --git a/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt b/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
index 7182cf3..03d0195 100644
--- a/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
+++ b/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
@@ -114,17 +114,14 @@
}
}
- private fun migrate(
- srcGrid: Grid,
- dstGrid: Grid,
- ): List<WorkspaceItem> {
+ private fun migrate(srcGrid: Grid, dstGrid: Grid): List<WorkspaceItem> {
val userSerial = UserCache.INSTANCE[context].getSerialNumberForUser(Process.myUserHandle())
val dbHelper =
DatabaseHelper(
context,
null,
{ UserCache.INSTANCE.get(context).getSerialNumberForUser(it) },
- {}
+ {},
)
Favorites.addTableToDb(dbHelper.writableDatabase, userSerial, false, srcGrid.tableName)
@@ -135,12 +132,12 @@
LauncherDbUtils.SQLiteTransaction(dbHelper.writableDatabase).use {
GridSizeMigrationUtil.migrate(
dbHelper,
- GridSizeMigrationUtil.DbReader(it.db, srcGrid.tableName, context, MockSet(1)),
- GridSizeMigrationUtil.DbReader(it.db, dstGrid.tableName, context, MockSet(1)),
+ GridSizeMigrationUtil.DbReader(it.db, srcGrid.tableName, context),
+ GridSizeMigrationUtil.DbReader(it.db, dstGrid.tableName, context),
dstGrid.size.x,
dstGrid.size,
srcGrid.toGridState(),
- dstGrid.toGridState()
+ dstGrid.toGridState(),
)
it.commit()
}
@@ -157,7 +154,7 @@
Grid(
tableName = Favorites.TMP_TABLE,
size = testCase.srcSize,
- items = generateItemsForTest(testCase.boards, REPEAT_AFTER)
+ items = generateItemsForTest(testCase.boards, REPEAT_AFTER),
)
val dstGrid =
Grid(tableName = Favorites.TABLE_NAME, size = testCase.targetSize, items = listOf())
@@ -175,13 +172,13 @@
Grid(
tableName = Favorites.TMP_TABLE,
size = testCase.srcSize,
- items = generateItemsForTest(testCase.boards, REPEAT_AFTER)
+ items = generateItemsForTest(testCase.boards, REPEAT_AFTER),
)
val dstGrid =
Grid(
tableName = Favorites.TABLE_NAME,
size = testCase.targetSize,
- items = generateItemsForTest(testCase.destBoards, REPEAT_AFTER_DST)
+ items = generateItemsForTest(testCase.destBoards, REPEAT_AFTER_DST),
)
validate(srcGrid, dstGrid, migrate(srcGrid, dstGrid))
}
@@ -199,7 +196,7 @@
Grid(
tableName = Favorites.TMP_TABLE,
size = testCase.srcSize,
- items = generateItemsForTest(testCase.boards, REPEAT_AFTER)
+ items = generateItemsForTest(testCase.boards, REPEAT_AFTER),
)
val dstGrid =
Grid(tableName = Favorites.TABLE_NAME, size = testCase.targetSize, items = listOf())
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 21e93c5..78627e5 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -2423,7 +2423,7 @@
eventChecker.setLogExclusionRule(event -> {
Matcher matcher = Pattern.compile("KeyEvent.*flags=0x([0-9a-fA-F]+)").matcher(event);
if (matcher.find()) {
- int keyEventFlags = Integer.parseInt(matcher.group(1), 16);
+ long keyEventFlags = Long.parseLong(matcher.group(1), 16);
// ignore KeyEvents with FLAG_CANCELED
return (keyEventFlags & KeyEvent.FLAG_CANCELED) != 0;
}