Merge "Moving DisplayController to dagger" into main
diff --git a/aconfig/launcher_overview.aconfig b/aconfig/launcher_overview.aconfig
index b299edf..e0a597c 100644
--- a/aconfig/launcher_overview.aconfig
+++ b/aconfig/launcher_overview.aconfig
@@ -71,4 +71,11 @@
metadata {
purpose: PURPOSE_BUGFIX
}
-}
\ No newline at end of file
+}
+
+flag {
+ name: "enable_expressive_dismiss_task_motion"
+ namespace: "launcher_overview"
+ description: "Enables expressive motion and animations for dismissing a task in Overview."
+ bug: "381239462"
+}
diff --git a/quickstep/res/drawable/task_header_close_button.xml b/quickstep/res/drawable/task_header_close_button.xml
new file mode 100644
index 0000000..b409158
--- /dev/null
+++ b/quickstep/res/drawable/task_header_close_button.xml
@@ -0,0 +1,24 @@
+<!-- Copyright (C) 2025 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="18dp"
+ android:height="18dp"
+ android:viewportWidth="960"
+ android:viewportHeight="960"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M256,760L200,704L424,480L200,256L256,200L480,424L704,200L760,256L536,480L760,704L704,760L480,536L256,760Z"/>
+</vector>
diff --git a/quickstep/res/drawable/task_thumbnail_header_bg.xml b/quickstep/res/drawable/task_thumbnail_header_bg.xml
new file mode 100644
index 0000000..52ac1ae
--- /dev/null
+++ b/quickstep/res/drawable/task_thumbnail_header_bg.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2025 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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="@color/materialColorSurfaceBright" />
+ <corners android:topLeftRadius="@dimen/task_thumbnail_header_round_corner_radius"
+ android:topRightRadius="@dimen/task_thumbnail_header_round_corner_radius"/>
+</shape>
diff --git a/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml b/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
index b004dfd..7530c28 100644
--- a/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
@@ -147,6 +147,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="104dp"
android:accessibilityHeading="true"
+ android:accessibilityTraversalBefore="@id/gesture_tutorial_fragment_feedback_subtitle"
android:gravity="top"
android:lineSpacingExtra="-1sp"
android:textAppearance="@style/TextAppearance.GestureTutorial.MainTitle"
@@ -161,6 +162,8 @@
android:layout_marginTop="24dp"
android:lineSpacingExtra="4sp"
android:textAppearance="@style/TextAppearance.GestureTutorial.MainSubtitle"
+ android:accessibilityTraversalAfter="@id/gesture_tutorial_fragment_feedback_title"
+ android:accessibilityTraversalBefore="@id/gesture_tutorial_fragment_action_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/gesture_tutorial_fragment_feedback_title" />
@@ -224,6 +227,10 @@
android:layout_marginBottom="@dimen/gesture_tutorial_done_button_bottom_margin"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
+ android:clickable="true"
+ android:focusableInTouchMode="true"
+ android:accessibilityTraversalAfter="@id/gesture_tutorial_fragment_feedback_subtitle"
+ android:contentDescription="@string/gesture_tutorial_action_button_label"
android:background="@drawable/gesture_tutorial_action_button_background"
android:stateListAnimator="@null"
android:text="@string/gesture_tutorial_action_button_label"
diff --git a/quickstep/res/layout/task_thumbnail_view_header.xml b/quickstep/res/layout/task_thumbnail_view_header.xml
new file mode 100644
index 0000000..ecc1559
--- /dev/null
+++ b/quickstep/res/layout/task_thumbnail_view_header.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright (C) 2025 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.
+-->
+<com.android.quickstep.views.TaskThumbnailViewHeader
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/task_thumbnail_header_bg">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/task_thumbnail_header_height"
+ android:layout_marginStart="@dimen/task_thumbnail_header_margin_edge"
+ android:layout_marginEnd="@dimen/task_thumbnail_header_margin_edge"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
+ <ImageView
+ android:id="@+id/header_app_icon"
+ android:contentDescription="@string/header_app_icon_description"
+ android:layout_width="@dimen/task_thumbnail_header_icon_size"
+ android:layout_height="@dimen/task_thumbnail_header_icon_size"
+ android:layout_marginEnd="@dimen/task_thumbnail_header_margin_between_views"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/header_app_title"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintHorizontal_bias="0"
+ app:layout_constraintVertical_bias="0.5"
+ app:layout_constraintHorizontal_chainStyle="spread_inside" />
+ <TextView
+ android:id="@+id/header_app_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/task_thumbnail_header_margin_between_views"
+ android:layout_marginEnd="@dimen/task_thumbnail_header_margin_between_views"
+ android:text="@string/header_default_app_title"
+ app:layout_constraintStart_toEndOf="@id/header_app_icon"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintHorizontal_bias="0"
+ app:layout_constraintVertical_bias="0.5" />
+ <ImageButton
+ android:id="@+id/header_close_button"
+ android:contentDescription="@string/header_close_icon_description"
+ android:layout_width="@dimen/task_thumbnail_header_icon_size"
+ android:layout_height="@dimen/task_thumbnail_header_icon_size"
+ android:layout_marginStart="@dimen/task_thumbnail_header_margin_between_views"
+ android:src="@drawable/task_header_close_button"
+ android:tint="@android:color/darker_gray"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintHorizontal_bias="1"
+ app:layout_constraintVertical_bias="0.5" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
+</com.android.quickstep.views.TaskThumbnailViewHeader>
diff --git a/quickstep/res/values-sw600dp-land/dimens.xml b/quickstep/res/values-sw600dp-land/dimens.xml
index 49239aa..0052a73 100644
--- a/quickstep/res/values-sw600dp-land/dimens.xml
+++ b/quickstep/res/values-sw600dp-land/dimens.xml
@@ -27,12 +27,6 @@
<dimen name="gesture_tutorial_menu_done_button_top_spacing">40dp</dimen>
<dimen name="gesture_tutorial_menu_back_shape_bottom_margin">49dp</dimen>
- <!-- Grid Only Overview -->
- <!-- The top margin above the top row of tasks in grid only overview -->
- <dimen name="overview_top_margin_grid_only">24dp</dimen>
- <!-- The bottom margin above the bottom row of tasks in grid only overview -->
- <dimen name="overview_bottom_margin_grid_only">40dp</dimen>
-
<dimen name="taskbar_suw_insets">24dp</dimen>
</resources>
diff --git a/quickstep/res/values-sw600dp/dimens.xml b/quickstep/res/values-sw600dp/dimens.xml
index 37a90a1..4996582 100644
--- a/quickstep/res/values-sw600dp/dimens.xml
+++ b/quickstep/res/values-sw600dp/dimens.xml
@@ -33,10 +33,6 @@
<dimen name="overview_page_spacing">36dp</dimen>
<!-- The space to the left and to the right of the "Clear all" button -->
<dimen name="overview_grid_side_margin">64dp</dimen>
- <!-- The top margin above the top row of tasks in grid only overview -->
- <dimen name="overview_top_margin_grid_only">80dp</dimen>
- <!-- The bottom margin above the bottom row of tasks in grid only overview -->
- <dimen name="overview_bottom_margin_grid_only">80dp</dimen>
<!-- Overview actions -->
<dimen name="overview_actions_top_margin">24dp</dimen>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index de0b2c7..493a5b8 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -34,9 +34,6 @@
<!-- Overview Task Views -->
<!-- The thumbnail uses up to this much of the total screen height/width in Overview -->
<item name="overview_max_scale" format="float" type="dimen">0.7</item>
- <!-- The thumbnail should not go smaller than this much of the total screen height/width in
- tablet app to Overview carousel -->
- <item name="overview_carousel_min_scale" format="float" type="dimen">0.46</item>
<!-- A touch target for icons, sometimes slightly larger than the icons themselves -->
<dimen name="task_thumbnail_icon_size">48dp</dimen>
<!-- The icon size for the focused task, placed in center of touch target -->
@@ -84,6 +81,12 @@
<!-- The size of the icon menu's icon touch target -->
<dimen name="task_thumbnail_icon_menu_drawable_touch_size">44dp</dimen>
<dimen name="task_thumbnail_icon_menu_elevation">4dp</dimen>
+ <!-- The size of the task thumbnail header -->
+ <dimen name="task_thumbnail_header_height">30dp</dimen>
+ <dimen name="task_thumbnail_header_margin_edge">18dp</dimen>
+ <dimen name="task_thumbnail_header_margin_between_views">9dp</dimen>
+ <dimen name="task_thumbnail_header_icon_size">18dp</dimen>
+ <dimen name="task_thumbnail_header_round_corner_radius">16dp</dimen>
<dimen name="task_icon_cache_default_icon_size">72dp</dimen>
<item name="overview_modal_max_scale" format="float" type="dimen">1.1</item>
@@ -465,6 +468,7 @@
<dimen name="bubblebar_icon_spacing_persistent_taskbar">@dimen/bubblebar_icon_spacing</dimen>
<dimen name="bubblebar_expanded_icon_spacing">12dp</dimen>
<dimen name="bubblebar_icon_elevation">1dp</dimen>
+ <dimen name="bubblebar_transient_taskbar_min_distance">12dp</dimen>
<!-- Bubble bar dismiss view -->
<dimen name="bubblebar_dismiss_target_size">@dimen/floating_dismiss_background_size</dimen>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index f126568..324ea31 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -357,4 +357,12 @@
<!-- Name of Google's new feature to circle to search anything on your phone screen, without
switching apps. [CHAR_LIMIT=60] -->
<string name="search_gesture_feature_title">Circle to Search</string>
+
+ <!-- Strings for task thumbnail header in Overview -->
+ <!-- Content description for the header app icon. [CHAR LIMIT=NONE] -->
+ <string name="header_app_icon_description">App icon</string>
+ <!-- Default app title for a task view in Overview. [CHAR LIMIT=NONE] -->
+ <string name="header_default_app_title">App title</string>
+ <!-- Content description for the header close button. [CHAR LIMIT=NONE] -->
+ <string name="header_close_icon_description">Close button</string>
</resources>
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
index cd38e5e..48cb911 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
@@ -269,7 +269,7 @@
DesktopTask desktopTask = findDesktopTask(tasks);
if (desktopTask != null) {
- mTasks = desktopTask.tasks.stream()
+ mTasks = desktopTask.getTasks().stream()
.map(GroupTask::new)
.filter(task -> !shouldExcludeTask(task, taskIdsToExclude))
.collect(Collectors.toList());
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index ee9c6a1..2745129 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -140,6 +140,7 @@
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.Executors;
+import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.SettingsCache;
@@ -194,6 +195,7 @@
private WindowManager.LayoutParams mWindowLayoutParams;
private WindowManager.LayoutParams mLastUpdatedLayoutParams;
private boolean mIsFullscreen;
+ private boolean mIsNotificationShadeExpanded = false;
// The size we should return to when we call setTaskbarWindowFullscreen(false)
private int mLastRequestedNonFullscreenSize;
/**
@@ -269,8 +271,7 @@
mWindowManager = c.getSystemService(WindowManager.class);
// Inflate views.
- final boolean isTransientTaskbar = DisplayController.isTransientTaskbar(this)
- && !isPhoneMode();
+ boolean isTransientTaskbar = isTransientTaskbar();
int taskbarLayout = isTransientTaskbar ? R.layout.transient_taskbar : R.layout.taskbar;
mDragLayer = (TaskbarDragLayer) mLayoutInflater.inflate(taskbarLayout, null, false);
TaskbarView taskbarView = mDragLayer.findViewById(R.id.taskbar_view);
@@ -383,6 +384,11 @@
dispatchDeviceProfileChanged();
}
+ /** Returns whether current taskbar is transient. */
+ public boolean isTransientTaskbar() {
+ return DisplayController.isTransientTaskbar(this) && !isPhoneMode();
+ }
+
/**
* Copy the original DeviceProfile, match the number of hotseat icons and qsb width and update
* the icon size
@@ -1005,6 +1011,8 @@
* Hides the taskbar icons and background when the notification shade is expanded.
*/
private void onNotificationShadeExpandChanged(boolean isExpanded, boolean skipAnim) {
+ boolean isExpandedUpdated = isExpanded != mIsNotificationShadeExpanded;
+ mIsNotificationShadeExpanded = isExpanded;
// Close all floating views within the Taskbar window to make sure nothing is shown over
// the notification shade.
if (isExpanded) {
@@ -1018,11 +1026,18 @@
anim.play(mControllers.taskbarDragLayerController.getNotificationShadeBgTaskbar()
.animateToValue(alpha));
- mControllers.bubbleControllers.ifPresent(controllers -> {
- BubbleBarViewController bubbleBarViewController = controllers.bubbleBarViewController;
- anim.play(bubbleBarViewController.getBubbleBarAlpha().get(0).animateToValue(alpha));
- });
-
+ if (isExpandedUpdated) {
+ mControllers.bubbleControllers.ifPresent(controllers -> {
+ BubbleBarViewController bubbleBarViewController =
+ controllers.bubbleBarViewController;
+ anim.play(bubbleBarViewController.getBubbleBarAlpha().get(0).animateToValue(alpha));
+ MultiPropertyFactory<View>.MultiProperty handleAlpha =
+ controllers.bubbleStashController.getHandleViewAlpha();
+ if (handleAlpha != null) {
+ anim.play(handleAlpha.animateToValue(alpha));
+ }
+ });
+ }
anim.start();
if (skipAnim) {
anim.end();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index ea6d82b..e44bce1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -57,6 +57,7 @@
var backgroundHeight = context.deviceProfile.taskbarHeight.toFloat()
var translationYForSwipe = 0f
var translationYForStash = 0f
+ var translationXForBubbleBar = 0f
private val transientBackgroundBounds = context.transientTaskbarBounds
@@ -244,12 +245,12 @@
setColorAlphaBound(Color.BLACK, Math.round(newShadowAlpha)),
)
strokePaint.alpha = (paint.alpha * strokeAlpha) / 255
-
+ val currentTranslationX = translationXForBubbleBar * progress
lastDrawnTransientRect.set(
- transientBackgroundBounds.left + halfWidthDelta,
+ transientBackgroundBounds.left + halfWidthDelta + currentTranslationX,
bottom - newBackgroundHeight,
- transientBackgroundBounds.right - halfWidthDelta,
- bottom
+ transientBackgroundBounds.right - halfWidthDelta + currentTranslationX,
+ 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 8b52112..59ef577 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -254,6 +254,11 @@
invalidate();
}
+ protected void setBackgroundTranslationXForBubbleBar(float translationX) {
+ mBackgroundRenderer.setTranslationXForBubbleBar(translationX);
+ invalidate();
+ }
+
/** Returns the bounds in DragLayer coordinates of where the transient background was drawn. */
protected RectF getLastDrawnTransientRect() {
return mBackgroundRenderer.getLastDrawnTransientRect();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 925e10b..68c252a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -198,6 +198,13 @@
}
/**
+ * Sets the translation of the background for the bubble bar.
+ */
+ public void setTranslationXForBubbleBar(float transX) {
+ mTaskbarDragLayer.setBackgroundTranslationXForBubbleBar(transX);
+ }
+
+ /**
* Sets the translation of the background during the spring on stash animation.
*/
public void setTranslationYForStash(float transY) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 1905561..9a9575d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -393,10 +393,7 @@
* @param launcherState The current state launcher is in
*/
private void updateOverviewDragState(LauncherState launcherState) {
- boolean disallowLongClick =
- FeatureFlags.enableSplitContextually()
- ? mLauncher.isSplitSelectionActive() || mIsAnimatingToLauncher
- : launcherState == LauncherState.OVERVIEW_SPLIT_SELECT;
+ boolean disallowLongClick = mLauncher.isSplitSelectionActive() || mIsAnimatingToLauncher;
com.android.launcher3.taskbar.Utilities.setOverviewDragState(
mControllers, launcherState.disallowTaskbarGlobalDrag(),
disallowLongClick, launcherState.allowTaskbarInitialSplitSelection());
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 60de066..e0be39d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -40,6 +40,7 @@
import static com.android.launcher3.taskbar.bubbles.BubbleBarView.FADE_IN_ANIM_ALPHA_DURATION_MS;
import static com.android.launcher3.taskbar.bubbles.BubbleBarView.FADE_OUT_ANIM_POSITION_DURATION_MS;
import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
+import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_BUBBLE_BAR_ANIM;
import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_NAV_BAR_ANIM;
import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_ALIGNMENT_ANIM;
import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_PINNING_ANIM;
@@ -81,6 +82,7 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.TaskItemInfo;
import com.android.launcher3.taskbar.bubbles.BubbleBarController;
+import com.android.launcher3.taskbar.bubbles.BubbleControllers;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LauncherBindableItemsContainer;
@@ -109,6 +111,8 @@
private static final Runnable NO_OP = () -> { };
+ public static long TRANSLATION_X_FOR_BUBBLEBAR_ANIM_DURATION_MS = 250;
+
public static final int ALPHA_INDEX_HOME = 0;
public static final int ALPHA_INDEX_KEYGUARD = 1;
public static final int ALPHA_INDEX_STASH = 2;
@@ -132,6 +136,7 @@
private static final int TRANSITION_FADE_OUT_DURATION = 83;
private final TaskbarActivityContext mActivity;
+ private @Nullable TaskbarDragLayerController mDragLayerController;
private final TaskbarView mTaskbarView;
private final MultiValueAlpha mTaskbarIconAlpha;
private final AnimatedFloat mTaskbarIconScaleForStash = new AnimatedFloat(this::updateScale);
@@ -144,15 +149,22 @@
this::updateTaskbarIconsScale);
private final AnimatedFloat mTaskbarIconTranslationXForPinning = new AnimatedFloat(
- this::updateTaskbarIconTranslationXForPinning);
+ () -> updateTaskbarIconTranslationXForPinning());
private final AnimatedFloat mIconsTranslationXForNavbar = new AnimatedFloat(
this::updateTranslationXForNavBar);
+ private final AnimatedFloat mTranslationXForBubbleBar = new AnimatedFloat(
+ this::updateTranslationXForBubbleBar);
+
@Nullable
private Animator mTaskbarShiftXAnim;
@Nullable
private BubbleBarLocation mCurrentBubbleBarLocation;
+ @Nullable
+ private BubbleControllers mBubbleControllers = null;
+ @Nullable
+ private ObjectAnimator mTranslationXAnimation;
private final AnimatedFloat mTaskbarIconTranslationYForPinning = new AnimatedFloat(
this::updateTranslationY);
@@ -174,11 +186,12 @@
private final View.OnLayoutChangeListener mTaskbarViewLayoutChangeListener =
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
if (!taskbarRecentsLayoutTransition()) {
- updateTaskbarIconTranslationXForPinning();
+ // update shiftX is handled with the animation at the end of the method
+ updateTaskbarIconTranslationXForPinning(/* updateShiftXForBubbleBar = */ false);
}
- if (BubbleBarController.isBubbleBarEnabled()) {
- mControllers.navbarButtonsViewController.onLayoutsUpdated();
- }
+ if (mBubbleControllers == null) return;
+ mControllers.navbarButtonsViewController.onLayoutsUpdated();
+ adjustTaskbarXForBubbleBar();
};
// Animation to align icons with Launcher, created lazily. This allows the controller to be
@@ -222,11 +235,11 @@
mIsRtl = Utilities.isRtl(mTaskbarView.getResources());
mTaskbarLeftRightMargin = mActivity.getResources().getDimensionPixelSize(
R.dimen.transient_taskbar_padding);
-
}
public void init(TaskbarControllers controllers) {
mControllers = controllers;
+ controllers.bubbleControllers.ifPresent(bc -> mBubbleControllers = bc);
mTaskbarView.init(TaskbarViewCallbacksFactory.newInstance(mActivity).create(
mActivity, mControllers, mTaskbarView));
mTaskbarView.getLayoutParams().height = mActivity.isPhoneMode()
@@ -252,7 +265,7 @@
controllers.navbarButtonsViewController.getTaskbarNavButtonTranslationY();
mTaskbarNavButtonTranslationYForInAppDisplay = controllers.navbarButtonsViewController
.getTaskbarNavButtonTranslationYForInAppDisplay();
-
+ mDragLayerController = controllers.taskbarDragLayerController;
mActivity.addOnDeviceProfileChangeListener(mDeviceProfileChangeListener);
if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
@@ -270,24 +283,59 @@
@Override
public void onBubbleBarLocationUpdated(BubbleBarLocation location) {
updateCurrentBubbleBarLocation(location);
- if (!shouldMoveTaskbarOnBubbleBarLocationUpdate()) return;
- cancelTaskbarShiftAnimation();
- // reset translation x, taskbar will position icons with the updated location
- mIconsTranslationXForNavbar.updateValue(0);
- mTaskbarView.onBubbleBarLocationUpdated(location);
+ if (mActivity.isTransientTaskbar()) {
+ translateTaskbarXForBubbleBar(/* animate= */ false);
+ } else if (mActivity.shouldStartAlignTaskbar()) {
+ cancelTaskbarShiftAnimation();
+ // reset translation x, taskbar will position icons with the updated location
+ mIconsTranslationXForNavbar.updateValue(0);
+ mTaskbarView.onBubbleBarLocationUpdated(location);
+ }
}
/** Animates start aligned taskbar accordingly to the bubble bar position. */
@Override
public void onBubbleBarLocationAnimated(BubbleBarLocation location) {
- if (!updateCurrentBubbleBarLocation(location)
- || !shouldMoveTaskbarOnBubbleBarLocationUpdate()) {
- return;
+ boolean locationUpdated = updateCurrentBubbleBarLocation(location);
+ if (mActivity.isTransientTaskbar()) {
+ translateTaskbarXForBubbleBar(/* animate= */ true);
+ } else if (locationUpdated && mActivity.shouldStartAlignTaskbar()) {
+ cancelTaskbarShiftAnimation();
+ float translationX = mTaskbarView.getTranslationXForBubbleBarPosition(location);
+ mTaskbarShiftXAnim = createTaskbarIconsShiftAnimator(translationX);
+ mTaskbarShiftXAnim.start();
}
- cancelTaskbarShiftAnimation();
- float translationX = mTaskbarView.getTranslationXForBubbleBarPosition(location);
- mTaskbarShiftXAnim = createTaskbarIconsShiftAnimator(translationX);
- mTaskbarShiftXAnim.start();
+ }
+
+ private void translateTaskbarXForBubbleBar(boolean animate) {
+ cancelCurrentTranslationXAnimation();
+ if (!mActivity.isTransientTaskbar()) return;
+ int shiftX = getTransientTaskbarShiftXForBubbleBar();
+ if (animate) {
+ mTranslationXAnimation = mTranslationXForBubbleBar.animateToValue(shiftX);
+ mTranslationXAnimation.setInterpolator(EMPHASIZED);
+ mTranslationXAnimation.setDuration(TRANSLATION_X_FOR_BUBBLEBAR_ANIM_DURATION_MS);
+ mTranslationXAnimation.start();
+ } else {
+ mTranslationXForBubbleBar.updateValue(shiftX);
+ }
+ }
+
+ private void cancelCurrentTranslationXAnimation() {
+ if (mTranslationXAnimation != null) {
+ if (mTranslationXAnimation.isRunning()) {
+ mTranslationXAnimation.cancel();
+ }
+ mTranslationXAnimation = null;
+ }
+ }
+
+ private int getTransientTaskbarShiftXForBubbleBar() {
+ if (mBubbleControllers == null || !mActivity.isTransientTaskbar()) {
+ return 0;
+ }
+ return mBubbleControllers.bubbleBarViewController
+ .getTransientTaskbarTranslationXForBubbleBar(mCurrentBubbleBarLocation);
}
/** Updates the mCurrentBubbleBarLocation, returns {@code} true if location is updated. */
@@ -300,13 +348,6 @@
}
}
- /** Returns whether taskbar should be moved on the bubble bar location update. */
- private boolean shouldMoveTaskbarOnBubbleBarLocationUpdate() {
- return mControllers.bubbleControllers.isPresent()
- && mActivity.shouldStartAlignTaskbar()
- && mActivity.isThreeButtonNav();
- }
-
private void cancelTaskbarShiftAnimation() {
if (mTaskbarShiftXAnim != null) {
mTaskbarShiftXAnim.cancel();
@@ -450,16 +491,26 @@
}
void updateTaskbarIconTranslationXForPinning() {
+ updateTaskbarIconTranslationXForPinning(/* updateShiftXForBubbleBar = */ true);
+ }
+
+ void updateTaskbarIconTranslationXForPinning(boolean updateShiftXForBubbleBar) {
View[] iconViews = mTaskbarView.getIconViews();
float scale = mTaskbarIconTranslationXForPinning.value;
float transientTaskbarAllAppsOffset = mActivity.getResources().getDimension(
mTaskbarView.getAllAppsButtonContainer().getAllAppsButtonTranslationXOffset(true));
float persistentTaskbarAllAppsOffset = mActivity.getResources().getDimension(
mTaskbarView.getAllAppsButtonContainer().getAllAppsButtonTranslationXOffset(false));
-
+ if (mBubbleControllers != null && updateShiftXForBubbleBar) {
+ cancelCurrentTranslationXAnimation();
+ int translationXForTransientTaskbar = mBubbleControllers.bubbleBarViewController
+ .getTransientTaskbarTranslationXForBubbleBar(mCurrentBubbleBarLocation);
+ float currentTranslationXForTransientTaskbar = mapRange(scale,
+ translationXForTransientTaskbar, 0);
+ mTranslationXForBubbleBar.updateValue(currentTranslationXForTransientTaskbar);
+ }
float allAppIconTranslateRange = mapRange(scale, transientTaskbarAllAppsOffset,
persistentTaskbarAllAppsOffset);
-
// Task icons are laid out so the taskbar content is centered. The taskbar width (used for
// centering taskbar icons) depends on the all apps button X translation, and is different
// for persistent and transient taskbar. If the offset used for current taskbar layout is
@@ -551,13 +602,23 @@
}
private void updateTranslationXForNavBar() {
+ updateIconViewsTranslationX(INDEX_NAV_BAR_ANIM, mIconsTranslationXForNavbar.value);
+ }
+
+ private void updateTranslationXForBubbleBar() {
+ float translationX = mTranslationXForBubbleBar.value;
+ updateIconViewsTranslationX(INDEX_BUBBLE_BAR_ANIM, translationX);
+ if (mDragLayerController != null) {
+ mDragLayerController.setTranslationXForBubbleBar(translationX);
+ }
+ }
+
+ private void updateIconViewsTranslationX(int translationXChannel, float translationX) {
View[] iconViews = mTaskbarView.getIconViews();
- float translationX = mIconsTranslationXForNavbar.value;
- for (int iconIndex = 0; iconIndex < iconViews.length; iconIndex++) {
- View iconView = iconViews[iconIndex];
+ for (View iconView : iconViews) {
MultiTranslateDelegate translateDelegate =
((Reorderable) iconView).getTranslateDelegate();
- translateDelegate.getTranslationX(INDEX_NAV_BAR_ANIM).setValue(translationX);
+ translateDelegate.getTranslationX(translationXChannel).setValue(translationX);
}
}
@@ -811,6 +872,13 @@
if (mTaskbarView.updateMaxNumIcons()) {
commitRunningAppsToUI();
}
+ adjustTaskbarXForBubbleBar();
+ }
+
+ private void adjustTaskbarXForBubbleBar() {
+ if (mBubbleControllers != null && mActivity.isTransientTaskbar()) {
+ translateTaskbarXForBubbleBar(/* animate= */ true);
+ }
}
/**
@@ -841,7 +909,17 @@
setter.setFloat(mTaskbarIconTranslationYForHome, VALUE, -offsetY, interpolator);
setter.setFloat(mTaskbarNavButtonTranslationY, VALUE, -offsetY, interpolator);
setter.setFloat(mTaskbarNavButtonTranslationYForInAppDisplay, VALUE, offsetY, interpolator);
-
+ if (mBubbleControllers != null
+ && mCurrentBubbleBarLocation != null
+ && mActivity.isTransientTaskbar()) {
+ int offsetX = mBubbleControllers.bubbleBarViewController
+ .getTransientTaskbarTranslationXForBubbleBar(mCurrentBubbleBarLocation);
+ if (offsetX != 0) {
+ // if taskbar should be adjusted for the bubble bar adjust the taskbar translation
+ mTranslationXForBubbleBar.updateValue(offsetX);
+ setter.setFloat(mTranslationXForBubbleBar, VALUE, 0, interpolator);
+ }
+ }
int collapsedHeight = mActivity.getDefaultTaskbarWindowSize();
int expandedHeight = Math.max(collapsedHeight, taskbarDp.taskbarHeight + offsetY);
setter.addOnFrameListener(anim -> mActivity.setTaskbarWindowSize(
@@ -1042,8 +1120,8 @@
}
private boolean bubbleBarHasBubbles() {
- return mControllers.bubbleControllers.isPresent()
- && mControllers.bubbleControllers.get().bubbleBarViewController.hasBubbles();
+ return mBubbleControllers != null
+ && mBubbleControllers.bubbleBarViewController.hasBubbles();
}
public void onRotationChanged(DeviceProfile deviceProfile) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 2d4d279..c001123 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -1339,6 +1339,14 @@
return getScaledIconSize() + mIconOverlapAmount + 2 * mBubbleBarPadding;
}
+ float getCollapsedWidthForIconSizeAndPadding(int iconSize, int bubbleBarPadding) {
+ final int bubbleChildCount = Math.min(getBubbleChildCount(), MAX_VISIBLE_BUBBLES_COLLAPSED);
+ if (bubbleChildCount == 0) return 0;
+ final int spacesCount = bubbleChildCount - 1;
+ final float horizontalPadding = 2 * bubbleBarPadding;
+ return iconSize * bubbleChildCount + mIconOverlapAmount * spacesCount + horizontalPadding;
+ }
+
/** Returns the child count excluding the overflow if it's present. */
int getBubbleChildCount() {
return hasOverflow() ? getChildCount() - 1 : getChildCount();
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 0b627d2..afbc932 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -122,7 +122,8 @@
private float mBubbleBarSwipeUpTranslationY;
// Modified when bubble bar is springing back into the stash handle.
private float mBubbleBarStashTranslationY;
-
+ // Minimum distance between the BubbleBar and the taskbar
+ private final int mBubbleBarTaskbarMinDistance;
// Whether the bar is hidden for a sysui state.
private boolean mHiddenForSysui;
// Whether the bar is hidden because there are no bubbles.
@@ -150,10 +151,11 @@
mBubbleBarContainer = bubbleBarContainer;
mSystemUiProxy = SystemUiProxy.INSTANCE.get(mActivity);
mBubbleBarAlpha = new MultiValueAlpha(mBarView, 1 /* num alpha channels */);
- mIconSize = activity.getResources().getDimensionPixelSize(
- R.dimen.bubblebar_icon_size);
- mDragElevation = activity.getResources().getDimensionPixelSize(
- R.dimen.bubblebar_drag_elevation);
+ Resources res = activity.getResources();
+ mIconSize = res.getDimensionPixelSize(R.dimen.bubblebar_icon_size);
+ mBubbleBarTaskbarMinDistance = res.getDimensionPixelSize(
+ R.dimen.bubblebar_transient_taskbar_min_distance);
+ mDragElevation = res.getDimensionPixelSize(R.dimen.bubblebar_drag_elevation);
mTaskbarTranslationDelta = getBubbleBarTranslationDeltaForTaskbar(activity);
}
@@ -664,6 +666,45 @@
}
}
+ /**
+ * Returns the translation X of the transient taskbar according to the bubble bar location
+ * regardless of the current taskbar mode.
+ */
+ public int getTransientTaskbarTranslationXForBubbleBar(BubbleBarLocation location) {
+ int taskbarShift = 0;
+ if (!isBubbleBarVisible() || mTaskbarViewPropertiesProvider == null) return taskbarShift;
+ Rect taskbarViewBounds = mTaskbarViewPropertiesProvider.getTaskbarViewBounds();
+ if (taskbarViewBounds.isEmpty()) return taskbarShift;
+ int actualDistance =
+ getDistanceBetweenTransientTaskbarAndBubbleBar(location, taskbarViewBounds);
+ if (actualDistance < mBubbleBarTaskbarMinDistance) {
+ taskbarShift = mBubbleBarTaskbarMinDistance - actualDistance;
+ if (!location.isOnLeft(mBarView.isLayoutRtl())) {
+ taskbarShift = -taskbarShift;
+ }
+ }
+ return taskbarShift;
+ }
+
+ private int getDistanceBetweenTransientTaskbarAndBubbleBar(BubbleBarLocation location,
+ Rect taskbarViewBounds) {
+ Resources res = mActivity.getResources();
+ DeviceProfile transientDp = mActivity.getTransientTaskbarDeviceProfile();
+ int transientIconSize = getBubbleBarIconSizeFromDeviceProfile(res, transientDp);
+ int transientPadding = getBubbleBarPaddingFromDeviceProfile(res, transientDp);
+ int transientWidthWithMargin = (int) (mBarView.getCollapsedWidthForIconSizeAndPadding(
+ transientIconSize, transientPadding) + mBarView.getHorizontalMargin());
+ int distance;
+ if (location.isOnLeft(mBarView.isLayoutRtl())) {
+ distance = taskbarViewBounds.left - transientWidthWithMargin;
+ } else {
+ int displayWidth = res.getDisplayMetrics().widthPixels;
+ int bubbleBarLeft = displayWidth - transientWidthWithMargin;
+ distance = bubbleBarLeft - taskbarViewBounds.right;
+ }
+ return distance;
+ }
+
//
// Modifying view related properties.
//
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
index 595dac3..fec1eaf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
@@ -24,6 +24,7 @@
import com.android.launcher3.taskbar.bubbles.BubbleBarView
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController
+import com.android.launcher3.util.MultiPropertyFactory
import com.android.wm.shell.shared.animation.PhysicsAnimator
import com.android.wm.shell.shared.bubbles.BubbleBarLocation
import java.io.PrintWriter
@@ -172,6 +173,9 @@
/** Returns bounds of the handle */
fun getHandleBounds(bounds: Rect)
+ /** Returns MultiValueAlpha of the handle view when the handle view is shown. */
+ fun getHandleViewAlpha(): MultiPropertyFactory<View>.MultiProperty? = null
+
/**
* Returns bubble bar Y position according to [isBubblesShowingOnHome] and
* [isBubblesShowingOnOverview] values. Default implementation only analyse
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
index 3e3f569..9c148e2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
@@ -512,6 +512,14 @@
}
}
+ override fun getHandleViewAlpha(): MultiPropertyFactory<View>.MultiProperty? =
+ // only return handle alpha if the bubble bar is stashed and has bubbles
+ if (isStashed && bubbleBarViewController.hasBubbles()) {
+ stashHandleViewAlpha
+ } else {
+ null
+ }
+
private fun Animator.updateTouchRegionOnAnimationEnd(): Animator {
doOnEnd { onIsStashedChanged() }
return this
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index d3ac411..810325c 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -39,7 +39,6 @@
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
import static com.android.launcher3.Utilities.isRtl;
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
-import static com.android.launcher3.config.FeatureFlags.enableSplitContextually;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_HOME;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED;
@@ -723,11 +722,7 @@
splitSelectSource.alreadyRunningTaskId = taskWasFound
? foundTask.key.id
: INVALID_TASK_ID;
- if (enableSplitContextually()) {
- startSplitToHome(splitSelectSource);
- } else {
- recentsView.initiateSplitSelect(splitSelectSource);
- }
+ startSplitToHome(splitSelectSource);
}
);
}
@@ -817,15 +812,13 @@
super.onPause();
- if (enableSplitContextually()) {
- // If Launcher pauses before both split apps are selected, exit split screen.
- if (!mSplitSelectStateController.isBothSplitAppsConfirmed() &&
- !mSplitSelectStateController.isLaunchingFirstAppFullscreen()) {
- mSplitSelectStateController
- .logExitReason(LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED);
- mSplitSelectStateController.getSplitAnimationController()
- .playPlaceholderDismissAnim(this, LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED);
- }
+ // If Launcher pauses before both split apps are selected, exit split screen.
+ if (!mSplitSelectStateController.isBothSplitAppsConfirmed() &&
+ !mSplitSelectStateController.isLaunchingFirstAppFullscreen()) {
+ mSplitSelectStateController
+ .logExitReason(LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED);
+ mSplitSelectStateController.getSplitAnimationController()
+ .playPlaceholderDismissAnim(this, LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED);
}
if (mTaskbarUIController != null && FeatureFlags.enableHomeTransitionListener()) {
@@ -1424,7 +1417,7 @@
@Override
public boolean handleIncorrectSplitTargetSelection() {
- if (!enableSplitContextually() || !mSplitSelectStateController.isSplitSelectActive()) {
+ if (!mSplitSelectStateController.isSplitSelectActive()) {
return false;
}
mSplitSelectStateController.getSplitInstructionsView().goBoing();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.kt b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.kt
index f196548..c8f46a9 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.kt
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.kt
@@ -26,7 +26,6 @@
import com.android.launcher3.anim.AnimatorListeners.forSuccessCallback
import com.android.launcher3.anim.PendingAnimation
import com.android.launcher3.anim.PropertySetter
-import com.android.launcher3.config.FeatureFlags.enableSplitContextually
import com.android.launcher3.logging.StatsLogManager.LauncherEvent
import com.android.launcher3.statemanager.StateManager.StateHandler
import com.android.launcher3.states.StateAnimationConfig
@@ -53,7 +52,6 @@
import com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION
import com.android.quickstep.views.RecentsView.TASK_THUMBNAIL_SPLASH_ALPHA
import com.android.quickstep.views.TaskView.Companion.FLAG_UPDATE_ALL
-import com.android.wm.shell.Flags.enableSplitContextual
/**
* State handler for handling UI changes for [com.android.quickstep.views.LauncherRecentsView]. In
@@ -129,23 +127,6 @@
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR),
)
- val exitingOverview = !enableSplitContextually() && !toState.isRecentsViewVisible
- if (recentsView.isSplitSelectionActive && exitingOverview) {
- builder.add(
- recentsView.splitSelectController.splitAnimationController
- .createPlaceholderDismissAnim(
- launcher,
- LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_HOME,
- builder.duration,
- )
- )
- builder.setViewAlpha(
- recentsView.splitInstructionsView,
- 0f,
- config.getInterpolator(ANIM_OVERVIEW_SPLIT_SELECT_INSTRUCTIONS_FADE, LINEAR),
- )
- }
-
builder.setFloat(
recentsView,
CONTENT_ALPHA,
@@ -227,9 +208,7 @@
builder: PendingAnimation,
animate: Boolean,
) {
- val goingToOverviewFromWorkspaceContextual =
- enableSplitContextual() &&
- toState == LauncherState.OVERVIEW &&
+ val goingToOverviewFromWorkspaceContextual = toState == LauncherState.OVERVIEW &&
launcher.isSplitSelectionActive
if (
toState != LauncherState.OVERVIEW_SPLIT_SELECT &&
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index c48ba4f..5c16a62 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -18,7 +18,6 @@
import static com.android.app.animation.Interpolators.DECELERATE_2;
import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
-import static com.android.wm.shell.Flags.enableSplitContextual;
import android.content.Context;
import android.graphics.Rect;
@@ -123,7 +122,7 @@
if (showFloatingSearch) {
elements |= FLOATING_SEARCH_BAR;
}
- if (enableSplitContextual() && launcher.isSplitSelectionActive()) {
+ if (launcher.isSplitSelectionActive()) {
elements &= ~CLEAR_ALL_BUTTON;
}
return elements;
@@ -131,7 +130,7 @@
@Override
public float getSplitSelectTranslation(Launcher launcher) {
- if (!enableSplitContextual() || !launcher.isSplitSelectionActive()) {
+ if (!launcher.isSplitSelectionActive()) {
return 0f;
}
RecentsView recentsView = launcher.getOverviewPanel();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index 3f0839d..a4f8b81 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -210,10 +210,7 @@
mLauncher.getStateManager().addStateListener(listener);
onSwipeInteractionCompleted(mEndState);
};
- new OverviewToHomeAnim(mLauncher, onReachedHome,
- FeatureFlags.enableSplitContextually()
- ? mCancelSplitRunnable
- : null)
+ new OverviewToHomeAnim(mLauncher, onReachedHome, mCancelSplitRunnable)
.animateWithVelocity(velocity);
} else {
mLauncher.getStateManager().goToState(mEndState, true,
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 0042c8a..98228ad 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -31,7 +31,6 @@
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
import static com.android.launcher3.Flags.enableAdditionalHomeAnimations;
-import static com.android.launcher3.Flags.enableGridOnlyOverview;
import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.Flags.msdlFeedback;
import static com.android.launcher3.PagedView.INVALID_PAGE;
@@ -100,7 +99,6 @@
import android.widget.Toast;
import android.window.DesktopModeFlags;
import android.window.PictureInPictureSurfaceTransaction;
-import android.window.TransitionInfo;
import android.window.WindowAnimationState;
import androidx.annotation.NonNull;
@@ -956,10 +954,10 @@
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
- super.onRecentsAnimationStart(controller, targets, transitionInfo);
+ RecentsAnimationTargets targets) {
+ super.onRecentsAnimationStart(controller, targets);
if (targets.hasDesktopTasks(mContext)) {
- mRemoteTargetHandles = mTargetGluer.assignTargetsForDesktop(targets, transitionInfo);
+ mRemoteTargetHandles = mTargetGluer.assignTargetsForDesktop(targets);
} else {
int untrimmedAppCount = mRemoteTargetHandles.length;
mRemoteTargetHandles = mTargetGluer.assignTargetsForSplitScreen(targets);
@@ -2688,9 +2686,7 @@
}
float scrollOffset = Math.abs(mRecentsView.getScrollOffset(mRecentsView.getCurrentPage()));
- Rect carouselTaskSize = enableGridOnlyOverview()
- ? mRecentsView.getLastComputedCarouselTaskSize()
- : mRecentsView.getLastComputedTaskSize();
+ Rect carouselTaskSize = mRecentsView.getLastComputedTaskSize();
int maxScrollOffset = mRecentsView.getPagedOrientationHandler().getPrimaryValue(
carouselTaskSize.width(), carouselTaskSize.height());
maxScrollOffset += mRecentsView.getPageSpacing();
diff --git a/quickstep/src/com/android/quickstep/BaseContainerInterface.java b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
index b20518c..6d588d9 100644
--- a/quickstep/src/com/android/quickstep/BaseContainerInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
@@ -251,11 +251,7 @@
public final void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect,
RecentsPagedOrientationHandler orientationHandler) {
if (dp.isTablet) {
- if (Flags.enableGridOnlyOverview()) {
- calculateGridTaskSize(context, dp, outRect, orientationHandler);
- } else {
- calculateFocusTaskSize(context, dp, outRect);
- }
+ calculateLargeTileSize(context, dp, outRect);
} else {
Resources res = context.getResources();
float maxScale = res.getFloat(R.dimen.overview_max_scale);
@@ -276,24 +272,7 @@
}
}
- /**
- * Calculates the taskView size for carousel during app to overview animation on tablets.
- */
- public final void calculateCarouselTaskSize(Context context, DeviceProfile dp, Rect outRect,
- RecentsPagedOrientationHandler orientationHandler) {
- if (dp.isTablet && dp.isGestureMode) {
- Resources res = context.getResources();
- float minScale = res.getFloat(R.dimen.overview_carousel_min_scale);
- Rect gridRect = new Rect();
- calculateGridSize(dp, context, gridRect);
- calculateTaskSizeInternal(context, dp, gridRect, minScale, Gravity.CENTER | Gravity.TOP,
- outRect);
- } else {
- calculateTaskSize(context, dp, outRect, orientationHandler);
- }
- }
-
- private void calculateFocusTaskSize(Context context, DeviceProfile dp, Rect outRect) {
+ private void calculateLargeTileSize(Context context, DeviceProfile dp, Rect outRect) {
Resources res = context.getResources();
float maxScale = res.getFloat(R.dimen.overview_max_scale);
Rect gridRect = new Rect();
@@ -381,12 +360,6 @@
Rect insets = dp.getInsets();
int topMargin = dp.overviewTaskThumbnailTopMarginPx;
int bottomMargin = dp.getOverviewActionsClaimedSpace();
- if (dp.isTaskbarPresent && Flags.enableGridOnlyOverview()) {
- topMargin += context.getResources().getDimensionPixelSize(
- R.dimen.overview_top_margin_grid_only);
- bottomMargin += context.getResources().getDimensionPixelSize(
- R.dimen.overview_bottom_margin_grid_only);
- }
int sideMargin = dp.overviewGridSideMargin;
outRect.set(0, 0, dp.widthPx, dp.heightPx);
@@ -401,11 +374,7 @@
RecentsPagedOrientationHandler orientationHandler) {
Resources res = context.getResources();
Rect potentialTaskRect = new Rect();
- if (Flags.enableGridOnlyOverview()) {
- calculateGridSize(dp, context, potentialTaskRect);
- } else {
- calculateFocusTaskSize(context, dp, potentialTaskRect);
- }
+ calculateLargeTileSize(context, dp, potentialTaskRect);
float rowHeight = (potentialTaskRect.height() + dp.overviewTaskThumbnailTopMarginPx
- dp.overviewRowSpacing) / 2f;
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index e0fa77a..cfbcf0a 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -33,7 +33,6 @@
import android.os.SystemClock;
import android.view.MotionEvent;
import android.view.RemoteAnimationTarget;
-import android.window.TransitionInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -492,7 +491,7 @@
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets, TransitionInfo info) {
+ RecentsAnimationTargets targets) {
mStateCallback.setState(STATE_RECENTS_ANIMATION_STARTED);
}
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
index 66f307c..089706f 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
@@ -23,7 +23,6 @@
import android.os.Trace
import android.util.Log
import android.view.View
-import android.window.TransitionInfo
import androidx.annotation.BinderThread
import androidx.annotation.UiThread
import androidx.annotation.VisibleForTesting
@@ -370,7 +369,6 @@
override fun onRecentsAnimationStart(
controller: RecentsAnimationController,
targets: RecentsAnimationTargets,
- transitionInfo: TransitionInfo,
) {
Log.d(TAG, "recents animation started: $command")
updateRecentsViewFocus(command)
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index 87bf81c..8fc1a78 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -26,7 +26,6 @@
import android.os.Bundle;
import android.util.ArraySet;
import android.view.RemoteAnimationTarget;
-import android.window.TransitionInfo;
import androidx.annotation.BinderThread;
import androidx.annotation.NonNull;
@@ -94,7 +93,7 @@
RemoteAnimationTarget[] appTargets, Rect homeContentInsets,
Rect minimizedHomeBounds, Bundle extras) {
onAnimationStart(controller, appTargets, new RemoteAnimationTarget[0],
- homeContentInsets, minimizedHomeBounds, extras, /* transitionInfo= */ null);
+ homeContentInsets, minimizedHomeBounds, extras);
}
// Called only in R+ platform
@@ -102,8 +101,7 @@
public final void onAnimationStart(RecentsAnimationControllerCompat animationController,
RemoteAnimationTarget[] appTargets,
RemoteAnimationTarget[] wallpaperTargets,
- Rect homeContentInsets, Rect minimizedHomeBounds, Bundle extras,
- TransitionInfo transitionInfo) {
+ Rect homeContentInsets, Rect minimizedHomeBounds, Bundle extras) {
long appCount = Arrays.stream(appTargets)
.filter(app -> app.mode == MODE_CLOSING)
.count();
@@ -143,7 +141,7 @@
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
ActiveGestureProtoLogProxy.logOnRecentsAnimationStart(targets.apps.length);
for (RecentsAnimationListener listener : getListeners()) {
- listener.onRecentsAnimationStart(mController, targets, transitionInfo);
+ listener.onRecentsAnimationStart(mController, targets);
}
});
}
@@ -207,7 +205,7 @@
*/
public interface RecentsAnimationListener {
default void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets, TransitionInfo transitionInfo) {}
+ RecentsAnimationTargets targets) {}
/**
* Callback from the system when the recents animation is canceled. {@param thumbnailData}
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index 8edbacb..89337e5 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -24,7 +24,6 @@
import android.graphics.Rect;
import android.util.Log;
import android.view.RemoteAnimationTarget;
-import android.window.TransitionInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -214,8 +213,7 @@
* Similar to {@link #assignTargets(RemoteAnimationTargets)}, except this creates distinct
* transform params per app in {@code targets.apps} list.
*/
- public RemoteTargetHandle[] assignTargetsForDesktop(
- RemoteAnimationTargets targets, TransitionInfo transitionInfo) {
+ public RemoteTargetHandle[] assignTargetsForDesktop(RemoteAnimationTargets targets) {
resizeRemoteTargetHandles(targets);
for (int i = 0; i < mRemoteTargetHandles.length; i++) {
@@ -224,7 +222,6 @@
.filter(target -> target.taskId != primaryTaskTarget.taskId).toList();
mRemoteTargetHandles[i].mTransformParams.setTargetSet(
createRemoteAnimationTargetsForTarget(targets, excludeTargets));
- mRemoteTargetHandles[i].mTransformParams.setTransitionInfo(transitionInfo);
mRemoteTargetHandles[i].mTaskViewSimulator.setPreview(primaryTaskTarget, null);
}
return mRemoteTargetHandles;
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index 910963d..233f0a9 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -112,7 +112,7 @@
PendingAnimation pendingAnimation = new PendingAnimation(mTransitionDragLength * 2);
TaskViewSimulator taskViewSimulator = remoteHandle.getTaskViewSimulator();
taskViewSimulator.setDp(dp);
- taskViewSimulator.addAppToOverviewAnim(pendingAnimation, LINEAR);
+ taskViewSimulator.addAppToCarouselAnim(pendingAnimation, LINEAR);
AnimatorPlaybackController playbackController =
pendingAnimation.createPlaybackController();
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.kt b/quickstep/src/com/android/quickstep/SystemUiProxy.kt
index f2cedba..feb9107 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.kt
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.kt
@@ -45,7 +45,6 @@
import android.window.RemoteTransition
import android.window.TaskSnapshot
import android.window.TransitionFilter
-import android.window.TransitionInfo
import androidx.annotation.MainThread
import androidx.annotation.VisibleForTesting
import androidx.annotation.WorkerThread
@@ -1176,7 +1175,6 @@
homeContentInsets: Rect?,
minimizedHomeBounds: Rect?,
extras: Bundle?,
- transitionInfo: TransitionInfo?,
) =
listener.onAnimationStart(
RecentsAnimationControllerCompat(controller),
@@ -1189,7 +1187,6 @@
// https://developer.android.com/guide/components/aidl#Bundles
classLoader = SplitBounds::class.java.classLoader
},
- transitionInfo,
)
override fun onAnimationCanceled(taskIds: IntArray?, taskSnapshots: Array<TaskSnapshot>?) =
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 1fd7211..731c256 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -35,7 +35,6 @@
import android.os.SystemProperties;
import android.util.Log;
import android.view.RemoteAnimationTarget;
-import android.window.TransitionInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -68,7 +67,6 @@
private RecentsAnimationController mController;
private RecentsAnimationCallbacks mCallbacks;
private RecentsAnimationTargets mTargets;
- private TransitionInfo mTransitionInfo;
private RecentsAnimationDeviceState mDeviceState;
// Temporary until we can hook into gesture state events
@@ -156,7 +154,7 @@
mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
+ RecentsAnimationTargets targets) {
if (enableHandleDelayedGestureCallbacks() && mRecentsAnimationStartPending) {
ActiveGestureProtoLogProxy.logStartRecentsAnimationCallback(
"onRecentsAnimationStart");
@@ -170,7 +168,6 @@
}
mController = controller;
mTargets = targets;
- mTransitionInfo = transitionInfo;
// TODO(b/236226779): We can probably get away w/ setting mLastAppearedTaskTargets
// to all appeared targets directly vs just looking at running ones
int[] runningTaskIds = mLastGestureState.getRunningTaskIds(targets.apps.length > 1);
@@ -439,7 +436,7 @@
public void notifyRecentsAnimationState(
RecentsAnimationCallbacks.RecentsAnimationListener listener) {
if (isRecentsAnimationRunning()) {
- listener.onRecentsAnimationStart(mController, mTargets, mTransitionInfo);
+ listener.onRecentsAnimationStart(mController, mTargets);
}
// TODO: Do we actually need to report canceled/finished?
}
@@ -479,7 +476,6 @@
mController = null;
mCallbacks = null;
mTargets = null;
- mTransitionInfo = null;
mLastGestureState = null;
mLastAppearedTaskTargets = null;
}
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 3e90374..c21ffb7 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -22,6 +22,7 @@
import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.app.animation.Interpolators.TOUCH_RESPONSE;
import static com.android.app.animation.Interpolators.clampToProgress;
+import static com.android.launcher3.Flags.enableGridOnlyOverview;
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
@@ -189,8 +190,7 @@
RemoteTargetGluer gluer = new RemoteTargetGluer(v.getContext(),
recentsView.getSizeStrategy(), targets, forDesktop);
if (forDesktop) {
- remoteTargetHandles =
- gluer.assignTargetsForDesktop(targets, /* transitionInfo=*/ null);
+ remoteTargetHandles = gluer.assignTargetsForDesktop(targets);
} else if (v.containsMultipleTasks()) {
remoteTargetHandles = gluer.assignTargetsForSplitScreen(targets,
((GroupedTaskView) v).getSplitBoundsConfig());
@@ -233,7 +233,9 @@
tvsLocal.fullScreenProgress.value = 0;
tvsLocal.recentsViewScale.value = 1;
- tvsLocal.setIsGridTask(v.isGridTask());
+ if (!enableGridOnlyOverview()) {
+ tvsLocal.setIsGridTask(v.isGridTask());
+ }
tvsLocal.getOrientationState().getOrientationHandler().set(tvsLocal,
TaskViewSimulator::setTaskRectTranslation, taskRectTranslationPrimary,
taskRectTranslationSecondary);
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 76da4af..d9209bf 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -284,11 +284,7 @@
}
if (finalState != OVERVIEW_SPLIT_SELECT) {
- if (FeatureFlags.enableSplitContextually()) {
- mSplitSelectStateController.resetState();
- } else {
- resetFromSplitSelectionState();
- }
+ mSplitSelectStateController.resetState();
}
// disabling this so app icons aren't drawn on top of recent tasks.
diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsDisplayModel.kt b/quickstep/src/com/android/quickstep/fallback/window/RecentsDisplayModel.kt
index 505f2cb..e7e9f51 100644
--- a/quickstep/src/com/android/quickstep/fallback/window/RecentsDisplayModel.kt
+++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsDisplayModel.kt
@@ -17,7 +17,6 @@
package com.android.quickstep.fallback.window
import android.content.Context
-import android.os.Handler
import android.util.Log
import android.view.Display
import com.android.launcher3.Flags
@@ -25,7 +24,7 @@
import com.android.launcher3.dagger.LauncherAppSingleton
import com.android.launcher3.util.DaggerSingletonObject
import com.android.launcher3.util.DaggerSingletonTracker
-import com.android.launcher3.util.Executors.MAIN_EXECUTOR
+import com.android.launcher3.util.Executors
import com.android.quickstep.DisplayModel
import com.android.quickstep.FallbackWindowInterface
import com.android.quickstep.dagger.QuickstepBaseAppComponent
@@ -51,15 +50,13 @@
init {
if (Flags.enableFallbackOverviewInWindow() || Flags.enableLauncherOverviewInWindow()) {
- MAIN_EXECUTOR.execute {
- displayManager.registerDisplayListener(displayListener, Handler.getMain())
- // In the scenario where displays were added before this display listener was
- // registered, we should store the RecentsDisplayResources for those displays
- // directly.
- displayManager.displays
- .filter { getDisplayResource(it.displayId) == null }
- .forEach { storeRecentsDisplayResource(it.displayId, it) }
- }
+ displayManager.registerDisplayListener(displayListener, Executors.MAIN_EXECUTOR.handler)
+ // In the scenario where displays were added before this display listener was
+ // registered, we should store the RecentsDisplayResources for those displays
+ // directly.
+ displayManager.displays
+ .filter { getDisplayResource(it.displayId) == null }
+ .forEach { storeRecentsDisplayResource(it.displayId, it) }
tracker.addCloseable { destroy() }
}
}
diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java
index 973fb2f..12bae53 100644
--- a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java
@@ -49,7 +49,6 @@
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.animation.Interpolator;
-import android.window.TransitionInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -125,8 +124,8 @@
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
- super.onRecentsAnimationStart(controller, targets, transitionInfo);
+ RecentsAnimationTargets targets) {
+ super.onRecentsAnimationStart(controller, targets);
initTransformParams();
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index 503b900..01f5522 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -37,7 +37,6 @@
import android.view.MotionEvent;
import android.view.RemoteAnimationTarget;
import android.view.VelocityTracker;
-import android.window.TransitionInfo;
import com.android.app.animation.Interpolators;
import com.android.launcher3.R;
@@ -250,7 +249,7 @@
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
+ RecentsAnimationTargets targets) {
mRecentsAnimationController = controller;
mTransformParams.setTargetSet(targets);
applyTransform();
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
index f5bef05e..afe988d 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
@@ -242,7 +242,7 @@
private void cancelLongPress(String reason) {
if (DEBUG_NAV_HANDLE) {
- Log.d(TAG, "cancelLongPress");
+ Log.d(TAG, "cancelLongPress: " + reason);
}
mGestureState.setIsInExtendedSlopRegion(false);
MAIN_EXECUTOR.getHandler().removeCallbacks(mTriggerLongPress);
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 870a479..f33eb5e 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -293,15 +293,15 @@
float upDist = -displacement;
boolean isTrackpadGesture = mGestureState.isTrackpadGesture();
float squaredHypot = squaredHypot(displacementX, displacementY);
- boolean isInExtendedSlopRegion = !mGestureState.isInExtendedSlopRegion();
+ boolean isInExtendedSlopRegion = mGestureState.isInExtendedSlopRegion();
boolean passedSlop = isTrackpadGesture
|| (squaredHypot >= mSquaredTouchSlop
- && isInExtendedSlopRegion);
+ && !isInExtendedSlopRegion);
if (DEBUG) {
Log.d(TAG, "ACTION_MOVE: passedSlop=" + passedSlop
+ " ( " + isTrackpadGesture
+ " || (" + squaredHypot + " >= " + mSquaredTouchSlop
- + " && " + isInExtendedSlopRegion + " ))");
+ + " && " + !isInExtendedSlopRegion + " ))");
}
if (!mPassedSlopOnThisGesture && passedSlop) {
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
index c91bebe..6dcb7bc 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
@@ -28,7 +28,6 @@
import android.content.Intent;
import android.graphics.Point;
import android.view.MotionEvent;
-import android.window.TransitionInfo;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.AnimatorListeners;
@@ -173,7 +172,7 @@
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
+ RecentsAnimationTargets targets) {
mRecentsAnimationController = controller;
mStateCallback.setState(STATE_TARGET_RECEIVED);
}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 7d14a3e..0fc95e2 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -80,8 +80,8 @@
private static final CharSequence DEFAULT_PIXEL_TIPS_APP_NAME = "Pixel Tips";
private static final int FEEDBACK_ANIMATION_MS = 133;
- private static final int RIPPLE_VISIBLE_MS = 300;
- private static final int GESTURE_ANIMATION_DELAY_MS = 1500;
+ private static final int SUBTITLE_ANNOUNCE_DELAY_MS = 3000;
+ private static final int DONE_BUTTON_ANNOUNCE_DELAY_MS = 4000;
private static final int ADVANCE_TUTORIAL_TIMEOUT_MS = 3000;
private static final long GESTURE_ANIMATION_PAUSE_DURATION_MILLIS = 1000;
protected float mExitingAppEndingCornerRadius;
@@ -124,10 +124,12 @@
// These runnables should be used when posting callbacks to their views and cleared from their
// views before posting new callbacks.
private final Runnable mTitleViewCallback;
+ private final Runnable mSubtitleViewCallback;
@Nullable private Runnable mFeedbackViewCallback;
@Nullable private Runnable mFakeTaskViewCallback;
@Nullable private Runnable mFakeTaskbarViewCallback;
private final Runnable mShowFeedbackRunnable;
+ private final AccessibilityManager mAccessibilityManager;
TutorialController(TutorialFragment tutorialFragment, TutorialType tutorialType) {
mTutorialFragment = tutorialFragment;
@@ -175,6 +177,7 @@
mFeedbackTitleView.setText(getIntroductionTitle());
mFeedbackSubtitleView.setText(getIntroductionSubtitle());
+
mExitingAppView.setClipToOutline(true);
mExitingAppView.setOutlineProvider(new ViewOutlineProvider() {
@Override
@@ -183,8 +186,16 @@
}
});
- mTitleViewCallback = () -> mFeedbackTitleView.sendAccessibilityEvent(
- AccessibilityEvent.TYPE_VIEW_FOCUSED);
+ mAccessibilityManager = AccessibilityManager.getInstance(mContext);
+ mTitleViewCallback = () -> {
+ mFeedbackTitleView.requestFocus();
+ mFeedbackTitleView.sendAccessibilityEvent(
+ AccessibilityEvent.TYPE_VIEW_FOCUSED);
+ };
+ mSubtitleViewCallback = () -> {
+ mFeedbackSubtitleView.requestFocus();
+ mFeedbackSubtitleView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+ };
mShowFeedbackRunnable = () -> {
mFeedbackView.setAlpha(0f);
mFeedbackView.setScaleX(0.95f);
@@ -203,10 +214,10 @@
mFeedbackViewCallback = mTutorialFragment::continueTutorial;
mFeedbackView.postDelayed(
mFeedbackViewCallback,
- AccessibilityManager.getInstance(mContext)
- .getRecommendedTimeoutMillis(
- ADVANCE_TUTORIAL_TIMEOUT_MS,
- AccessibilityManager.FLAG_CONTENT_TEXT));
+ mAccessibilityManager.getRecommendedTimeoutMillis(
+ ADVANCE_TUTORIAL_TIMEOUT_MS,
+ AccessibilityManager.FLAG_CONTENT_TEXT
+ | AccessibilityManager.FLAG_CONTENT_CONTROLS));
}
})
.start();
@@ -404,6 +415,7 @@
int subtitleResId,
boolean isGestureSuccessful) {
mFeedbackTitleView.removeCallbacks(mTitleViewCallback);
+ mFeedbackSubtitleView.removeCallbacks(mSubtitleViewCallback);
if (mFeedbackViewCallback != null) {
mFeedbackView.removeCallbacks(mFeedbackViewCallback);
mFeedbackViewCallback = null;
@@ -411,6 +423,15 @@
mFeedbackTitleView.setText(titleResId);
mFeedbackSubtitleView.setText(subtitleResId);
+ mFeedbackTitleView.postDelayed(mTitleViewCallback, mAccessibilityManager
+ .getRecommendedTimeoutMillis(
+ FEEDBACK_ANIMATION_MS,
+ AccessibilityManager.FLAG_CONTENT_TEXT));
+ mFeedbackSubtitleView.postDelayed(mSubtitleViewCallback, mAccessibilityManager
+ .getRecommendedTimeoutMillis(
+ SUBTITLE_ANNOUNCE_DELAY_MS,
+ AccessibilityManager.FLAG_CONTENT_TEXT));
+
if (isGestureSuccessful) {
if (mTutorialFragment.isAtFinalStep()) {
showActionButton();
@@ -467,6 +488,7 @@
mFakeTaskbarViewCallback = null;
}
mFeedbackTitleView.removeCallbacks(mTitleViewCallback);
+ mFeedbackSubtitleView.removeCallbacks(mSubtitleViewCallback);
}
private void playFeedbackAnimation() {
@@ -542,6 +564,13 @@
mSkipButton.setVisibility(GONE);
mDoneButton.setVisibility(View.VISIBLE);
mDoneButton.setOnClickListener(this::onActionButtonClicked);
+ mDoneButton.postDelayed(() -> {
+ mDoneButton.requestFocus();
+ mDoneButton.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
+ }, mAccessibilityManager
+ .getRecommendedTimeoutMillis(
+ DONE_BUTTON_ANNOUNCE_DELAY_MS,
+ AccessibilityManager.FLAG_CONTENT_CONTROLS));
}
void hideFakeTaskbar(boolean animateToHotseat) {
diff --git a/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfile.kt b/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfile.kt
index d2cb595..0ee2bd2 100644
--- a/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfile.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfile.kt
@@ -20,7 +20,6 @@
* Container to hold [com.android.launcher3.DeviceProfile] related to Recents.
*
* @property isLargeScreen whether the current device posture has a large screen
+ * @property canEnterDesktopMode whether the current device can enter Desktop UI mode
*/
-data class RecentsDeviceProfile(
- val isLargeScreen: Boolean,
-)
+data class RecentsDeviceProfile(val isLargeScreen: Boolean, val canEnterDesktopMode: Boolean)
diff --git a/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImpl.kt b/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImpl.kt
index c64453d..8450f09 100644
--- a/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImpl.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImpl.kt
@@ -17,6 +17,7 @@
package com.android.quickstep.recents.data
import com.android.quickstep.views.RecentsViewContainer
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
/**
* Repository for shrink down version of [com.android.launcher3.DeviceProfile] that only contains
@@ -26,5 +27,10 @@
RecentsDeviceProfileRepository {
override fun getRecentsDeviceProfile() =
- with(container.deviceProfile) { RecentsDeviceProfile(isLargeScreen = isTablet) }
+ with(container.deviceProfile) {
+ RecentsDeviceProfile(
+ isLargeScreen = isTablet,
+ canEnterDesktopMode = DesktopModeStatus.canEnterDesktopMode(container.asContext()),
+ )
+ }
}
diff --git a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
index dd83af6..2b364f9 100644
--- a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
+++ b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
@@ -182,6 +182,7 @@
dispatcherProvider = inject(),
getThumbnailPositionUseCase = inject(),
tasksRepository = inject(),
+ deviceProfileRepository = inject(),
splashAlphaUseCase = inject(scopeId),
)
TaskOverlayViewModel::class.java -> {
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
index 36a86f2..6118544 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
@@ -24,18 +24,35 @@
sealed class TaskThumbnailUiState {
data object Uninitialized : TaskThumbnailUiState()
- data object LiveTile : TaskThumbnailUiState()
-
data class BackgroundOnly(@ColorInt val backgroundColor: Int) : TaskThumbnailUiState()
- data class SnapshotSplash(
- val snapshot: Snapshot,
- val splash: Drawable?,
- ) : TaskThumbnailUiState()
+ data class SnapshotSplash(val snapshot: Snapshot, val splash: Drawable?) :
+ TaskThumbnailUiState()
- data class Snapshot(
- val bitmap: Bitmap,
- @Surface.Rotation val thumbnailRotation: Int,
- @ColorInt val backgroundColor: Int
- )
+ sealed class LiveTile : TaskThumbnailUiState() {
+ data class WithHeader(val header: ThumbnailHeader) : LiveTile()
+
+ data object WithoutHeader : LiveTile()
+ }
+
+ sealed class Snapshot {
+ abstract val bitmap: Bitmap
+ abstract val thumbnailRotation: Int
+ abstract val backgroundColor: Int
+
+ data class WithHeader(
+ override val bitmap: Bitmap,
+ @Surface.Rotation override val thumbnailRotation: Int,
+ @ColorInt override val backgroundColor: Int,
+ val header: ThumbnailHeader,
+ ) : Snapshot()
+
+ data class WithoutHeader(
+ override val bitmap: Bitmap,
+ @Surface.Rotation override val thumbnailRotation: Int,
+ @ColorInt override val backgroundColor: Int,
+ ) : Snapshot()
+ }
+
+ data class ThumbnailHeader(val icon: Drawable, val title: String)
}
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
index b040723..639d3a7 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
@@ -22,11 +22,13 @@
import android.graphics.Rect
import android.util.AttributeSet
import android.util.Log
+import android.view.LayoutInflater
import android.view.View
import android.view.ViewOutlineProvider
import android.widget.FrameLayout
import androidx.annotation.ColorInt
import androidx.core.view.isInvisible
+import com.android.launcher3.Flags.enableDesktopExplodedView
import com.android.launcher3.R
import com.android.launcher3.util.ViewPool
import com.android.launcher3.util.coroutines.DispatcherProvider
@@ -39,11 +41,14 @@
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
import com.android.quickstep.task.viewmodel.TaskThumbnailViewModel
import com.android.quickstep.views.FixedSizeImageView
+import com.android.quickstep.views.TaskThumbnailViewHeader
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.dropWhile
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
@@ -66,6 +71,8 @@
private val splashBackground: View by lazy { findViewById(R.id.splash_background) }
private val splashIcon: FixedSizeImageView by lazy { findViewById(R.id.splash_icon) }
+ private var taskThumbnailViewHeader: TaskThumbnailViewHeader? = null
+
private var uiState: TaskThumbnailUiState = Uninitialized
private val bounds = Rect()
@@ -86,6 +93,12 @@
defStyleAttr: Int,
) : super(context, attrs, defStyleAttr)
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+
+ maybeCreateHeader()
+ }
+
override fun onAttachedToWindow() {
super.onAttachedToWindow()
viewAttachedScope =
@@ -96,22 +109,28 @@
updateViewDataValues()
viewModel = RecentsDependencies.get(this)
viewModel.uiState
+ .dropWhile { it == Uninitialized }
+ .flowOn(dispatcherProvider.background)
.onEach { viewModelUiState ->
Log.d(TAG, "viewModelUiState changed from: $uiState to: $viewModelUiState")
uiState = viewModelUiState
resetViews()
when (viewModelUiState) {
is Uninitialized -> {}
- is LiveTile -> drawLiveWindow()
+ is LiveTile -> drawLiveWindow(viewModelUiState)
is SnapshotSplash -> drawSnapshotSplash(viewModelUiState)
is BackgroundOnly -> drawBackground(viewModelUiState.backgroundColor)
}
}
.launchIn(viewAttachedScope)
viewModel.dimProgress
+ .dropWhile { it == 0f }
+ .flowOn(dispatcherProvider.background)
.onEach { dimProgress -> scrimView.alpha = dimProgress }
.launchIn(viewAttachedScope)
viewModel.splashAlpha
+ .dropWhile { it == 0f }
+ .flowOn(dispatcherProvider.background)
.onEach { splashAlpha ->
splashBackground.alpha = splashAlpha
splashIcon.alpha = splashAlpha
@@ -137,6 +156,7 @@
override fun onRecycle() {
uiState = Uninitialized
+ resetViews()
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
@@ -179,14 +199,20 @@
splashIcon.alpha = 0f
scrimView.alpha = 0f
setBackgroundColor(Color.BLACK)
+ taskThumbnailViewHeader?.isInvisible = true
}
private fun drawBackground(@ColorInt background: Int) {
setBackgroundColor(background)
}
- private fun drawLiveWindow() {
+ private fun drawLiveWindow(liveTile: LiveTile) {
liveTileView.isInvisible = false
+
+ if (liveTile is LiveTile.WithHeader) {
+ taskThumbnailViewHeader?.isInvisible = false
+ taskThumbnailViewHeader?.setHeader(liveTile.header)
+ }
}
private fun drawSnapshotSplash(snapshotSplash: SnapshotSplash) {
@@ -197,6 +223,11 @@
}
private fun drawSnapshot(snapshot: Snapshot) {
+ if (snapshot is Snapshot.WithHeader) {
+ taskThumbnailViewHeader?.isInvisible = false
+ taskThumbnailViewHeader?.setHeader(snapshot.header)
+ }
+
drawBackground(snapshot.backgroundColor)
thumbnailView.setImageBitmap(snapshot.bitmap)
thumbnailView.isInvisible = false
@@ -210,4 +241,14 @@
private companion object {
const val TAG = "TaskThumbnailView"
}
+
+ private fun maybeCreateHeader() {
+ if (enableDesktopExplodedView() && taskThumbnailViewHeader == null) {
+ taskThumbnailViewHeader =
+ LayoutInflater.from(context)
+ .inflate(R.layout.task_thumbnail_view_header, this, false)
+ as TaskThumbnailViewHeader
+ addView(taskThumbnailViewHeader)
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt b/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt
index 677875c..f51660b 100644
--- a/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt
+++ b/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt
@@ -32,6 +32,8 @@
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.dropWhile
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
@@ -79,6 +81,8 @@
dispatcherProvider = RecentsDependencies.get(),
)
viewModel.overlayState
+ .dropWhile { it == Disabled }
+ .flowOn(dispatcherProvider.background)
.onEach {
uiState = it
if (it is Enabled) {
diff --git a/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModelImpl.kt b/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModelImpl.kt
index b5b2fc9..a154c3c 100644
--- a/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModelImpl.kt
+++ b/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModelImpl.kt
@@ -18,11 +18,14 @@
import android.annotation.ColorInt
import android.app.ActivityTaskManager.INVALID_TASK_ID
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
import android.graphics.Matrix
import android.util.Log
import androidx.core.graphics.ColorUtils
+import com.android.launcher3.Flags.enableDesktopExplodedView
import com.android.launcher3.util.coroutines.DispatcherProvider
import com.android.quickstep.recents.data.RecentTasksRepository
+import com.android.quickstep.recents.data.RecentsDeviceProfileRepository
import com.android.quickstep.recents.usecase.GetThumbnailPositionUseCase
import com.android.quickstep.recents.usecase.ThumbnailPositionState
import com.android.quickstep.recents.viewmodel.RecentsViewData
@@ -32,6 +35,7 @@
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Snapshot
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.SnapshotSplash
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.ThumbnailHeader
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
import com.android.systemui.shared.recents.model.Task
import kotlin.math.max
@@ -51,6 +55,7 @@
taskContainerData: TaskContainerData,
dispatcherProvider: DispatcherProvider,
private val tasksRepository: RecentTasksRepository,
+ private val deviceProfileRepository: RecentsDeviceProfileRepository,
private val getThumbnailPositionUseCase: GetThumbnailPositionUseCase,
private val splashAlphaUseCase: SplashAlphaUseCase,
) : TaskThumbnailViewModel {
@@ -90,7 +95,7 @@
// )
when {
taskVal == null -> Uninitialized
- isRunning -> LiveTile
+ isRunning -> createLiveTileState(taskVal)
isBackgroundOnly(taskVal) ->
BackgroundOnly(taskVal.colorBackground.removeAlpha())
isSnapshotSplashState(taskVal) ->
@@ -129,7 +134,46 @@
private fun createSnapshotState(task: Task): Snapshot {
val thumbnailData = task.thumbnail
val bitmap = thumbnailData?.thumbnail!!
- return Snapshot(bitmap, thumbnailData.rotation, task.colorBackground.removeAlpha())
+ var thumbnailHeader = maybeCreateHeader(task)
+ return if (thumbnailHeader != null)
+ Snapshot.WithHeader(
+ bitmap,
+ thumbnailData.rotation,
+ task.colorBackground.removeAlpha(),
+ thumbnailHeader,
+ )
+ else
+ Snapshot.WithoutHeader(
+ bitmap,
+ thumbnailData.rotation,
+ task.colorBackground.removeAlpha(),
+ )
+ }
+
+ private fun shouldHaveThumbnailHeader(task: Task): Boolean {
+ return deviceProfileRepository.getRecentsDeviceProfile().canEnterDesktopMode &&
+ enableDesktopExplodedView() &&
+ task.key.windowingMode == WINDOWING_MODE_FREEFORM
+ }
+
+ private fun maybeCreateHeader(task: Task): ThumbnailHeader? {
+ // Header is only needed when this task is a desktop task and Overivew exploded view is
+ // enabled.
+ if (!shouldHaveThumbnailHeader(task)) {
+ return null
+ }
+
+ // TODO(http://b/353965691): figure out what to do when `icon` or `titleDescription` is
+ // null.
+ val icon = task.icon ?: return null
+ val titleDescription = task.titleDescription ?: return null
+ return ThumbnailHeader(icon, titleDescription)
+ }
+
+ private fun createLiveTileState(task: Task): LiveTile {
+ val thumbnailHeader = maybeCreateHeader(task)
+ return if (thumbnailHeader != null) LiveTile.WithHeader(thumbnailHeader)
+ else LiveTile.WithoutHeader
}
@ColorInt private fun Int.removeAlpha(): Int = ColorUtils.setAlphaComponent(this, 0xff)
diff --git a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
index b583a4b..37d7030 100644
--- a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
+++ b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
@@ -17,7 +17,6 @@
import static com.android.app.animation.Interpolators.DECELERATE;
import static com.android.app.animation.Interpolators.LINEAR;
-import static com.android.launcher3.Flags.enableGridOnlyOverview;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
@@ -50,7 +49,6 @@
private enum RecentsResistanceParams {
FROM_APP(0.75f, 0.5f, 1f, false),
FROM_APP_TABLET(1f, 0.7f, 1f, true),
- FROM_APP_TABLET_GRID_ONLY(1f, 1f, 1f, true),
FROM_OVERVIEW(1f, 0.75f, 0.5f, false);
RecentsResistanceParams(float scaleStartResist, float scaleMaxResist,
@@ -259,9 +257,7 @@
this.translationTarget = translationTarget;
this.translationProperty = translationProperty;
if (dp.isTablet) {
- resistanceParams = enableGridOnlyOverview()
- ? RecentsResistanceParams.FROM_APP_TABLET_GRID_ONLY
- : RecentsResistanceParams.FROM_APP_TABLET;
+ resistanceParams = RecentsResistanceParams.FROM_APP_TABLET;
} else {
resistanceParams = RecentsResistanceParams.FROM_APP;
}
diff --git a/quickstep/src/com/android/quickstep/util/DesktopTask.java b/quickstep/src/com/android/quickstep/util/DesktopTask.java
deleted file mode 100644
index fc4fc4d..0000000
--- a/quickstep/src/com/android/quickstep/util/DesktopTask.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.quickstep.util;
-
-import androidx.annotation.NonNull;
-
-import com.android.quickstep.views.TaskViewType;
-import com.android.systemui.shared.recents.model.Task;
-
-import java.util.List;
-import java.util.Objects;
-
-/**
- * A {@link Task} container that can contain N number of tasks that are part of the desktop in
- * recent tasks list.
- */
-public class DesktopTask extends GroupTask {
-
- @NonNull
- public final List<Task> tasks;
-
- public DesktopTask(@NonNull List<Task> tasks) {
- super(tasks.get(0), null, null, TaskViewType.DESKTOP);
- this.tasks = tasks;
- }
-
- @Override
- public boolean containsTask(int taskId) {
- for (Task task : tasks) {
- if (task.key.id == taskId) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public boolean hasMultipleTasks() {
- return tasks.size() > 1;
- }
-
- @Override
- public boolean supportsMultipleTasks() {
- return true;
- }
-
- @Override
- @NonNull
- public List<Task> getTasks() {
- return tasks;
- }
-
- @Override
- public DesktopTask copy() {
- return new DesktopTask(tasks);
- }
-
- @Override
- public String toString() {
- return "type=" + taskViewType + " tasks=" + tasks;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof DesktopTask that)) return false;
- if (!super.equals(o)) return false;
- return Objects.equals(tasks, that.tasks);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(super.hashCode(), tasks);
- }
-}
diff --git a/quickstep/src/com/android/quickstep/util/DesktopTask.kt b/quickstep/src/com/android/quickstep/util/DesktopTask.kt
new file mode 100644
index 0000000..1cee2d2
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/DesktopTask.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util
+
+import com.android.quickstep.views.TaskViewType
+import com.android.systemui.shared.recents.model.Task
+import java.util.Objects
+
+/**
+ * A [Task] container that can contain N number of tasks that are part of the desktop in recent
+ * tasks list.
+ */
+class DesktopTask(override val tasks: List<Task>) :
+ GroupTask(tasks[0], null, null, TaskViewType.DESKTOP) {
+
+ override fun containsTask(taskId: Int) = tasks.any { it.key.id == taskId }
+
+ override fun hasMultipleTasks() = tasks.size > 1
+
+ override fun supportsMultipleTasks() = true
+
+ override fun copy() = DesktopTask(tasks)
+
+ override fun toString() = "type=$taskViewType tasks=$tasks"
+
+ override fun equals(o: Any?): Boolean {
+ if (this === o) return true
+ if (o !is DesktopTask) return false
+ if (!super.equals(o)) return false
+ return tasks == o.tasks
+ }
+
+ override fun hashCode() = Objects.hash(super.hashCode(), tasks)
+}
diff --git a/quickstep/src/com/android/quickstep/util/GroupTask.java b/quickstep/src/com/android/quickstep/util/GroupTask.java
deleted file mode 100644
index 7aeeb2f..0000000
--- a/quickstep/src/com/android/quickstep/util/GroupTask.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.quickstep.util;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
-import com.android.quickstep.views.TaskViewType;
-import com.android.systemui.shared.recents.model.Task;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * A {@link Task} container that can contain one or two tasks, depending on if the two tasks
- * are represented as an app-pair in the recents task list.
- */
-public class GroupTask {
- @NonNull
- public final Task task1;
- @Nullable
- public final Task task2;
- @Nullable
- public final SplitBounds mSplitBounds;
- public final TaskViewType taskViewType;
-
- public GroupTask(@NonNull Task task) {
- this(task, null, null);
- }
-
- public GroupTask(@NonNull Task t1, @Nullable Task t2, @Nullable SplitBounds splitBounds) {
- this(t1, t2, splitBounds, t2 != null ? TaskViewType.GROUPED : TaskViewType.SINGLE);
- }
-
- protected GroupTask(@NonNull Task t1, @Nullable Task t2, @Nullable SplitBounds splitBounds,
- TaskViewType taskViewType) {
- task1 = t1;
- task2 = t2;
- mSplitBounds = splitBounds;
- this.taskViewType = taskViewType;
- }
-
- public boolean containsTask(int taskId) {
- return task1.key.id == taskId || (task2 != null && task2.key.id == taskId);
- }
-
- public boolean hasMultipleTasks() {
- return task2 != null;
- }
-
- /**
- * Returns whether this task supports multiple tasks or not.
- */
- public boolean supportsMultipleTasks() {
- return taskViewType == TaskViewType.GROUPED;
- }
-
- /**
- * Returns a List of all the Tasks in this GroupTask
- */
- public List<Task> getTasks() {
- if (task2 == null) {
- return Collections.singletonList(task1);
- } else {
- return Arrays.asList(task1, task2);
- }
- }
-
- /**
- * Create a copy of this instance
- */
- public GroupTask copy() {
- return new GroupTask(
- new Task(task1),
- task2 != null ? new Task(task2) : null,
- mSplitBounds);
- }
-
- @Override
- public String toString() {
- return "type=" + taskViewType + " task1=" + task1 + " task2=" + task2;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof GroupTask that)) return false;
- return taskViewType == that.taskViewType && Objects.equals(task1,
- that.task1) && Objects.equals(task2, that.task2)
- && Objects.equals(mSplitBounds, that.mSplitBounds);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(task1, task2, mSplitBounds, taskViewType);
- }
-}
diff --git a/quickstep/src/com/android/quickstep/util/GroupTask.kt b/quickstep/src/com/android/quickstep/util/GroupTask.kt
new file mode 100644
index 0000000..1dd8d18
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/GroupTask.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util
+
+import androidx.annotation.VisibleForTesting
+import com.android.launcher3.util.SplitConfigurationOptions
+import com.android.quickstep.views.TaskViewType
+import com.android.systemui.shared.recents.model.Task
+import java.util.Objects
+
+/**
+ * A [Task] container that can contain one or two tasks, depending on if the two tasks are
+ * represented as an app-pair in the recents task list.
+ */
+open class GroupTask
+@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
+constructor(
+ @JvmField val task1: Task,
+ @JvmField val task2: Task?,
+ @JvmField val mSplitBounds: SplitConfigurationOptions.SplitBounds?,
+ @JvmField val taskViewType: TaskViewType,
+) {
+ constructor(task: Task) : this(task, null, null)
+
+ constructor(
+ t1: Task,
+ t2: Task?,
+ splitBounds: SplitConfigurationOptions.SplitBounds?,
+ ) : this(t1, t2, splitBounds, if (t2 != null) TaskViewType.GROUPED else TaskViewType.SINGLE)
+
+ open fun containsTask(taskId: Int) =
+ task1.key.id == taskId || (task2 != null && task2.key.id == taskId)
+
+ open fun hasMultipleTasks() = task2 != null
+
+ /** Returns whether this task supports multiple tasks or not. */
+ open fun supportsMultipleTasks() = taskViewType == TaskViewType.GROUPED
+
+ /** Returns a List of all the Tasks in this GroupTask */
+ open val tasks: List<Task>
+ get() = listOfNotNull(task1, task2)
+
+ /** Creates a copy of this instance */
+ open fun copy() = GroupTask(Task(task1), if (task2 != null) Task(task2) else null, mSplitBounds)
+
+ override fun toString() = "type=$taskViewType task1=$task1 task2=$task2"
+
+ override fun equals(o: Any?): Boolean {
+ if (this === o) return true
+ if (o !is GroupTask) return false
+ return taskViewType == o.taskViewType &&
+ task1 == o.task1 &&
+ task2 == o.task2 &&
+ mSplitBounds == o.mSplitBounds
+ }
+
+ override fun hashCode() = Objects.hash(task1, task2, mSplitBounds, taskViewType)
+}
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index f708f4b..9b4c772 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -486,11 +486,7 @@
pendingAnimation.addEndListener {
splitSelectStateController.launchInitialAppFullscreen {
- if (FeatureFlags.enableSplitContextually()) {
- splitSelectStateController.resetState()
- } else if (resetCallback.isPresent) {
- resetCallback.get().run()
- }
+ splitSelectStateController.resetState()
}
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 202574b..6b59c1b 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -169,7 +169,7 @@
private final BackPressHandler mSplitBackHandler = new BackPressHandler() {
@Override
public boolean canHandleBack() {
- return FeatureFlags.enableSplitContextually() && isSplitSelectActive();
+ return isSplitSelectActive();
}
@Override
@@ -678,7 +678,7 @@
}
@Override
- public void startAnimation(IBinder transition, TransitionInfo transitionInfo,
+ public void startAnimation(IBinder transition, TransitionInfo info,
SurfaceControl.Transaction t,
IRemoteTransitionFinishedCallback finishedCallback) {
final Runnable finishAdapter = () -> {
@@ -708,7 +708,7 @@
null /* nonApps */,
mStateManager,
mDepthController,
- transitionInfo, t, () -> {
+ info, t, () -> {
finishAdapter.run();
cleanup(true /*success*/);
},
@@ -739,8 +739,7 @@
}
/**
- * To be called whenever we exit split selection state. If
- * {@link FeatureFlags#enableSplitContextually()} is set, this should be the
+ * To be called whenever we exit split selection state. This should be the
* central way split is getting reset, which should then go through the callbacks to reset
* other state.
*/
@@ -920,7 +919,7 @@
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
+ RecentsAnimationTargets targets) {
StatsLogManager.LauncherEvent launcherDesktopSplitEvent =
mSplitPosition == STAGE_POSITION_BOTTOM_OR_RIGHT ?
LAUNCHER_DESKTOP_MODE_SPLIT_RIGHT_BOTTOM :
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
index 86090d5..d3390b4 100644
--- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
@@ -219,6 +219,6 @@
}
private boolean shouldIgnoreSecondSplitLaunch() {
- return !FeatureFlags.enableSplitContextually() || !mController.isSplitSelectActive();
+ return !mController.isSplitSelectActive();
}
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
index 32c4b90..6ba733a 100644
--- a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
@@ -16,7 +16,6 @@
package com.android.quickstep.util;
-import static com.android.launcher3.config.FeatureFlags.enableSplitContextually;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_KEYBOARD_SHORTCUT_SPLIT_LEFT_TOP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_KEYBOARD_SHORTCUT_SPLIT_RIGHT_BOTTOM;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -30,7 +29,6 @@
import android.app.ActivityOptions;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.window.TransitionInfo;
import androidx.annotation.BinderThread;
@@ -74,9 +72,8 @@
@BinderThread
public void enterStageSplit(boolean leftOrTop) {
- if (!enableSplitContextually() ||
- // Do not enter stage split from keyboard shortcuts if the user is already in split
- TopTaskTracker.INSTANCE.get(mLauncher).getRunningSplitTaskIds().length == 2) {
+ if (TopTaskTracker.INSTANCE.get(mLauncher).getRunningSplitTaskIds().length == 2) {
+ // Do not enter stage split from keyboard shortcuts if the user is already in split
return;
}
RecentsAnimationCallbacks callbacks = new RecentsAnimationCallbacks(
@@ -115,7 +112,7 @@
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
+ RecentsAnimationTargets targets) {
mController.setInitialTaskSelect(mRunningTaskInfo,
mLeftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT,
null /* itemInfo */,
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 706cfe4..a1e55fb 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -41,7 +41,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.app.animation.Interpolators;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatedFloat;
@@ -101,8 +100,6 @@
// Carousel properties
public final AnimatedFloat carouselScale = new AnimatedFloat();
- public final AnimatedFloat carouselPrimaryTranslation = new AnimatedFloat();
- public final AnimatedFloat carouselSecondaryTranslation = new AnimatedFloat();
// RecentsView properties
public final AnimatedFloat recentsViewScale = new AnimatedFloat();
@@ -118,7 +115,7 @@
private Boolean mDrawsBelowRecents = null;
private boolean mIsGridTask;
private final boolean mIsDesktopTask;
- private boolean mScaleToCarouselTaskSize = false;
+ private boolean mIsAnimatingToCarousel = false;
private int mTaskRectTranslationX;
private int mTaskRectTranslationY;
private int mDesktopTaskIndex = 0;
@@ -149,6 +146,9 @@
mDp = dp;
mLayoutValid = false;
mOrientationState.setDeviceProfile(dp);
+ if (enableGridOnlyOverview()) {
+ mIsGridTask = dp.isTablet && !mIsDesktopTask;
+ }
calculateTaskSize();
}
@@ -160,14 +160,16 @@
if (mIsGridTask) {
mSizeStrategy.calculateGridTaskSize(mContext, mDp, mFullTaskSize,
mOrientationState.getOrientationHandler());
+ if (enableGridOnlyOverview()) {
+ mSizeStrategy.calculateTaskSize(mContext, mDp, mCarouselTaskSize,
+ mOrientationState.getOrientationHandler());
+ }
} else {
mSizeStrategy.calculateTaskSize(mContext, mDp, mFullTaskSize,
mOrientationState.getOrientationHandler());
- }
-
- if (enableGridOnlyOverview()) {
- mSizeStrategy.calculateCarouselTaskSize(mContext, mDp, mCarouselTaskSize,
- mOrientationState.getOrientationHandler());
+ if (enableGridOnlyOverview()) {
+ mCarouselTaskSize.set(mFullTaskSize);
+ }
}
if (mSplitBounds != null) {
@@ -222,12 +224,7 @@
}
// Copy mFullTaskSize instead of updating it directly so it could be reused next time
// without recalculating
- Rect scaleRect = new Rect();
- if (mScaleToCarouselTaskSize) {
- scaleRect.set(mCarouselTaskSize);
- } else {
- scaleRect.set(mFullTaskSize);
- }
+ Rect scaleRect = new Rect(mIsAnimatingToCarousel ? mCarouselTaskSize : mFullTaskSize);
scaleRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
float scale = mOrientationState.getFullScreenScaleAndPivot(scaleRect, mDp, mPivot);
if (mPivotOverride != null) {
@@ -313,66 +310,16 @@
}
/**
- * Adds animation for all the components corresponding to transition from an app to overview.
+ * Adds animation for all the components corresponding to transition from an app to carousel.
*/
- public void addAppToOverviewAnim(PendingAnimation pa, Interpolator interpolator) {
+ public void addAppToCarouselAnim(PendingAnimation pa, Interpolator interpolator) {
pa.addFloat(fullScreenProgress, AnimatedFloat.VALUE, 1, 0, interpolator);
- float fullScreenScale;
if (enableGridOnlyOverview() && mDp.isTablet && mDp.isGestureMode) {
- // Move pivot to top right edge of the screen, to avoid task scaling down in opposite
- // direction of app window movement, otherwise the animation will wiggle left and right.
- // Also translate the app window to top right edge of the screen to simplify
- // calculations.
- taskPrimaryTranslation.value = mIsRecentsRtl
- ? mDp.widthPx - mFullTaskSize.right
- : -mFullTaskSize.left;
- taskSecondaryTranslation.value = -mFullTaskSize.top;
- mPivotOverride = new PointF(mIsRecentsRtl ? mDp.widthPx : 0, 0);
-
- // Scale down to the carousel and use the carousel Rect to calculate fullScreenScale.
- mScaleToCarouselTaskSize = true;
+ mIsAnimatingToCarousel = true;
carouselScale.value = mCarouselTaskSize.width() / (float) mFullTaskSize.width();
- fullScreenScale = getFullScreenScale();
-
- float carouselPrimaryTranslationTarget = mIsRecentsRtl
- ? mCarouselTaskSize.right - mDp.widthPx
- : mCarouselTaskSize.left;
- float carouselSecondaryTranslationTarget = mCarouselTaskSize.top;
-
- // Expected carousel position's center is in the middle, and invariant of
- // recentsViewScale.
- float exceptedCarouselCenterX = mCarouselTaskSize.centerX();
- // Animating carousel translations linearly will result in a curved path, therefore
- // we'll need to calculate the expected translation at each recentsView scale. Luckily
- // primary and secondary follow the same translation, and primary is used here due to
- // it being simpler.
- Interpolator carouselTranslationInterpolator = t -> {
- // recentsViewScale is calculated rather than using recentsViewScale.value, so that
- // this interpolator works independently even if recentsViewScale don't animate.
- float recentsViewScale =
- Utilities.mapToRange(t, 0, 1, fullScreenScale, 1, Interpolators.LINEAR);
- // Without the translation, the app window will animate from fullscreen into top
- // right corner.
- float expectedTaskCenterX = mIsRecentsRtl
- ? mDp.widthPx - mCarouselTaskSize.width() * recentsViewScale / 2f
- : mCarouselTaskSize.width() * recentsViewScale / 2f;
- // Calculate the expected translation, then work back the animatedFraction that
- // results in this value.
- float carouselPrimaryTranslation =
- (exceptedCarouselCenterX - expectedTaskCenterX) / recentsViewScale;
- return carouselPrimaryTranslation / carouselPrimaryTranslationTarget;
- };
-
- // Use addAnimatedFloat so this animation can later be canceled and animate to a
- // different value in RecentsView.onPrepareGestureEndAnimation.
- pa.addAnimatedFloat(carouselPrimaryTranslation, 0, carouselPrimaryTranslationTarget,
- carouselTranslationInterpolator);
- pa.addAnimatedFloat(carouselSecondaryTranslation, 0, carouselSecondaryTranslationTarget,
- carouselTranslationInterpolator);
- } else {
- fullScreenScale = getFullScreenScale();
}
- pa.addFloat(recentsViewScale, AnimatedFloat.VALUE, fullScreenScale, 1, interpolator);
+ pa.addFloat(recentsViewScale, AnimatedFloat.VALUE, getFullScreenScale(), 1,
+ interpolator);
}
/**
@@ -484,11 +431,9 @@
mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
taskSecondaryTranslation.value);
- mMatrix.postScale(carouselScale.value, carouselScale.value, mPivot.x, mPivot.y);
- mOrientationState.getOrientationHandler().setPrimary(mMatrix, MATRIX_POST_TRANSLATE,
- carouselPrimaryTranslation.value);
- mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
- carouselSecondaryTranslation.value);
+ mMatrix.postScale(carouselScale.value, carouselScale.value,
+ mIsRecentsRtl ? mCarouselTaskSize.right : mCarouselTaskSize.left,
+ mCarouselTaskSize.top);
mOrientationState.getOrientationHandler().setPrimary(
mMatrix, MATRIX_POST_TRANSLATE, recentsViewScroll.value);
@@ -524,8 +469,6 @@
+ " taskRect: " + mTaskRect
+ " taskPrimaryT: " + taskPrimaryTranslation.value
+ " taskSecondaryT: " + taskSecondaryTranslation.value
- + " carouselPrimaryT: " + carouselPrimaryTranslation.value
- + " carouselSecondaryT: " + carouselSecondaryTranslation.value
+ " recentsPrimaryT: " + recentsViewPrimaryTranslation.value
+ " recentsSecondaryT: " + recentsViewSecondaryTranslation.value
+ " recentsScroll: " + recentsViewScroll.value
diff --git a/quickstep/src/com/android/quickstep/util/TransformParams.java b/quickstep/src/com/android/quickstep/util/TransformParams.java
index bb88818..401eccc 100644
--- a/quickstep/src/com/android/quickstep/util/TransformParams.java
+++ b/quickstep/src/com/android/quickstep/util/TransformParams.java
@@ -19,12 +19,9 @@
import android.util.FloatProperty;
import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl;
-import android.window.TransitionInfo;
import com.android.quickstep.RemoteAnimationTargets;
import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
-import com.android.window.flags.Flags;
public class TransformParams {
@@ -59,7 +56,6 @@
private float mTargetAlpha;
private float mCornerRadius;
private RemoteAnimationTargets mTargetSet;
- private TransitionInfo mTransitionInfo;
private SurfaceTransactionApplier mSyncTransactionApplier;
private BuilderProxy mHomeBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
@@ -111,14 +107,6 @@
}
/**
- * Provides the {@code TransitionInfo} of the transition that this transformation stems from.
- */
- public TransformParams setTransitionInfo(TransitionInfo transitionInfo) {
- mTransitionInfo = transitionInfo;
- return this;
- }
-
- /**
* Sets the SyncRtSurfaceTransactionApplierCompat that will apply the SurfaceParams that
* are computed based on these TransformParams.
*/
@@ -164,9 +152,6 @@
builder.setAlpha(getTargetAlpha());
}
targetProxy.onBuildTargetParams(builder, app, this);
- // Override the corner radius for {@code app} with the leash used by Shell, so that it
- // doesn't interfere with the window clip and corner radius applied here.
- overrideChangeLeashCornerRadiusToZero(app, transaction.getTransaction());
}
// always put wallpaper layer to bottom.
@@ -178,28 +163,6 @@
return transaction;
}
- private void overrideChangeLeashCornerRadiusToZero(
- RemoteAnimationTarget app, SurfaceControl.Transaction transaction) {
- if (!Flags.enableDesktopRecentsTransitionsCornersBugfix()) {
- return;
- }
- SurfaceControl changeLeash = getChangeLeashForApp(app);
- if (changeLeash != null) {
- transaction.setCornerRadius(changeLeash, 0);
- }
- }
-
- private SurfaceControl getChangeLeashForApp(RemoteAnimationTarget app) {
- if (mTransitionInfo == null) return null;
- for (TransitionInfo.Change change : mTransitionInfo.getChanges()) {
- if (change.getTaskInfo() == null) continue;
- if (change.getTaskInfo().taskId == app.taskId) {
- return change.getLeash();
- }
- }
- return null;
- }
-
// Pubic getters so outside packages can read the values.
public float getProgress() {
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index c3efc3c..72f97df 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -16,7 +16,6 @@
package com.android.quickstep.views;
-import static com.android.launcher3.Flags.enableGridOnlyOverview;
import static com.android.quickstep.util.BorderAnimator.DEFAULT_BORDER_COLOR;
import android.content.Context;
@@ -331,13 +330,7 @@
private float getOriginalTranslationY() {
DeviceProfile deviceProfile = mContainer.getDeviceProfile();
if (deviceProfile.isTablet) {
- if (enableGridOnlyOverview()) {
- return (getRecentsView().getLastComputedTaskSize().height()
- + deviceProfile.overviewTaskThumbnailTopMarginPx) / 2.0f
- + deviceProfile.overviewRowSpacing;
- } else {
- return deviceProfile.overviewRowSpacing;
- }
+ return deviceProfile.overviewRowSpacing;
}
return deviceProfile.overviewTaskThumbnailTopMarginPx / 2.0f;
}
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
index 7d04451..471313a 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
@@ -174,16 +174,8 @@
}
@SuppressLint("RtlHardcoded")
- override fun updateTaskSize(
- lastComputedTaskSize: Rect,
- lastComputedGridTaskSize: Rect,
- lastComputedCarouselTaskSize: Rect,
- ) {
- super.updateTaskSize(
- lastComputedTaskSize,
- lastComputedGridTaskSize,
- lastComputedCarouselTaskSize,
- )
+ override fun updateTaskSize(lastComputedTaskSize: Rect, lastComputedGridTaskSize: Rect) {
+ super.updateTaskSize(lastComputedTaskSize, lastComputedGridTaskSize)
if (taskContainers.isEmpty()) {
return
}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index d6fe049..9be462c 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -255,11 +255,7 @@
@Override
public boolean canLaunchFullscreenTask() {
- if (FeatureFlags.enableSplitContextually()) {
- return !mSplitSelectStateController.isSplitSelectActive();
- } else {
- return !mContainer.isInState(OVERVIEW_SPLIT_SELECT);
- }
+ return !mSplitSelectStateController.isSplitSelectActive();
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 9a4933a..e621d0c 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -209,7 +209,6 @@
import com.android.quickstep.recents.viewmodel.RecentsViewModel;
import com.android.quickstep.util.ActiveGestureProtoLogProxy;
import com.android.quickstep.util.AnimUtils;
-import com.android.quickstep.util.DesktopTask;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RecentsAtomicAnimationFactory;
@@ -521,7 +520,6 @@
@Nullable
protected RemoteTargetHandle[] mRemoteTargetHandles;
- protected final Rect mLastComputedCarouselTaskSize = new Rect();
protected final Rect mLastComputedTaskSize = new Rect();
protected final Rect mLastComputedGridSize = new Rect();
protected final Rect mLastComputedGridTaskSize = new Rect();
@@ -551,6 +549,8 @@
private final ClearAllButton mClearAllButton;
private final Rect mClearAllButtonDeadZoneRect = new Rect();
private final Rect mTaskViewDeadZoneRect = new Rect();
+ private final Rect mTopRowDeadZoneRect = new Rect();
+ private final Rect mBottomRowDeadZoneRect = new Rect();
/**
* Reflects if Recents is currently in the middle of a gesture, and if so, which tasks are
* running. If a gesture is not in progress, this will be null.
@@ -1217,9 +1217,7 @@
mIPipAnimationListener);
mOrientationState.initListeners();
mTaskOverlayFactory.initListeners();
- if (FeatureFlags.enableSplitContextually()) {
- mSplitSelectStateController.registerSplitListener(mSplitSelectionListener);
- }
+ mSplitSelectStateController.registerSplitListener(mSplitSelectionListener);
}
@Override
@@ -1239,9 +1237,7 @@
mIPipAnimationListener.setActivityAndRecentsView(null, null);
mOrientationState.destroyListeners();
mTaskOverlayFactory.removeListeners();
- if (FeatureFlags.enableSplitContextually()) {
- mSplitSelectStateController.unregisterSplitListener(mSplitSelectionListener);
- }
+ mSplitSelectStateController.unregisterSplitListener(mSplitSelectionListener);
reset();
}
@@ -1722,8 +1718,11 @@
mClearAllButton.getAlpha() == 1
&& mClearAllButtonDeadZoneRect.contains(x, y);
final boolean cameFromNavBar = (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0;
+ int adjustedX = x + getScrollX();
if (!clearAllButtonDeadZoneConsumed && !cameFromNavBar
- && !mTaskViewDeadZoneRect.contains(x + getScrollX(), y)) {
+ && !mTaskViewDeadZoneRect.contains(adjustedX, y)
+ && !mTopRowDeadZoneRect.contains(adjustedX, y)
+ && !mBottomRowDeadZoneRect.contains(adjustedX, y)) {
mTouchDownToStartHome = true;
}
}
@@ -1971,7 +1970,7 @@
} else if (taskView instanceof DesktopTaskView) {
// Minimized tasks should not be shown in Overview
List<Task> nonMinimizedTasks =
- ((DesktopTask) groupTask).tasks.stream()
+ groupTask.getTasks().stream()
.filter(task -> !task.isMinimized)
.toList();
((DesktopTaskView) taskView).bind(nonMinimizedTasks, mOrientationState,
@@ -2101,7 +2100,7 @@
/** Returns true if there are at least one TaskView has been added to the RecentsView. */
public boolean hasTaskViews() {
- return CollectionsKt.any(getTaskViews());
+ return mUtils.hasTaskViews();
}
public int getTaskViewCount() {
@@ -2292,11 +2291,6 @@
mSizeStrategy.calculateGridTaskSize(mContainer, dp, mLastComputedGridTaskSize,
getPagedOrientationHandler());
- if (enableGridOnlyOverview()) {
- mSizeStrategy.calculateCarouselTaskSize(mContainer, dp, mLastComputedCarouselTaskSize,
- getPagedOrientationHandler());
- }
-
mTaskGridVerticalDiff = mLastComputedGridTaskSize.top - mLastComputedTaskSize.top;
mTopBottomRowHeightDiff =
mLastComputedGridTaskSize.height() + dp.overviewTaskThumbnailTopMarginPx
@@ -2316,17 +2310,9 @@
}
float accumulatedTranslationX = 0;
- float translateXToMiddle = 0;
- if (enableGridOnlyOverview() && mContainer.getDeviceProfile().isTablet) {
- translateXToMiddle = mIsRtl
- ? mLastComputedCarouselTaskSize.right - mLastComputedTaskSize.right
- : mLastComputedCarouselTaskSize.left - mLastComputedTaskSize.left;
- }
for (TaskView taskView : getTaskViews()) {
- taskView.updateTaskSize(mLastComputedTaskSize, mLastComputedGridTaskSize,
- mLastComputedCarouselTaskSize);
+ taskView.updateTaskSize(mLastComputedTaskSize, mLastComputedGridTaskSize);
taskView.setNonGridTranslationX(accumulatedTranslationX);
- taskView.setNonGridPivotTranslationX(translateXToMiddle);
// Compensate space caused by TaskView scaling.
float widthDiff =
taskView.getLayoutParams().width * (1 - taskView.getNonGridScale());
@@ -2355,7 +2341,8 @@
*/
public Rect getSelectedTaskBounds() {
if (mSelectedTask == null) {
- return mLastComputedTaskSize;
+ return enableGridOnlyOverview() && mContainer.getDeviceProfile().isTablet
+ ? mLastComputedGridTaskSize : mLastComputedTaskSize;
}
return getTaskBounds(mSelectedTask);
}
@@ -2364,8 +2351,9 @@
int selectedPage = indexOfChild(taskView);
int primaryScroll = getPagedOrientationHandler().getPrimaryScroll(this);
int selectedPageScroll = getScrollForPage(selectedPage);
- boolean isTopRow = taskView != null && mTopRowIdSet.contains(taskView.getTaskViewId());
- Rect outRect = new Rect(mLastComputedTaskSize);
+ boolean isTopRow = mTopRowIdSet.contains(taskView.getTaskViewId());
+ Rect outRect = new Rect(
+ taskView.isGridTask() ? mLastComputedGridTaskSize : mLastComputedTaskSize);
outRect.offset(
-(primaryScroll - (selectedPageScroll + getOffsetFromScrollPosition(selectedPage))),
(int) (showAsGrid() && enableGridOnlyOverview() && !isTopRow
@@ -2382,10 +2370,6 @@
return mLastComputedGridTaskSize;
}
- public Rect getLastComputedCarouselTaskSize() {
- return mLastComputedCarouselTaskSize;
- }
-
/** Gets the task size for modal state. */
public void getModalTaskSize(Rect outRect) {
mSizeStrategy.calculateModalTaskSize(mContainer, mContainer.getDeviceProfile(), outRect,
@@ -2663,9 +2647,6 @@
}
runActionOnRemoteHandles(remoteTargetHandle ->
remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false));
- if (!FeatureFlags.enableSplitContextually()) {
- resetFromSplitSelectionState();
- }
// These are relatively expensive and don't need to be done this frame (RecentsView isn't
// visible anyway), so defer by a frame to get off the critical path, e.g. app to home.
@@ -2712,7 +2693,7 @@
}
@Nullable
- private TaskView getTaskViewFromTaskViewId(int taskViewId) {
+ TaskView getTaskViewFromTaskViewId(int taskViewId) {
if (taskViewId == -1) {
return null;
}
@@ -2912,8 +2893,6 @@
} else {
animatorSet.play(ObjectAnimator.ofFloat(this, RECENTS_GRID_PROGRESS, 1));
animatorSet.play(tvs.carouselScale.animateToValue(1));
- animatorSet.play(tvs.carouselPrimaryTranslation.animateToValue(0));
- animatorSet.play(tvs.carouselSecondaryTranslation.animateToValue(0));
animatorSet.play(tvs.taskPrimaryTranslation.animateToValue(
runningTaskPrimaryGridTranslation));
animatorSet.play(tvs.taskSecondaryTranslation.animateToValue(
@@ -3640,11 +3619,7 @@
InteractionJankMonitorWrapper.end(Cuj.CUJ_SPLIT_SCREEN_ENTER);
} else {
// If transition to split select was interrupted, clean up to prevent glitches
- if (FeatureFlags.enableSplitContextually()) {
- mSplitSelectStateController.resetState();
- } else {
- resetFromSplitSelectionState();
- }
+ mSplitSelectStateController.resetState();
InteractionJankMonitorWrapper.cancel(Cuj.CUJ_SPLIT_SCREEN_ENTER);
}
@@ -4240,6 +4215,12 @@
onDismissAnimationEnds();
mPendingAnimation = null;
mTaskViewsDismissPrimaryTranslations.clear();
+
+ if (!dismissingForSplitSelection && success) {
+ InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_OVERVIEW_TASK_DISMISS);
+ } else if (!dismissingForSplitSelection) {
+ InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_OVERVIEW_TASK_DISMISS);
+ }
}
});
}
@@ -4365,7 +4346,7 @@
/**
* Returns all the tasks in the top row, without the focused task
*/
- private IntArray getTopRowIdArray() {
+ IntArray getTopRowIdArray() {
if (mTopRowIdSet.isEmpty()) {
return new IntArray(0);
}
@@ -4382,7 +4363,7 @@
/**
* Returns all the tasks in the bottom row, without the focused task
*/
- private IntArray getBottomRowIdArray() {
+ IntArray getBottomRowIdArray() {
int bottomRowIdArraySize = getBottomRowTaskCountForTablet();
if (bottomRowIdArraySize <= 0) {
return new IntArray(0);
@@ -4543,6 +4524,7 @@
}
public void dismissTask(TaskView taskView, boolean animateTaskView, boolean removeTask) {
+ InteractionJankMonitorWrapper.begin(this, Cuj.CUJ_LAUNCHER_OVERVIEW_TASK_DISMISS);
PendingAnimation pa = new PendingAnimation(DISMISS_TASK_DURATION);
createTaskDismissAnimation(pa, taskView, animateTaskView, removeTask, DISMISS_TASK_DURATION,
false /* dismissingForSplitSelection*/);
@@ -4809,14 +4791,7 @@
mTempPointF.set(mLastComputedTaskSize.centerX(), mLastComputedTaskSize.bottom);
}
} else {
- // Only update pivot when it is tablet and not in grid yet, so the pivot is correct
- // for non-current tasks when swiping up to overview
- if (enableGridOnlyOverview() && mContainer.getDeviceProfile().isTablet
- && !mOverviewGridEnabled) {
- mTempRect.set(mLastComputedCarouselTaskSize);
- } else {
- mTempRect.set(mLastComputedTaskSize);
- }
+ mTempRect.set(mLastComputedTaskSize);
getPagedViewOrientedState().getFullScreenScaleAndPivot(mTempRect,
mContainer.getDeviceProfile(), mTempPointF);
}
@@ -4927,10 +4902,12 @@
&& child instanceof DesktopTaskView;
float totalTranslationX = (skipTranslationOffset ? 0f : translation) + modalTranslation
+ carouselHiddenOffsetSize;
- FloatProperty translationPropertyX = child instanceof TaskView
- ? ((TaskView) child).getPrimaryTaskOffsetTranslationProperty()
- : getPagedOrientationHandler().getPrimaryViewTranslate();
- translationPropertyX.set(child, totalTranslationX);
+ if (child instanceof TaskView taskView) {
+ taskView.getPrimaryTaskOffsetTranslationProperty().set(taskView, totalTranslationX);
+ } else {
+ getPagedOrientationHandler().getPrimaryViewTranslate().set(child,
+ totalTranslationX);
+ }
if (mEnableDrawingLiveTile && i == getRunningTaskIndex()) {
runActionOnRemoteHandles(
remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator()
@@ -4938,11 +4915,11 @@
redrawLiveTile();
}
- if (showAsGrid && enableGridOnlyOverview() && child instanceof TaskView) {
- float totalTranslationY = getVerticalOffsetSize(i, modalOffset);
- FloatProperty translationPropertyY =
- ((TaskView) child).getSecondaryTaskOffsetTranslationProperty();
- translationPropertyY.set(child, totalTranslationY);
+ if (showAsGrid && enableGridOnlyOverview() && child instanceof TaskView taskView) {
+ float totalTranslationY = getVerticalOffsetSize(taskView, modalOffset);
+ FloatProperty<TaskView> translationPropertyY =
+ taskView.getSecondaryTaskOffsetTranslationProperty();
+ translationPropertyY.set(taskView, totalTranslationY);
}
}
updateCurveProperties();
@@ -5058,7 +5035,7 @@
*
* @param offsetProgress From 0 to 1 where 0 means no offset and 1 means offset offscreen.
*/
- private float getVerticalOffsetSize(int childIndex, float offsetProgress) {
+ private float getVerticalOffsetSize(TaskView taskView, float offsetProgress) {
if (offsetProgress == 0 || !(showAsGrid() && enableGridOnlyOverview())
|| mSelectedTask == null) {
// Don't bother calculating everything below if we won't offset vertically.
@@ -5066,11 +5043,10 @@
}
// First, get the position of the task relative to the top row.
- TaskView child = getTaskViewAt(childIndex);
- Rect taskPosition = getTaskBounds(child);
+ Rect taskPosition = getTaskBounds(taskView);
boolean isSelectedTaskTopRow = mTopRowIdSet.contains(mSelectedTask.getTaskViewId());
- boolean isChildTopRow = mTopRowIdSet.contains(child.getTaskViewId());
+ boolean isChildTopRow = mTopRowIdSet.contains(taskView.getTaskViewId());
// Whether the task should be shifted to the top.
boolean isTopShift = !isSelectedTaskTopRow && isChildTopRow;
boolean isBottomShift = isSelectedTaskTopRow && !isChildTopRow;
@@ -5368,11 +5344,7 @@
mSplitSelectStateController.launchSplitTasks(
aBoolean1 -> {
InteractionJankMonitorWrapper.end(Cuj.CUJ_SPLIT_SCREEN_ENTER);
- if (FeatureFlags.enableSplitContextually()) {
- mSplitSelectStateController.resetState();
- } else {
- resetFromSplitSelectionState();
- }
+ mSplitSelectStateController.resetState();
});
});
@@ -5394,17 +5366,14 @@
@SuppressLint("WrongCall")
protected void resetFromSplitSelectionState() {
- if (mSplitSelectSource != null || mSplitHiddenTaskViewIndex != -1 ||
- FeatureFlags.enableSplitContextually()) {
- safeRemoveDragLayerView(mSplitSelectStateController.getFirstFloatingTaskView());
- safeRemoveDragLayerView(mSecondFloatingTaskView);
- safeRemoveDragLayerView(mSplitSelectStateController.getSplitInstructionsView());
- safeRemoveDragLayerView(mSplitScrim);
- mSecondFloatingTaskView = null;
- mSplitSelectSource = null;
- mSplitSelectStateController.getSplitAnimationController()
- .removeSplitInstructionsView(mContainer);
- }
+ safeRemoveDragLayerView(mSplitSelectStateController.getFirstFloatingTaskView());
+ safeRemoveDragLayerView(mSecondFloatingTaskView);
+ safeRemoveDragLayerView(mSplitSelectStateController.getSplitInstructionsView());
+ safeRemoveDragLayerView(mSplitScrim);
+ mSecondFloatingTaskView = null;
+ mSplitSelectSource = null;
+ mSplitSelectStateController.getSplitAnimationController()
+ .removeSplitInstructionsView(mContainer);
if (mSecondSplitHiddenView != null) {
mSecondSplitHiddenView.setThumbnailVisibility(VISIBLE, INVALID_TASK_ID);
@@ -5416,11 +5385,6 @@
setTaskViewsPrimarySplitTranslation(0);
setTaskViewsSecondarySplitTranslation(0);
- if (!FeatureFlags.enableSplitContextually()) {
- // When flag is on, this method gets called from resetState() call below, let's avoid
- // infinite recursion today
- mSplitSelectStateController.resetState();
- }
if (mSplitHiddenTaskViewIndex == -1) {
return;
}
@@ -5519,15 +5483,8 @@
mClearAllButtonDeadZoneRect.inset(-getPaddingRight() / 2, -verticalMargin);
}
- // Get the deadzone rect between the task views
- mTaskViewDeadZoneRect.setEmpty();
- if (hasTaskViews()) {
- final View firstTaskView = getFirstTaskView();
- mUtils.getLastTaskView().getHitRect(mTaskViewDeadZoneRect);
- mTaskViewDeadZoneRect.union(firstTaskView.getLeft(), firstTaskView.getTop(),
- firstTaskView.getRight(),
- firstTaskView.getBottom());
- }
+ mUtils.updateTaskViewDeadZoneRect(mTaskViewDeadZoneRect, mTopRowDeadZoneRect,
+ mBottomRowDeadZoneRect);
}
private void updateEmptyStateUi(boolean sizeChanged) {
@@ -5667,19 +5624,10 @@
* Returns the scale up required on the view, so that it coves the screen completely
*/
public float getMaxScaleForFullScreen() {
- if (enableGridOnlyOverview() && mContainer.getDeviceProfile().isTablet
- && !mOverviewGridEnabled) {
- if (mLastComputedCarouselTaskSize.isEmpty()) {
- mSizeStrategy.calculateCarouselTaskSize(mContainer, mContainer.getDeviceProfile(),
- mLastComputedCarouselTaskSize, getPagedOrientationHandler());
- }
- mTempRect.set(mLastComputedCarouselTaskSize);
- } else {
- if (mLastComputedTaskSize.isEmpty()) {
- getTaskSize(mLastComputedTaskSize);
- }
- mTempRect.set(mLastComputedTaskSize);
+ if (mLastComputedTaskSize.isEmpty()) {
+ getTaskSize(mLastComputedTaskSize);
}
+ mTempRect.set(mLastComputedTaskSize);
return getPagedViewOrientedState().getFullScreenScaleAndPivot(
mTempRect, mContainer.getDeviceProfile(), mTempPointF);
}
@@ -5870,8 +5818,7 @@
if (recentsAnimationTargets.hasDesktopTasks(mContext)) {
gluer = new RemoteTargetGluer(getContext(), getSizeStrategy(), recentsAnimationTargets,
true /* forDesktop */);
- mRemoteTargetHandles = gluer.assignTargetsForDesktop(
- recentsAnimationTargets, /* transitionInfo= */ null);
+ mRemoteTargetHandles = gluer.assignTargetsForDesktop(recentsAnimationTargets);
} else {
gluer = new RemoteTargetGluer(getContext(), getSizeStrategy(), recentsAnimationTargets,
false);
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt
index 3ac3349..dcb954a 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt
@@ -16,9 +16,11 @@
package com.android.quickstep.views
+import android.graphics.Rect
import android.view.View
import androidx.core.view.children
import com.android.launcher3.Flags.enableLargeDesktopWindowingTile
+import com.android.launcher3.util.IntArray
import com.android.quickstep.util.GroupTask
import com.android.quickstep.views.RecentsView.RUNNING_TASK_ATTACH_ALPHA
import com.android.systemui.shared.recents.model.ThumbnailData
@@ -169,4 +171,78 @@
FULL_SCREEN,
DESKTOP,
}
+
+ /** Returns true if there are at least one TaskView has been added to the RecentsView. */
+ fun hasTaskViews() = taskViews.any()
+
+ private fun getRowRect(firstView: View?, lastView: View?, outRowRect: Rect) {
+ outRowRect.setEmpty()
+ firstView?.let {
+ it.getHitRect(TEMP_RECT)
+ outRowRect.union(TEMP_RECT)
+ }
+ lastView?.let {
+ it.getHitRect(TEMP_RECT)
+ outRowRect.union(TEMP_RECT)
+ }
+ }
+
+ private fun getRowRect(rowTaskViewIds: IntArray, outRowRect: Rect) {
+ if (rowTaskViewIds.isEmpty) {
+ outRowRect.setEmpty()
+ return
+ }
+ getRowRect(
+ recentsView.getTaskViewFromTaskViewId(rowTaskViewIds.get(0)),
+ recentsView.getTaskViewFromTaskViewId(rowTaskViewIds.get(rowTaskViewIds.size() - 1)),
+ outRowRect,
+ )
+ }
+
+ fun updateTaskViewDeadZoneRect(
+ outTaskViewRowRect: Rect,
+ outTopRowRect: Rect,
+ outBottomRowRect: Rect,
+ ) {
+ if (!(recentsView.mContainer as RecentsViewContainer).deviceProfile.isTablet) {
+ getRowRect(getFirstTaskView(), getLastTaskView(), outTaskViewRowRect)
+ return
+ }
+ getRowRect(getFirstLargeTaskView(), getLastLargeTaskView(), outTaskViewRowRect)
+ getRowRect(recentsView.getTopRowIdArray(), outTopRowRect)
+ getRowRect(recentsView.getBottomRowIdArray(), outBottomRowRect)
+
+ // Expand large tile Rect to include space between top/bottom row.
+ val nonEmptyRowRect =
+ when {
+ !outTopRowRect.isEmpty -> outTopRowRect
+ !outBottomRowRect.isEmpty -> outBottomRowRect
+ else -> return
+ }
+ if (recentsView.isRtl) {
+ if (outTaskViewRowRect.left > nonEmptyRowRect.right) {
+ outTaskViewRowRect.left = nonEmptyRowRect.right
+ }
+ } else {
+ if (outTaskViewRowRect.right < nonEmptyRowRect.left) {
+ outTaskViewRowRect.right = nonEmptyRowRect.left
+ }
+ }
+
+ // Expand the shorter row Rect to include the space between the 2 rows.
+ if (outTopRowRect.isEmpty || outBottomRowRect.isEmpty) return
+ if (outTopRowRect.width() <= outBottomRowRect.width()) {
+ if (outTopRowRect.bottom < outBottomRowRect.top) {
+ outTopRowRect.bottom = outBottomRowRect.top
+ }
+ } else {
+ if (outBottomRowRect.top > outTopRowRect.bottom) {
+ outBottomRowRect.top = outTopRowRect.bottom
+ }
+ }
+ }
+
+ companion object {
+ val TEMP_RECT = Rect()
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
index f6393e4..0d80f6a 100644
--- a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
+++ b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
@@ -126,33 +126,31 @@
TextView cancelTextView = findViewById(R.id.split_instructions_text_cancel);
TextView instructionTextView = findViewById(R.id.split_instructions_text);
- if (FeatureFlags.enableSplitContextually()) {
- cancelTextView.setVisibility(VISIBLE);
- cancelTextView.setOnClickListener((v) -> exitSplitSelection());
- instructionTextView.setText(R.string.toast_contextual_split_select_app);
+ cancelTextView.setVisibility(VISIBLE);
+ cancelTextView.setOnClickListener((v) -> exitSplitSelection());
+ instructionTextView.setText(R.string.toast_contextual_split_select_app);
- // After layout, expand touch target of cancel button to meet minimum a11y measurements.
- post(() -> {
- int minTouchSize = getResources()
- .getDimensionPixelSize(settingslib_preferred_minimum_touch_target);
- Rect r = new Rect();
- cancelTextView.getHitRect(r);
+ // After layout, expand touch target of cancel button to meet minimum a11y measurements.
+ post(() -> {
+ int minTouchSize = getResources()
+ .getDimensionPixelSize(settingslib_preferred_minimum_touch_target);
+ Rect r = new Rect();
+ cancelTextView.getHitRect(r);
- if (r.width() < minTouchSize) {
- // add 1 to ensure ceiling on int division
- int expandAmount = (minTouchSize + 1 - r.width()) / 2;
- r.left -= expandAmount;
- r.right += expandAmount;
- }
- if (r.height() < minTouchSize) {
- int expandAmount = (minTouchSize + 1 - r.height()) / 2;
- r.top -= expandAmount;
- r.bottom += expandAmount;
- }
+ if (r.width() < minTouchSize) {
+ // add 1 to ensure ceiling on int division
+ int expandAmount = (minTouchSize + 1 - r.width()) / 2;
+ r.left -= expandAmount;
+ r.right += expandAmount;
+ }
+ if (r.height() < minTouchSize) {
+ int expandAmount = (minTouchSize + 1 - r.height()) / 2;
+ r.top -= expandAmount;
+ r.bottom += expandAmount;
+ }
- setTouchDelegate(new TouchDelegate(r, cancelTextView));
- });
- }
+ setTouchDelegate(new TouchDelegate(r, cancelTextView));
+ });
// Set accessibility title, will be announced by a11y tools.
instructionTextView.setAccessibilityPaneTitle(instructionTextView.getText());
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailViewHeader.kt b/quickstep/src/com/android/quickstep/views/TaskThumbnailViewHeader.kt
new file mode 100644
index 0000000..9eb294a
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailViewHeader.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.views
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.FrameLayout
+import android.widget.ImageView
+import android.widget.TextView
+import com.android.launcher3.R
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.ThumbnailHeader
+
+class TaskThumbnailViewHeader
+@JvmOverloads
+constructor(context: Context, attrs: AttributeSet? = null) : FrameLayout(context, attrs) {
+
+ private val headerTitleView: TextView by lazy { findViewById(R.id.header_app_title) }
+ private val headerIconView: ImageView by lazy { findViewById(R.id.header_app_icon) }
+
+ fun setHeader(header: ThumbnailHeader) {
+ headerTitleView.setText(header.title)
+ headerIconView.setImageDrawable(header.icon)
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 5b99286..dc849f3 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -165,10 +165,7 @@
* Returns addition of translationX that is persistent (e.g. fullscreen and grid), and does
* not change according to a temporary state (e.g. task offset).
*/
- get() =
- (getNonGridTrans(nonGridTranslationX) +
- getGridTrans(this.gridTranslationX) +
- getNonGridTrans(nonGridPivotTranslationX))
+ get() = (getNonGridTrans(nonGridTranslationX) + getGridTrans(this.gridTranslationX))
protected val persistentTranslationY: Float
/**
@@ -352,12 +349,6 @@
applyTranslationX()
}
- protected var nonGridPivotTranslationX = 0f
- set(value) {
- field = value
- applyTranslationX()
- }
-
// Used when in SplitScreenSelectState
private var splitSelectTranslationY = 0f
set(value) {
@@ -801,11 +792,7 @@
* Updates TaskView scaling and translation required to support variable width if enabled, while
* ensuring TaskView fits into screen in fullscreen.
*/
- open fun updateTaskSize(
- lastComputedTaskSize: Rect,
- lastComputedGridTaskSize: Rect,
- lastComputedCarouselTaskSize: Rect,
- ) {
+ open fun updateTaskSize(lastComputedTaskSize: Rect, lastComputedGridTaskSize: Rect) {
val thumbnailPadding = container.deviceProfile.overviewTaskThumbnailTopMarginPx
val taskWidth = lastComputedTaskSize.width()
val taskHeight = lastComputedTaskSize.height()
@@ -833,12 +820,7 @@
expectedHeight = boxHeight + thumbnailPadding
// Scale to to fit task Rect.
- nonGridScale =
- if (enableGridOnlyOverview()) {
- lastComputedCarouselTaskSize.width() / taskWidth.toFloat()
- } else {
- taskWidth / boxWidth.toFloat()
- }
+ nonGridScale = taskWidth / boxWidth.toFloat()
// Align to top of task Rect.
boxTranslationY = (expectedHeight - thumbnailPadding - taskHeight) / 2.0f
@@ -1591,7 +1573,6 @@
gridTranslationX = 0f
gridTranslationY = 0f
boxTranslationY = 0f
- nonGridPivotTranslationX = 0f
taskContainers.forEach {
it.snapshotView.translationX = 0f
it.snapshotView.translationY = 0f
diff --git a/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewScreenshotTest.kt b/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewScreenshotTest.kt
index 49fe614..a76f83c 100644
--- a/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewScreenshotTest.kt
+++ b/quickstep/tests/multivalentScreenshotTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewScreenshotTest.kt
@@ -20,6 +20,8 @@
import android.view.LayoutInflater
import com.android.launcher3.R
import com.android.quickstep.recents.di.RecentsDependencies
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.BackgroundOnly
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
import com.android.quickstep.task.viewmodel.TaskThumbnailViewModel
import com.google.android.apps.nexuslauncher.imagecomparison.goldenpathmanager.ViewScreenshotGoldenPathManager
import org.junit.Rule
@@ -46,7 +48,7 @@
private val taskThumbnailViewModel = FakeTaskThumbnailViewModel()
@Test
- fun taskThumbnailView_uninitialized() {
+ fun taskThumbnailView_uninitializedByDefault() {
screenshotRule.screenshotTest("taskThumbnailView_uninitialized") { activity ->
activity.actionBar?.hide()
createTaskThumbnailView(activity)
@@ -54,10 +56,39 @@
}
@Test
+ fun taskThumbnailView_resetsToUninitialized() {
+ screenshotRule.screenshotTest("taskThumbnailView_uninitialized") { activity ->
+ activity.actionBar?.hide()
+ val taskThumbnailView = createTaskThumbnailView(activity)
+ taskThumbnailViewModel.uiState.value = BackgroundOnly(Color.YELLOW)
+ taskThumbnailViewModel.uiState.value = Uninitialized
+ taskThumbnailView
+ }
+ }
+
+ @Test
+ fun taskThumbnailView_recyclesToUninitialized() {
+ screenshotRule.screenshotTest(
+ "taskThumbnailView_uninitialized",
+ viewProvider = { activity ->
+ activity.actionBar?.hide()
+ val taskThumbnailView = createTaskThumbnailView(activity)
+ taskThumbnailViewModel.uiState.value = BackgroundOnly(Color.YELLOW)
+ taskThumbnailView
+ },
+ checkView = { _, taskThumbnailView ->
+ // Call onRecycle() after View is attached (end of block above)
+ (taskThumbnailView as TaskThumbnailView).onRecycle()
+ false
+ },
+ )
+ }
+
+ @Test
fun taskThumbnailView_backgroundOnly() {
screenshotRule.screenshotTest("taskThumbnailView_backgroundOnly") { activity ->
activity.actionBar?.hide()
- taskThumbnailViewModel.uiState.value = TaskThumbnailUiState.BackgroundOnly(Color.YELLOW)
+ taskThumbnailViewModel.uiState.value = BackgroundOnly(Color.YELLOW)
createTaskThumbnailView(activity)
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
index f642345..b24926b 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
@@ -507,6 +507,45 @@
assertThat(height).isEqualTo(BUBBLE_BAR_HEIGHT)
}
+ @Test
+ fun getHandleViewAlpha_stashedHasBubbles_alphaPropertyReturned() {
+ // Given BubbleBar is stashed and has bubbles
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
+ mTransientBubbleStashController.isStashed = true
+
+ // When handle view alpha property
+ val alphaProperty = mTransientBubbleStashController.getHandleViewAlpha()
+
+ // Then the stash handle alpha property should not be null
+ assertThat(alphaProperty).isNotNull()
+ }
+
+ @Test
+ fun getHandleViewAlpha_stashedHasNoBubblesBar_alphaPropertyIsNull() {
+ // Given BubbleBar is stashed and has no bubbles
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(false)
+ mTransientBubbleStashController.isStashed = true
+
+ // When handle view alpha property
+ val alphaProperty = mTransientBubbleStashController.getHandleViewAlpha()
+
+ // Then the stash handle alpha property should be null
+ assertThat(alphaProperty).isNull()
+ }
+
+ @Test
+ fun getHandleViewAlpha_unstashedHasBubbles_alphaPropertyIsNull() {
+ // Given BubbleBar is not stashed and has bubbles
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
+ mTransientBubbleStashController.isStashed = false
+
+ // When handle view alpha property
+ val alphaProperty = mTransientBubbleStashController.getHandleViewAlpha()
+
+ // Then the stash handle alpha property should be null
+ assertThat(alphaProperty).isNull()
+ }
+
private fun advanceTimeBy(advanceMs: Long) {
// Advance animator for on-device tests
getInstrumentation().runOnMainSync { animatorTestRule.advanceTimeBy(advanceMs) }
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
index 542eb64..f16e193 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
@@ -364,7 +364,7 @@
private void onRecentsAnimationStart(SWIPE_HANDLER absSwipeUpHandler) {
runOnMainSync(() -> absSwipeUpHandler.onRecentsAnimationStart(
- mRecentsAnimationController, mRecentsAnimationTargets, /* transitionInfo= */null));
+ mRecentsAnimationController, mRecentsAnimationTargets));
}
protected static void runOnMainSync(Runnable runnable) {
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt
index 4541fdb..f05b422 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2Test.kt
@@ -17,6 +17,12 @@
package com.android.quickstep
import android.graphics.PointF
+import android.hardware.display.DisplayManager
+import android.hardware.display.DisplayManagerGlobal
+import android.view.Display
+import android.view.Display.DEFAULT_DISPLAY
+import android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS
+import android.view.DisplayInfo
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.launcher3.R
@@ -39,6 +45,7 @@
import org.mockito.junit.MockitoJUnit
import org.mockito.kotlin.eq
import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -63,8 +70,21 @@
private val flingSpeed =
-(sandboxContext.resources.getDimension(R.dimen.quickstep_fling_threshold_speed) + 1)
+ private val displayManager: DisplayManager =
+ sandboxContext.spyService(DisplayManager::class.java)
+
@Before
fun setup() {
+ val display =
+ Display(
+ DisplayManagerGlobal.getInstance(),
+ DEFAULT_DISPLAY,
+ DisplayInfo(),
+ DEFAULT_DISPLAY_ADJUSTMENTS,
+ )
+ whenever(displayManager.getDisplay(eq(DEFAULT_DISPLAY))).thenReturn(display)
+ whenever(displayManager.displays).thenReturn(arrayOf(display))
+
sandboxContext.initDaggerComponent(
DaggerTestComponent.builder().bindSystemUiProxy(systemUiProxy)
)
@@ -72,8 +92,10 @@
RotationTouchHelper.INSTANCE,
mock(RotationTouchHelper::class.java),
)
- val deviceState = mock(RecentsAnimationDeviceState::class.java)
- sandboxContext.putObject(RecentsAnimationDeviceState.INSTANCE, deviceState)
+ sandboxContext.putObject(
+ RecentsAnimationDeviceState.INSTANCE,
+ mock(RecentsAnimationDeviceState::class.java),
+ )
gestureState = spy(GestureState(OverviewComponentObserver.INSTANCE.get(sandboxContext), 0))
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentsDeviceProfileRepository.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentsDeviceProfileRepository.kt
index fc2f029..4e90903 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentsDeviceProfileRepository.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentsDeviceProfileRepository.kt
@@ -18,9 +18,7 @@
class FakeRecentsDeviceProfileRepository : RecentsDeviceProfileRepository {
private var recentsDeviceProfile =
- RecentsDeviceProfile(
- isLargeScreen = false,
- )
+ RecentsDeviceProfile(isLargeScreen = false, canEnterDesktopMode = false)
override fun getRecentsDeviceProfile() = recentsDeviceProfile
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImplTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImplTest.kt
deleted file mode 100644
index abe4142..0000000
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/RecentsDeviceProfileRepositoryImplTest.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.quickstep.recents.data
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.android.launcher3.FakeInvariantDeviceProfileTest
-import com.android.quickstep.views.RecentsViewContainer
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.kotlin.mock
-import org.mockito.kotlin.whenever
-
-/** Test for [RecentsDeviceProfileRepositoryImpl] */
-@RunWith(AndroidJUnit4::class)
-class RecentsDeviceProfileRepositoryImplTest : FakeInvariantDeviceProfileTest() {
- private val recentsViewContainer = mock<RecentsViewContainer>()
-
- private val systemUnderTest = RecentsDeviceProfileRepositoryImpl(recentsViewContainer)
-
- @Test
- fun deviceProfileMappedCorrectly() {
- initializeVarsForTablet()
- val tabletDeviceProfile = newDP()
- whenever(recentsViewContainer.deviceProfile).thenReturn(tabletDeviceProfile)
-
- assertThat(systemUnderTest.getRecentsDeviceProfile())
- .isEqualTo(RecentsDeviceProfile(isLargeScreen = true))
- }
-}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelImplTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelImplTest.kt
index a777bd4..a956c9c 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelImplTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelImplTest.kt
@@ -16,16 +16,23 @@
package com.android.quickstep.task.thumbnail
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
+import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
import android.content.ComponentName
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.Matrix
import android.graphics.drawable.Drawable
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
import android.view.Surface
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.launcher3.Flags
import com.android.launcher3.util.TestDispatcherProvider
+import com.android.quickstep.recents.data.FakeRecentsDeviceProfileRepository
import com.android.quickstep.recents.data.FakeTasksRepository
+import com.android.quickstep.recents.data.RecentsDeviceProfile
import com.android.quickstep.recents.usecase.GetThumbnailPositionUseCase
import com.android.quickstep.recents.usecase.ThumbnailPositionState.MatrixScaling
import com.android.quickstep.recents.usecase.ThumbnailPositionState.MissingThumbnail
@@ -34,6 +41,7 @@
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Snapshot
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.SnapshotSplash
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.ThumbnailHeader
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
import com.android.quickstep.task.viewmodel.TaskContainerData
import com.android.quickstep.task.viewmodel.TaskThumbnailViewModelImpl
@@ -44,6 +52,7 @@
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.mock
@@ -52,6 +61,8 @@
/** Test for [TaskThumbnailView] */
@RunWith(AndroidJUnit4::class)
class TaskThumbnailViewModelImplTest {
+ @get:Rule val setFlagsRule = SetFlagsRule()
+
private val dispatcher = StandardTestDispatcher()
private val testScope = TestScope(dispatcher)
@@ -59,6 +70,7 @@
private val taskContainerData = TaskContainerData()
private val dispatcherProvider = TestDispatcherProvider(dispatcher)
private val tasksRepository = FakeTasksRepository()
+ private val deviceProfileRepository = FakeRecentsDeviceProfileRepository()
private val mGetThumbnailPositionUseCase = mock<GetThumbnailPositionUseCase>()
private val splashAlphaUseCase: SplashAlphaUseCase = mock()
@@ -68,12 +80,18 @@
taskContainerData,
dispatcherProvider,
tasksRepository,
+ deviceProfileRepository,
mGetThumbnailPositionUseCase,
splashAlphaUseCase,
)
}
- private val tasks = (0..5).map(::createTaskWithId)
+ private val fullscreenTaskIdRange: IntRange = 0..5
+ private val freeformTaskIdRange: IntRange = 6..10
+
+ private val fullscreenTasks = fullscreenTaskIdRange.map(::createTaskWithId)
+ private val freeformTasks = freeformTaskIdRange.map(::createFreeformTaskWithId)
+ private val tasks = fullscreenTasks + freeformTasks
@Test
fun initialStateIsUninitialized() =
@@ -88,7 +106,7 @@
recentsViewData.runningTaskIds.value = setOf(taskId)
systemUnderTest.bind(taskId)
- assertThat(systemUnderTest.uiState.first()).isEqualTo(LiveTile)
+ assertThat(systemUnderTest.uiState.first()).isEqualTo(LiveTile.WithoutHeader)
}
@Test
@@ -108,7 +126,7 @@
assertThat(systemUnderTest.uiState.first())
.isEqualTo(
SnapshotSplash(
- Snapshot(
+ Snapshot.WithoutHeader(
backgroundColor = Color.rgb(1, 1, 1),
bitmap = expectedThumbnailData.thumbnail!!,
thumbnailRotation = Surface.ROTATION_0,
@@ -127,7 +145,7 @@
tasksRepository.setVisibleTasks(setOf(runningTaskId, stoppedTaskId))
recentsViewData.runningTaskIds.value = setOf(runningTaskId)
systemUnderTest.bind(runningTaskId)
- assertThat(systemUnderTest.uiState.first()).isEqualTo(LiveTile)
+ assertThat(systemUnderTest.uiState.first()).isEqualTo(LiveTile.WithoutHeader)
systemUnderTest.bind(stoppedTaskId)
assertThat(systemUnderTest.uiState.first())
@@ -175,7 +193,7 @@
assertThat(systemUnderTest.uiState.first())
.isEqualTo(
SnapshotSplash(
- Snapshot(
+ Snapshot.WithoutHeader(
backgroundColor = Color.rgb(2, 2, 2),
bitmap = expectedThumbnailData.thumbnail!!,
thumbnailRotation = Surface.ROTATION_270,
@@ -202,7 +220,7 @@
assertThat(systemUnderTest.uiState.first())
.isEqualTo(
SnapshotSplash(
- Snapshot(
+ Snapshot.WithoutHeader(
backgroundColor = Color.rgb(2, 2, 2),
bitmap = expectedThumbnailData.thumbnail!!,
thumbnailRotation = Surface.ROTATION_0,
@@ -213,6 +231,57 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_EXPLODED_VIEW)
+ fun bindRunningTask_inDesktop_thenStateIs_LiveTile_withHeader() =
+ testScope.runTest {
+ deviceProfileRepository.setRecentsDeviceProfile(
+ RecentsDeviceProfile(isLargeScreen = true, canEnterDesktopMode = true)
+ )
+
+ val taskId = freeformTaskIdRange.first
+ val expectedIconData = mock<Drawable>()
+ tasksRepository.seedIconData(taskId, "Task $taskId", "Task $taskId", expectedIconData)
+ tasksRepository.seedTasks(freeformTasks)
+ tasksRepository.setVisibleTasks(setOf(taskId))
+ recentsViewData.runningTaskIds.value = setOf(taskId)
+ systemUnderTest.bind(taskId)
+
+ assertThat(systemUnderTest.uiState.first())
+ .isEqualTo(LiveTile.WithHeader(ThumbnailHeader(expectedIconData, "Task $taskId")))
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_EXPLODED_VIEW)
+ fun bindStoppedTaskWithThumbnail_inDesktop_thenStateIs_SnapshotSplash_withHeader() =
+ testScope.runTest {
+ deviceProfileRepository.setRecentsDeviceProfile(
+ RecentsDeviceProfile(isLargeScreen = true, canEnterDesktopMode = true)
+ )
+
+ val taskId = freeformTaskIdRange.first
+ val expectedThumbnailData = createThumbnailData(rotation = Surface.ROTATION_0)
+ tasksRepository.seedThumbnailData(mapOf(taskId to expectedThumbnailData))
+ val expectedIconData = mock<Drawable>()
+ tasksRepository.seedIconData(taskId, "Task $taskId", "Task $taskId", expectedIconData)
+ tasksRepository.seedTasks(freeformTasks)
+ tasksRepository.setVisibleTasks(setOf(taskId))
+
+ systemUnderTest.bind(taskId)
+ assertThat(systemUnderTest.uiState.first())
+ .isEqualTo(
+ SnapshotSplash(
+ Snapshot.WithHeader(
+ backgroundColor = Color.rgb(taskId, taskId, taskId),
+ bitmap = expectedThumbnailData.thumbnail!!,
+ thumbnailRotation = Surface.ROTATION_0,
+ header = ThumbnailHeader(expectedIconData, "Task $taskId"),
+ ),
+ expectedIconData,
+ )
+ )
+ }
+
+ @Test
fun getSnapshotMatrix_MissingThumbnail() =
testScope.runTest {
val taskId = 2
@@ -269,9 +338,38 @@
}
private fun createTaskWithId(taskId: Int) =
- Task(Task.TaskKey(taskId, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
- colorBackground = Color.argb(taskId, taskId, taskId, taskId)
- }
+ Task(
+ Task.TaskKey(
+ taskId,
+ WINDOWING_MODE_FULLSCREEN,
+ Intent(),
+ ComponentName("", ""),
+ 0,
+ 2000,
+ )
+ )
+ .apply {
+ colorBackground = Color.argb(taskId, taskId, taskId, taskId)
+ titleDescription = "Task $taskId"
+ icon = mock<Drawable>()
+ }
+
+ private fun createFreeformTaskWithId(taskId: Int) =
+ Task(
+ Task.TaskKey(
+ taskId,
+ WINDOWING_MODE_FREEFORM,
+ Intent(),
+ ComponentName("", ""),
+ 0,
+ 2000,
+ )
+ )
+ .apply {
+ colorBackground = Color.argb(taskId, taskId, taskId, taskId)
+ titleDescription = "Task $taskId"
+ icon = mock<Drawable>()
+ }
private fun createThumbnailData(rotation: Int = Surface.ROTATION_0): ThumbnailData {
val bitmap = mock<Bitmap>()
diff --git a/quickstep/tests/src/com/android/quickstep/RecentsDeviceProfileRepositoryImplTest.kt b/quickstep/tests/src/com/android/quickstep/RecentsDeviceProfileRepositoryImplTest.kt
new file mode 100644
index 0000000..418d66c
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/RecentsDeviceProfileRepositoryImplTest.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
+import com.android.launcher3.FakeInvariantDeviceProfileTest
+import com.android.quickstep.recents.data.RecentsDeviceProfile
+import com.android.quickstep.recents.data.RecentsDeviceProfileRepositoryImpl
+import com.android.quickstep.views.RecentsViewContainer
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+import org.mockito.quality.Strictness
+
+class RecentsDeviceProfileRepositoryImplTest : FakeInvariantDeviceProfileTest() {
+ private val recentsViewContainer: RecentsViewContainer = mock()
+
+ private lateinit var mockitoSession: StaticMockitoSession
+
+ @Before
+ override fun setUp() {
+ super.setUp()
+ mockitoSession =
+ mockitoSession()
+ .strictness(Strictness.LENIENT)
+ .mockStatic(DesktopModeStatus::class.java)
+ .startMocking()
+ whenever(recentsViewContainer.asContext()).thenReturn(context)
+ }
+
+ @After
+ fun tearDown() {
+ mockitoSession.finishMocking()
+ }
+
+ @Test
+ fun deviceProfileMappedCorrectlyForPhone() {
+ val deviceProfileRepo = RecentsDeviceProfileRepositoryImpl(recentsViewContainer)
+ initializeVarsForPhone()
+ val phoneDeviceProfile = newDP()
+ whenever(recentsViewContainer.deviceProfile).thenReturn(phoneDeviceProfile)
+
+ whenever(DesktopModeStatus.canEnterDesktopMode(any())).thenReturn(false)
+ assertThat(deviceProfileRepo.getRecentsDeviceProfile())
+ .isEqualTo(RecentsDeviceProfile(isLargeScreen = false, canEnterDesktopMode = false))
+ }
+
+ @Test
+ fun deviceProfileMappedCorrectlyForTablet() {
+ val deviceProfileRepo = RecentsDeviceProfileRepositoryImpl(recentsViewContainer)
+ initializeVarsForTablet()
+ val tabletDeviceProfile = newDP()
+ whenever(recentsViewContainer.deviceProfile).thenReturn(tabletDeviceProfile)
+
+ whenever(DesktopModeStatus.canEnterDesktopMode(any())).thenReturn(true)
+ assertThat(deviceProfileRepo.getRecentsDeviceProfile())
+ .isEqualTo(RecentsDeviceProfile(isLargeScreen = true, canEnterDesktopMode = true))
+ }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
index e065dba..88be752 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
@@ -165,7 +165,6 @@
}
@Test
- @ScreenRecordRule.ScreenRecord // b/355466672
public void testPrivateSpaceLockingBehaviour() throws IOException {
assumeFalse(mLauncher.isTablet()); // b/367258373
// Scroll to the bottom of All Apps
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index daa4ec3..afe6368 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -16,8 +16,6 @@
package com.android.quickstep;
-import static com.android.launcher3.config.FeatureFlags.enableSplitContextually;
-
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
@@ -89,18 +87,10 @@
.getSplitScreenMenuItem()
.click();
- if (enableSplitContextually()) {
- // We're staying in all apps, use same instance
- mLauncher.getAllApps()
- .getAppIcon(CALCULATOR_APP_NAME)
- .launchIntoSplitScreen();
- } else {
- // We're in overview, use taskbar instance
- mLauncher.getLaunchedAppState()
- .getTaskbar()
- .getAppIcon(CALCULATOR_APP_NAME)
- .launchIntoSplitScreen();
- }
+ // We're staying in all apps, use same instance
+ mLauncher.getAllApps()
+ .getAppIcon(CALCULATOR_APP_NAME)
+ .launchIntoSplitScreen();
}
@Test
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
index c24e974..08ce5e7 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
@@ -124,6 +124,7 @@
}
@Test
+ @ScreenRecordRule.ScreenRecord // b/373417111
public void testLaunchShortcut_fromTaskbarAllApps() {
getTaskbar().openAllApps()
.getAppIcon(TEST_APP_NAME)
@@ -134,7 +135,6 @@
@Test
@PortraitLandscape
- @ScreenRecordRule.ScreenRecord // b/349439239
public void testLaunchAppInSplitscreen_fromTaskbarAllApps() {
getTaskbar().openAllApps()
.getAppIcon(TEST_APP_NAME)
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 21aabfa..212534b 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -488,8 +488,6 @@
<dimen name="overview_grid_side_margin">0dp</dimen>
<dimen name="overview_grid_row_spacing">0dp</dimen>
<dimen name="overview_page_spacing">0dp</dimen>
- <dimen name="overview_top_margin_grid_only">0dp</dimen>
- <dimen name="overview_bottom_margin_grid_only">0dp</dimen>
<dimen name="split_placeholder_size">72dp</dimen>
<dimen name="split_placeholder_inset">16dp</dimen>
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index f68c8e0..7df4014 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1657,9 +1657,7 @@
}
}
- if (FeatureFlags.enableSplitContextually()) {
- handleSplitAnimationGoingToHome(LAUNCHER_SPLIT_SELECTION_EXIT_HOME);
- }
+ handleSplitAnimationGoingToHome(LAUNCHER_SPLIT_SELECTION_EXIT_HOME);
mOverlayManager.hideOverlay(isStarted());
handleGestureContract(intent);
} else if (Intent.ACTION_ALL_APPS.equals(intent.getAction())) {
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index e44caa4..7563493 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -681,7 +681,7 @@
} else {
// Wrap the main icon in AID
try (LauncherIcons li = LauncherIcons.obtain(context)) {
- result = li.wrapToAdaptiveIcon(mainIcon, null);
+ result = li.wrapToAdaptiveIcon(mainIcon);
}
}
if (result == null) {
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 9e38824..1fe42f7 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -201,15 +201,6 @@
"USE_LOCAL_ICON_OVERRIDES", ENABLED,
"Use inbuilt monochrome icons if app doesn't provide one");
- // Aconfig migration complete for ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.
- public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE = getDebugFlag(
- 270393453, "ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE", DISABLED,
- "Enable initiating split screen from workspace to workspace.");
- public static boolean enableSplitContextually() {
- return ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get() ||
- com.android.wm.shell.Flags.enableSplitContextual();
- }
-
// TODO(Block 29): Clean up flags
// Aconfig migration complete for ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.
public static final BooleanFlag ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT = getDebugFlag(270393897,
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 67fe889..f1b461b 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -264,8 +264,7 @@
try (LauncherIcons li = LauncherIcons.obtain(mActivity)) {
// Since we just want the scale, avoid heavy drawing operations
Utilities.scaleRectAboutCenter(bounds, li.getNormalizer().getScale(
- new AdaptiveIconDrawable(new ColorDrawable(Color.BLACK), null),
- null, null, null));
+ new AdaptiveIconDrawable(new ColorDrawable(Color.BLACK), null)));
}
// Shrink very tiny bit so that the clip path is smaller than the original bitmap
diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
index f144d14..ad176dc 100644
--- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
+++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.graphics;
+
+import static com.android.launcher3.graphics.IconShape.PREF_ICON_SHAPE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@@ -40,9 +42,10 @@
import com.android.launcher3.InvariantDeviceProfile.GridOption;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
+import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.model.BgDataModel;
-import com.android.launcher3.shapes.AppShape;
-import com.android.launcher3.shapes.AppShapesProvider;
+import com.android.launcher3.shapes.IconShapeModel;
+import com.android.launcher3.shapes.IconShapesProvider;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.RunnableList;
@@ -50,7 +53,6 @@
import java.util.Collections;
import java.util.List;
-import java.util.Optional;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutionException;
@@ -139,16 +141,23 @@
if (Flags.newCustomizationPickerUi()) {
MatrixCursor cursor = new MatrixCursor(new String[]{
KEY_SHAPE_KEY, KEY_SHAPE_TITLE, KEY_PATH, KEY_IS_DEFAULT});
- List<AppShape> shapes = AppShapesProvider.INSTANCE.getShapes();
+ List<IconShapeModel> shapes = IconShapesProvider.INSTANCE.getShapes()
+ .values()
+ .stream()
+ .toList();
+ String currentPath = LauncherPrefs.get(context).get(PREF_ICON_SHAPE);
+ IconShapeModel currentShape = shapes.stream()
+ .filter(shape -> currentPath.equals(shape.getPathString()))
+ .findFirst()
+ .orElse(IconShapesProvider.INSTANCE.getShapes().get("circle"));
+
for (int i = 0; i < shapes.size(); i++) {
- AppShape shape = shapes.get(i);
+ IconShapeModel shape = shapes.get(i);
cursor.newRow()
.add(KEY_SHAPE_KEY, shape.getKey())
.add(KEY_SHAPE_TITLE, shape.getTitle())
- .add(KEY_PATH, shape.getPath())
- // TODO (b/348664593): We should fetch the currently-set shape
- // option from the preferences.
- .add(KEY_IS_DEFAULT, i == 0);
+ .add(KEY_PATH, shape.getPathString())
+ .add(KEY_IS_DEFAULT, shape.equals(currentShape));
}
return cursor;
} else {
@@ -210,11 +219,8 @@
case KEY_DEFAULT_GRID: {
if (Flags.newCustomizationPickerUi()) {
String shapeKey = values.getAsString(KEY_SHAPE_KEY);
- Optional<AppShape> optionalShape = AppShapesProvider.INSTANCE.getShapes()
- .stream().filter(shape -> shape.getKey().equals(shapeKey)).findFirst();
- String pathToSet = optionalShape.map(AppShape::getPath).orElse(null);
- // TODO (b/348664593): Apply shapeName to the system. This needs to be a
- // synchronous call.
+ IconShapeModel shape = IconShapesProvider.INSTANCE.getShapes().get(shapeKey);
+ IconShape.INSTANCE.get(context).setShapeOverride(shape);
}
String gridName = values.getAsString(KEY_NAME);
InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(context);
@@ -353,14 +359,12 @@
renderer.hideBottomRow(message.getData().getBoolean(KEY_HIDE_BOTTOM_ROW));
break;
case MESSAGE_ID_UPDATE_SHAPE:
- if (Flags.newCustomizationPickerUi() && Flags.enableLauncherIconShapes()) {
+ if (Flags.newCustomizationPickerUi()
+ && com.android.launcher3.Flags.enableLauncherIconShapes()) {
String shapeKey = message.getData().getString(KEY_SHAPE_KEY);
- Optional<AppShape> optionalShape = AppShapesProvider.INSTANCE.getShapes()
- .stream()
- .filter(shape -> shape.getKey().equals(shapeKey))
- .findFirst();
- String pathToSet = optionalShape.map(AppShape::getPath).orElse(null);
- // TODO (b/348664593): Update launcher preview with the given shape
+ IconShapeModel shape =
+ IconShapesProvider.INSTANCE.getShapes().get(shapeKey);
+ renderer.updateShape(shape);
}
break;
case MESSAGE_ID_UPDATE_GRID:
diff --git a/src/com/android/launcher3/graphics/IconShape.kt b/src/com/android/launcher3/graphics/IconShape.kt
index 1377610..2d2ee30 100644
--- a/src/com/android/launcher3/graphics/IconShape.kt
+++ b/src/com/android/launcher3/graphics/IconShape.kt
@@ -18,6 +18,7 @@
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
+import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Matrix
@@ -39,12 +40,19 @@
import androidx.graphics.shapes.SvgPathParser
import androidx.graphics.shapes.toPath
import androidx.graphics.shapes.transformed
+import com.android.launcher3.EncryptionType
+import com.android.launcher3.LauncherPrefs
+import com.android.launcher3.LauncherPrefs.Companion.backedUpItem
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider
+import com.android.launcher3.dagger.ApplicationContext
import com.android.launcher3.dagger.LauncherAppComponent
import com.android.launcher3.dagger.LauncherAppSingleton
+import com.android.launcher3.graphics.LauncherPreviewRenderer.PreviewContext
import com.android.launcher3.graphics.ThemeManager.ThemeChangeListener
import com.android.launcher3.icons.GraphicsUtils
import com.android.launcher3.icons.IconNormalizer
+import com.android.launcher3.shapes.IconShapeModel
+import com.android.launcher3.shapes.IconShapesProvider
import com.android.launcher3.util.DaggerSingletonObject
import com.android.launcher3.util.DaggerSingletonTracker
import com.android.launcher3.views.ClipPathView
@@ -52,7 +60,22 @@
/** Abstract representation of the shape of an icon shape */
@LauncherAppSingleton
-class IconShape @Inject constructor(themeManager: ThemeManager, lifeCycle: DaggerSingletonTracker) {
+class IconShape
+@Inject
+constructor(
+ @ApplicationContext private val context: Context,
+ private val prefs: LauncherPrefs,
+ themeManager: ThemeManager,
+ lifeCycle: DaggerSingletonTracker,
+) {
+
+ var shapeOverride: IconShapeModel? = getShapeFromPathString(prefs.get(PREF_ICON_SHAPE))
+ set(value) {
+ field = value
+ if (context !is PreviewContext) {
+ value?.let { prefs.put(PREF_ICON_SHAPE, value.pathString) }
+ }
+ }
var normalizationScale: Float = IconNormalizer.ICON_VISIBLE_AREA_FACTOR
private set
@@ -62,7 +85,6 @@
init {
val changeListener = ThemeChangeListener { shape = pickBestShape(themeManager) }
-
themeManager.addChangeListener(changeListener)
lifeCycle.addCloseable { themeManager.removeChangeListener(changeListener) }
}
@@ -74,13 +96,11 @@
setBounds(0, 0, AREA_CALC_SIZE, AREA_CALC_SIZE)
}
- normalizationScale = IconNormalizer.normalizeAdaptiveIcon(drawable, AREA_CALC_SIZE, null)
+ normalizationScale = IconNormalizer.normalizeAdaptiveIcon(drawable, AREA_CALC_SIZE)
return pickBestShape(drawable.iconMask, themeManager.iconState.iconMask)
}
interface ShapeDelegate {
- fun enableShapeDetection() = false
-
fun drawShape(canvas: Canvas, offsetX: Float, offsetY: Float, radius: Float, paint: Paint)
fun addToPath(path: Path, offsetX: Float, offsetY: Float, radius: Float)
@@ -107,8 +127,6 @@
override fun addToPath(path: Path, offsetX: Float, offsetY: Float, radius: Float) =
path.addCircle(radius + offsetX, radius + offsetY, radius, Path.Direction.CW)
-
- override fun enableShapeDetection() = true
}
/** Rounded square with [radiusRatio] as a ratio of its half edge size */
@@ -231,7 +249,7 @@
private var oldOutlineProvider: ViewOutlineProvider? = null
override fun onAnimationStart(animation: Animator) {
- target?.apply {
+ target.apply {
oldOutlineProvider = outlineProvider
outlineProvider = null
translationZ = -target.elevation
@@ -262,11 +280,19 @@
@JvmField var INSTANCE = DaggerSingletonObject(LauncherAppComponent::getIconShape)
const val TAG = "IconShape"
-
+ const val KEY_ICON_SHAPE = "icon_shape"
const val AREA_CALC_SIZE = 1000
// .1% error margin
const val AREA_DIFF_THRESHOLD = AREA_CALC_SIZE * AREA_CALC_SIZE / 1000
+ @JvmField val PREF_ICON_SHAPE = backedUpItem(KEY_ICON_SHAPE, "", EncryptionType.ENCRYPTED)
+
+ private fun getShapeFromPathString(pathString: String): IconShapeModel? {
+ return IconShapesProvider.shapes.values.firstOrNull { shape: IconShapeModel ->
+ shape.pathString == pathString
+ }
+ }
+
/** Returns a function to calculate area diff from [base] */
@VisibleForTesting
fun areaDiffCalculator(base: Path): (ShapeDelegate) -> Int {
@@ -328,14 +354,19 @@
RoundedPolygon(
vertices =
floatArrayOf(
+ // x1, y1
(left + right) / 2,
top,
+ // x2, y2
right,
top,
+ // x3, y3
right,
bottom,
+ // x4, y4
left,
bottom,
+ // x5, y5
left,
top,
),
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index 3000b25..6afac71 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -62,6 +62,7 @@
import com.android.launcher3.model.LoaderTask;
import com.android.launcher3.model.ModelDbController;
import com.android.launcher3.provider.LauncherDbUtils;
+import com.android.launcher3.shapes.IconShapeModel;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.Themes;
@@ -77,9 +78,7 @@
public class PreviewSurfaceRenderer {
private static final String TAG = "PreviewSurfaceRenderer";
-
private static final int FADE_IN_ANIMATION_DURATION = 200;
-
private static final String KEY_HOST_TOKEN = "host_token";
private static final String KEY_VIEW_WIDTH = "width";
private static final String KEY_VIEW_HEIGHT = "height";
@@ -90,25 +89,25 @@
private static final String KEY_DARK_MODE = "use_dark_mode";
private Context mContext;
- private final IBinder mHostToken;
- private final int mWidth;
- private final int mHeight;
- private String mGridName;
-
- private final int mDisplayId;
- private final Display mDisplay;
- private final WallpaperColors mWallpaperColors;
private SparseIntArray mPreviewColorOverride;
+ private String mGridName;
+ private IconShapeModel mShape;
@Nullable private Boolean mDarkMode;
- private final RunnableList mLifeCycleTracker;
-
- private final SurfaceControlViewHost mSurfaceControlViewHost;
-
private boolean mDestroyed = false;
private LauncherPreviewRenderer mRenderer;
private boolean mHideQsb;
@Nullable private FrameLayout mViewRoot = null;
+ private final IBinder mHostToken;
+ private final int mWidth;
+ private final int mHeight;
+ private final int mDisplayId;
+ private final Display mDisplay;
+ private final WallpaperColors mWallpaperColors;
+ private final RunnableList mLifeCycleTracker;
+ private final SurfaceControlViewHost mSurfaceControlViewHost;
+
+
public PreviewSurfaceRenderer(
Context context, RunnableList lifecycleTracker, Bundle bundle) throws Exception {
mContext = context;
@@ -135,10 +134,10 @@
}
mSurfaceControlViewHost = MAIN_EXECUTOR.submit(() -> new MySurfaceControlViewHost(
- mContext,
- context.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY),
- mHostToken,
- mLifeCycleTracker))
+ mContext,
+ context.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY),
+ mHostToken,
+ mLifeCycleTracker))
.get(5, TimeUnit.SECONDS);
mLifeCycleTracker.add(this::destroy);
}
@@ -219,6 +218,20 @@
}
/**
+ * Update the shapes of the launcher preview
+ *
+ * @param shape path for shapes
+ */
+ public void updateShape(@NonNull IconShapeModel shape) {
+ if (shape.equals(mShape)) {
+ Log.w(TAG, "Preview shape already set, skipping. shape=" + shape);
+ return;
+ }
+ mShape = shape;
+ loadAsync();
+ }
+
+ /**
* Hides the components in the bottom row.
*
* @param hide True to hide and false to show.
@@ -303,9 +316,13 @@
private void loadModelData() {
final Context inflationContext = getPreviewContext();
final InvariantDeviceProfile idp = new InvariantDeviceProfile(inflationContext, mGridName);
- if (GridSizeMigrationDBController.needsToMigrate(inflationContext, idp)) {
+ if (GridSizeMigrationDBController.needsToMigrate(inflationContext, idp)
+ || mShape != null) {
// Start the migration
PreviewContext previewContext = new PreviewContext(inflationContext, idp);
+ if (mShape != null) {
+ IconShape.INSTANCE.get(previewContext).setShapeOverride(mShape);
+ }
// Copy existing data to preview DB
LauncherDbUtils.copyTable(LauncherAppState.getInstance(mContext)
.getModel().getModelDbController().getDb(),
diff --git a/src/com/android/launcher3/graphics/ThemeManager.kt b/src/com/android/launcher3/graphics/ThemeManager.kt
index 991edf7..989471f 100644
--- a/src/com/android/launcher3/graphics/ThemeManager.kt
+++ b/src/com/android/launcher3/graphics/ThemeManager.kt
@@ -25,6 +25,8 @@
import com.android.launcher3.dagger.ApplicationContext
import com.android.launcher3.dagger.LauncherAppComponent
import com.android.launcher3.dagger.LauncherAppSingleton
+import com.android.launcher3.graphics.IconShape.Companion.KEY_ICON_SHAPE
+import com.android.launcher3.graphics.IconShape.Companion.PREF_ICON_SHAPE
import com.android.launcher3.icons.IconThemeController
import com.android.launcher3.icons.mono.MonoIconThemeController
import com.android.launcher3.util.DaggerSingletonObject
@@ -63,9 +65,12 @@
receiver.registerPkgActions(context, "android", ACTION_OVERLAY_CHANGED)
val prefListener = LauncherPrefChangeListener { key ->
- if (key == THEMED_ICONS.sharedPrefKey) verifyIconState()
+ when (key) {
+ KEY_THEMED_ICONS,
+ KEY_ICON_SHAPE -> verifyIconState()
+ }
}
- prefs.addListener(prefListener, THEMED_ICONS)
+ prefs.addListener(prefListener, THEMED_ICONS, PREF_ICON_SHAPE)
lifecycle.addCloseable {
receiver.unregisterReceiverSafely(context)
@@ -87,13 +92,18 @@
fun removeChangeListener(listener: ThemeChangeListener) = listeners.remove(listener)
- private fun parseIconState() =
- IconState(
+ private fun parseIconState(): IconState {
+ val shapeOverride = prefs.get(PREF_ICON_SHAPE)
+ return IconState(
iconMask =
- if (CONFIG_ICON_MASK_RES_ID == Resources.ID_NULL) ""
- else context.resources.getString(CONFIG_ICON_MASK_RES_ID),
+ when {
+ shapeOverride.isNotEmpty() -> shapeOverride
+ CONFIG_ICON_MASK_RES_ID == Resources.ID_NULL -> ""
+ else -> context.resources.getString(CONFIG_ICON_MASK_RES_ID)
+ },
isMonoTheme = isMonoThemeEnabled,
)
+ }
data class IconState(
val iconMask: String,
diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java
index 04d88b0..2ffbeb8 100644
--- a/src/com/android/launcher3/icons/LauncherIcons.java
+++ b/src/com/android/launcher3/icons/LauncherIcons.java
@@ -17,14 +17,22 @@
package com.android.launcher3.icons;
import android.content.Context;
+import android.graphics.Matrix;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.AdaptiveIconDrawable;
import android.os.UserHandle;
import androidx.annotation.NonNull;
+import androidx.core.graphics.PathParser;
+import com.android.launcher3.Flags;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.graphics.IconShape;
import com.android.launcher3.graphics.ThemeManager;
import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.shapes.IconShapeModel;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.UserIconInfo;
@@ -56,8 +64,7 @@
protected LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize,
ConcurrentLinkedQueue<LauncherIcons> pool) {
- super(context, fillResIconDpi, iconBitmapSize,
- IconShape.INSTANCE.get(context).getShape().enableShapeDetection());
+ super(context, fillResIconDpi, iconBitmapSize);
mThemeController = ThemeManager.INSTANCE.get(context).getThemeController();
mPool = pool;
}
@@ -76,6 +83,28 @@
return UserCache.INSTANCE.get(mContext).getUserInfo(user);
}
+ @NonNull
+ @Override
+ public Path getShapePath(AdaptiveIconDrawable drawable, Rect iconBounds) {
+ if (!Flags.enableLauncherIconShapes()) return drawable.getIconMask();
+
+ IconShapeModel shapeOverride = IconShape.INSTANCE.get(mContext).getShapeOverride();
+ if (shapeOverride != null) {
+ Path maskPath = PathParser.createPathFromPathData(shapeOverride.getPathString());
+ Matrix matrix = new Matrix();
+ // Assuming Path is in [0, 0, 100, 100] coordinate space.
+ matrix.setRectToRect(
+ new RectF(0, 0, 100, 100),
+ new RectF(iconBounds),
+ Matrix.ScaleToFit.CENTER // Todo: CENTER or FILL?
+ );
+ maskPath.transform(matrix);
+ return maskPath;
+ } else {
+ return drawable.getIconMask();
+ }
+ }
+
@Override
public void close() {
recycle();
diff --git a/src/com/android/launcher3/model/GridSizeMigrationDBController.java b/src/com/android/launcher3/model/GridSizeMigrationDBController.java
index 211c351..0732379 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationDBController.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationDBController.java
@@ -120,7 +120,8 @@
@NonNull DeviceGridState destDeviceState,
@NonNull DatabaseHelper target,
@NonNull SQLiteDatabase source,
- boolean isDestNewDb) {
+ boolean isDestNewDb,
+ ModelDelegate modelDelegate) {
if (!needsToMigrate(srcDeviceState, destDeviceState)) {
return true;
@@ -174,7 +175,6 @@
return true;
} catch (Exception e) {
Log.e(TAG, "Error during grid migration", e);
-
return false;
} finally {
Log.v(TAG, "Workspace migration completed in "
@@ -182,6 +182,8 @@
// Save current configuration, so that the migration does not run again.
destDeviceState.writeToPrefs(context);
+ // Notify if we've migrated successfully
+ modelDelegate.gridMigrationComplete(srcDeviceState, destDeviceState);
}
}
diff --git a/src/com/android/launcher3/model/GridSizeMigrationLogic.kt b/src/com/android/launcher3/model/GridSizeMigrationLogic.kt
index 0b12af8..1729153 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationLogic.kt
+++ b/src/com/android/launcher3/model/GridSizeMigrationLogic.kt
@@ -53,6 +53,7 @@
target: DatabaseHelper,
source: SQLiteDatabase,
isDestNewDb: Boolean,
+ modelDelegate: ModelDelegate,
) {
if (!GridSizeMigrationDBController.needsToMigrate(srcDeviceState, destDeviceState)) {
return
@@ -132,6 +133,9 @@
// Save current configuration, so that the migration does not run again.
destDeviceState.writeToPrefs(context)
+
+ // Notify if we've migrated successfully
+ modelDelegate.gridMigrationComplete(srcDeviceState, destDeviceState)
}
}
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 4e57944..44b7e8b 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -438,12 +438,12 @@
ModelDbController dbController = mApp.getModel().getModelDbController();
if (Flags.gridMigrationRefactor()) {
try {
- dbController.attemptMigrateDb(restoreEventLogger);
+ dbController.attemptMigrateDb(restoreEventLogger, mModelDelegate);
} catch (Exception e) {
FileLog.e(TAG, "Failed to migrate grid", e);
}
} else {
- dbController.tryMigrateDB(restoreEventLogger);
+ dbController.tryMigrateDB(restoreEventLogger, mModelDelegate);
}
Log.d(TAG, "loadWorkspace: loading default favorites if necessary");
dbController.loadDefaultFavoritesIfNecessary();
diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java
index e76391f..0138390 100644
--- a/src/com/android/launcher3/model/ModelDbController.java
+++ b/src/com/android/launcher3/model/ModelDbController.java
@@ -361,7 +361,8 @@
/**
* Migrates the DB. If the migration failed, it clears the DB.
*/
- public void attemptMigrateDb(LauncherRestoreEventLogger restoreEventLogger) throws Exception {
+ public void attemptMigrateDb(LauncherRestoreEventLogger restoreEventLogger,
+ ModelDelegate modelDelegate) throws Exception {
createDbIfNotExists();
if (shouldResetDb()) {
@@ -389,7 +390,7 @@
boolean isDestNewDb = !existingDBs.contains(destDeviceState.getDbFile());
GridSizeMigrationLogic gridSizeMigrationLogic = new GridSizeMigrationLogic();
gridSizeMigrationLogic.migrateGrid(mContext, srcDeviceState, destDeviceState,
- mOpenHelper, oldHelper.getWritableDatabase(), isDestNewDb);
+ mOpenHelper, oldHelper.getWritableDatabase(), isDestNewDb, modelDelegate);
} catch (Exception e) {
resetLauncherDb(restoreEventLogger);
throw new Exception("attemptMigrateDb: Failed to migrate grid", e);
@@ -403,8 +404,9 @@
/**
* Migrates the DB if needed. If the migration failed, it clears the DB.
*/
- public void tryMigrateDB(@Nullable LauncherRestoreEventLogger restoreEventLogger) {
- if (!migrateGridIfNeeded()) {
+ public void tryMigrateDB(@Nullable LauncherRestoreEventLogger restoreEventLogger,
+ ModelDelegate modelDelegate) {
+ if (!migrateGridIfNeeded(modelDelegate)) {
if (restoreEventLogger != null) {
if (LauncherPrefs.get(mContext).get(NO_DB_FILES_RESTORED)) {
restoreEventLogger.logLauncherItemsRestoreFailed(DATA_TYPE_DB_FILE, 1,
@@ -434,7 +436,7 @@
* @return true if migration was success or ignored, false if migration failed
* and the DB should be reset.
*/
- private boolean migrateGridIfNeeded() {
+ private boolean migrateGridIfNeeded(ModelDelegate modelDelegate) {
createDbIfNotExists();
if (LauncherPrefs.get(mContext).get(getEmptyDbCreatedKey())) {
// If we have already create a new DB, ignore migration
@@ -468,7 +470,8 @@
DeviceGridState destDeviceState = new DeviceGridState(idp);
boolean isDestNewDb = !existingDBs.contains(destDeviceState.getDbFile());
return GridSizeMigrationDBController.migrateGridIfNeeded(mContext, srcDeviceState,
- destDeviceState, mOpenHelper, oldHelper.getWritableDatabase(), isDestNewDb);
+ destDeviceState, mOpenHelper, oldHelper.getWritableDatabase(), isDestNewDb,
+ modelDelegate);
} catch (Exception e) {
FileLog.e(TAG, "migrateGridIfNeeded: Failed to migrate grid", e);
return false;
diff --git a/src/com/android/launcher3/model/ModelDelegate.java b/src/com/android/launcher3/model/ModelDelegate.java
index 2264d35..5a2aef0 100644
--- a/src/com/android/launcher3/model/ModelDelegate.java
+++ b/src/com/android/launcher3/model/ModelDelegate.java
@@ -123,6 +123,11 @@
@WorkerThread
public void modelLoadComplete() { }
+ /** Called when grid migration has completed as part of grid size refactor. */
+ @WorkerThread
+ public void gridMigrationComplete(
+ @NonNull DeviceGridState src, @NonNull DeviceGridState dest) { }
+
/**
* Called when the delegate is no loner needed
*/
diff --git a/src/com/android/launcher3/shapes/AppShapesProvider.kt b/src/com/android/launcher3/shapes/AppShapesProvider.kt
deleted file mode 100644
index 3f4549a..0000000
--- a/src/com/android/launcher3/shapes/AppShapesProvider.kt
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.shapes
-
-import com.android.systemui.shared.Flags
-
-object AppShapesProvider {
-
- val shapes =
- if (Flags.newCustomizationPickerUi() && Flags.enableLauncherIconShapes())
- listOf(
- AppShape(
- "arch",
- "arch",
- "M100 83.46C100 85.471 100 86.476 99.9 87.321 99.116 93.916 93.916 99.116 87.321 99.9 86.476 100 85.471 100 83.46 100H16.54C14.529 100 13.524 100 12.679 99.9 6.084 99.116 .884 93.916 .1 87.321 0 86.476 0 85.471 0 83.46L0 50C0 22.386 22.386 0 50 0 77.614 0 100 22.386 100 50V83.46Z",
- ),
- AppShape(
- "4_sided_cookie",
- "4 sided cookie",
- "M63.605 3C84.733 -6.176 106.176 15.268 97 36.395L95.483 39.888C92.681 46.338 92.681 53.662 95.483 60.112L97 63.605C106.176 84.732 84.733 106.176 63.605 97L60.112 95.483C53.662 92.681 46.338 92.681 39.888 95.483L36.395 97C15.267 106.176 -6.176 84.732 3 63.605L4.517 60.112C7.319 53.662 7.319 46.338 4.517 39.888L3 36.395C -6.176 15.268 15.267 -6.176 36.395 3L39.888 4.517C46.338 7.319 53.662 7.319 60.112 4.517L63.605 3Z",
- ),
- AppShape(
- "seven_sided_cookie",
- "7 sided cookie",
- "M35.209 4.878C36.326 3.895 36.884 3.404 37.397 3.006 44.82 -2.742 55.18 -2.742 62.603 3.006 63.116 3.404 63.674 3.895 64.791 4.878 65.164 5.207 65.351 5.371 65.539 5.529 68.167 7.734 71.303 9.248 74.663 9.932 74.902 9.981 75.147 10.025 75.637 10.113 77.1 10.375 77.831 10.506 78.461 10.66 87.573 12.893 94.032 21.011 94.176 30.412 94.186 31.062 94.151 31.805 94.08 33.293 94.057 33.791 94.045 34.04 94.039 34.285 93.958 37.72 94.732 41.121 96.293 44.18 96.404 44.399 96.522 44.618 96.759 45.056 97.467 46.366 97.821 47.021 98.093 47.611 102.032 56.143 99.727 66.266 92.484 72.24 91.983 72.653 91.381 73.089 90.177 73.961 89.774 74.254 89.572 74.4 89.377 74.548 86.647 76.626 84.477 79.353 83.063 82.483 82.962 82.707 82.865 82.936 82.671 83.395 82.091 84.766 81.8 85.451 81.51 86.033 77.31 94.44 67.977 98.945 58.801 96.994 58.166 96.859 57.451 96.659 56.019 96.259 55.54 96.125 55.3 96.058 55.063 95.998 51.74 95.154 48.26 95.154 44.937 95.998 44.699 96.058 44.46 96.125 43.981 96.259 42.549 96.659 41.834 96.859 41.199 96.994 32.023 98.945 22.69 94.44 18.49 86.033 18.2 85.451 17.909 84.766 17.329 83.395 17.135 82.936 17.038 82.707 16.937 82.483 15.523 79.353 13.353 76.626 10.623 74.548 10.428 74.4 10.226 74.254 9.823 73.961 8.619 73.089 8.017 72.653 7.516 72.24 .273 66.266 -2.032 56.143 1.907 47.611 2.179 47.021 2.533 46.366 3.241 45.056 3.478 44.618 3.596 44.399 3.707 44.18 5.268 41.121 6.042 37.72 5.961 34.285 5.955 34.04 5.943 33.791 5.92 33.293 5.849 31.805 5.814 31.062 5.824 30.412 5.968 21.011 12.427 12.893 21.539 10.66 22.169 10.506 22.9 10.375 24.363 10.113 24.853 10.025 25.098 9.981 25.337 9.932 28.697 9.248 31.833 7.734 34.461 5.529 34.649 5.371 34.836 5.207 35.209 4.878Z",
- ),
- AppShape(
- "sunny",
- "sunny",
- "M42.846 4.873C46.084 -.531 53.916 -.531 57.154 4.873L60.796 10.951C62.685 14.103 66.414 15.647 69.978 14.754L76.851 13.032C82.962 11.5 88.5 17.038 86.968 23.149L85.246 30.022C84.353 33.586 85.897 37.315 89.049 39.204L95.127 42.846C100.531 46.084 100.531 53.916 95.127 57.154L89.049 60.796C85.897 62.685 84.353 66.414 85.246 69.978L86.968 76.851C88.5 82.962 82.962 88.5 76.851 86.968L69.978 85.246C66.414 84.353 62.685 85.898 60.796 89.049L57.154 95.127C53.916 100.531 46.084 100.531 42.846 95.127L39.204 89.049C37.315 85.898 33.586 84.353 30.022 85.246L23.149 86.968C17.038 88.5 11.5 82.962 13.032 76.851L14.754 69.978C15.647 66.414 14.103 62.685 10.951 60.796L4.873 57.154C-.531 53.916 -.531 46.084 4.873 42.846L10.951 39.204C14.103 37.315 15.647 33.586 14.754 30.022L13.032 23.149C11.5 17.038 17.038 11.5 23.149 13.032L30.022 14.754C33.586 15.647 37.315 14.103 39.204 10.951L42.846 4.873Z",
- ),
- AppShape(
- "circle",
- "circle",
- "M99.18 50C99.18 77.162 77.162 99.18 50 99.18 22.838 99.18.82 77.162.82 50 .82 22.839 22.838.82 50 .82 77.162.82 99.18 22.839 99.18 50Z",
- ),
- AppShape(
- "square",
- "square",
- "M99.18 53.689C99.18 67.434 99.18 74.306 97.022 79.758 93.897 87.649 87.649 93.897 79.758 97.022 74.306 99.18 67.434 99.18 53.689 99.18H46.311C32.566 99.18 25.694 99.18 20.242 97.022 12.351 93.897 6.103 87.649 2.978 79.758 .82 74.306 .82 67.434 .82 53.689L.82 46.311C.82 32.566 .82 25.694 2.978 20.242 6.103 12.351 12.351 6.103 20.242 2.978 25.694 .82 32.566 .82 46.311 .82L53.689 .82C67.434 .82 74.306 .82 79.758 2.978 87.649 6.103 93.897 12.351 97.022 20.242 99.18 25.694 99.18 32.566 99.18 46.311V53.689Z",
- ),
- )
- else if (Flags.newCustomizationPickerUi() && !Flags.enableLauncherIconShapes())
- listOf(
- AppShape(
- "circle",
- "circle",
- "M99.18 50C99.18 77.162 77.162 99.18 50 99.18 22.838 99.18.82 77.162.82 50 .82 22.839 22.838.82 50 .82 77.162.82 99.18 22.839 99.18 50Z",
- )
- )
- else emptyList()
-}
diff --git a/src/com/android/launcher3/shapes/AppShape.kt b/src/com/android/launcher3/shapes/IconShapeModel.kt
similarity index 88%
rename from src/com/android/launcher3/shapes/AppShape.kt
rename to src/com/android/launcher3/shapes/IconShapeModel.kt
index 68200a0..10b7f91 100644
--- a/src/com/android/launcher3/shapes/AppShape.kt
+++ b/src/com/android/launcher3/shapes/IconShapeModel.kt
@@ -16,4 +16,4 @@
package com.android.launcher3.shapes
-class AppShape(val key: String, val title: String, val path: String)
+data class IconShapeModel(val key: String, val title: String, val pathString: String)
diff --git a/src/com/android/launcher3/shapes/IconShapesProvider.kt b/src/com/android/launcher3/shapes/IconShapesProvider.kt
new file mode 100644
index 0000000..a190e22
--- /dev/null
+++ b/src/com/android/launcher3/shapes/IconShapesProvider.kt
@@ -0,0 +1,78 @@
+/*
+ * 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.shapes
+
+import com.android.launcher3.Flags as LauncherFlags
+import com.android.systemui.shared.Flags
+
+object IconShapesProvider {
+ val shapes =
+ if (Flags.newCustomizationPickerUi() && LauncherFlags.enableLauncherIconShapes()) {
+ mapOf(
+ "arch" to
+ IconShapeModel(
+ key = "arch",
+ title = "arch",
+ pathString =
+ "M50 0C77.614 0 100 22.386 100 50C100 85.471 100 86.476 99.9 87.321 99.116 93.916 93.916 99.116 87.321 99.9 86.476 100 85.471 100 83.46 100H16.54C14.529 100 13.524 100 12.679 99.9 6.084 99.116.884 93.916.1 87.321 0 86.476 0 85.471 0 83.46L0 50C0 22.386 22.386 0 50 0Z",
+ ),
+ "4_sided_cookie" to
+ IconShapeModel(
+ key = "4_sided_cookie",
+ title = "4 sided cookie",
+ pathString =
+ "M39.888,4.517C46.338 7.319 53.662 7.319 60.112 4.517L63.605 3C84.733 -6.176 106.176 15.268 97 36.395L95.483 39.888C92.681 46.338 92.681 53.662 95.483 60.112L97 63.605C106.176 84.732 84.733 106.176 63.605 97L60.112 95.483C53.662 92.681 46.338 92.681 39.888 95.483L36.395 97C15.267 106.176 -6.176 84.732 3 63.605L4.517 60.112C7.319 53.662 7.319 46.338 4.517 39.888L3 36.395C -6.176 15.268 15.267 -6.176 36.395 3Z",
+ ),
+ "seven_sided_cookie" to
+ IconShapeModel(
+ key = "seven_sided_cookie",
+ title = "7 sided cookie",
+ pathString =
+ "M35.209 4.878C36.326 3.895 36.884 3.404 37.397 3.006 44.82 -2.742 55.18 -2.742 62.603 3.006 63.116 3.404 63.674 3.895 64.791 4.878 65.164 5.207 65.351 5.371 65.539 5.529 68.167 7.734 71.303 9.248 74.663 9.932 74.902 9.981 75.147 10.025 75.637 10.113 77.1 10.375 77.831 10.506 78.461 10.66 87.573 12.893 94.032 21.011 94.176 30.412 94.186 31.062 94.151 31.805 94.08 33.293 94.057 33.791 94.045 34.04 94.039 34.285 93.958 37.72 94.732 41.121 96.293 44.18 96.404 44.399 96.522 44.618 96.759 45.056 97.467 46.366 97.821 47.021 98.093 47.611 102.032 56.143 99.727 66.266 92.484 72.24 91.983 72.653 91.381 73.089 90.177 73.961 89.774 74.254 89.572 74.4 89.377 74.548 86.647 76.626 84.477 79.353 83.063 82.483 82.962 82.707 82.865 82.936 82.671 83.395 82.091 84.766 81.8 85.451 81.51 86.033 77.31 94.44 67.977 98.945 58.801 96.994 58.166 96.859 57.451 96.659 56.019 96.259 55.54 96.125 55.3 96.058 55.063 95.998 51.74 95.154 48.26 95.154 44.937 95.998 44.699 96.058 44.46 96.125 43.981 96.259 42.549 96.659 41.834 96.859 41.199 96.994 32.023 98.945 22.69 94.44 18.49 86.033 18.2 85.451 17.909 84.766 17.329 83.395 17.135 82.936 17.038 82.707 16.937 82.483 15.523 79.353 13.353 76.626 10.623 74.548 10.428 74.4 10.226 74.254 9.823 73.961 8.619 73.089 8.017 72.653 7.516 72.24.273 66.266 -2.032 56.143 1.907 47.611 2.179 47.021 2.533 46.366 3.241 45.056 3.478 44.618 3.596 44.399 3.707 44.18 5.268 41.121 6.042 37.72 5.961 34.285 5.955 34.04 5.943 33.791 5.92 33.293 5.849 31.805 5.814 31.062 5.824 30.412 5.968 21.011 12.427 12.893 21.539 10.66 22.169 10.506 22.9 10.375 24.363 10.113 24.853 10.025 25.098 9.981 25.337 9.932 28.697 9.248 31.833 7.734 34.461 5.529 34.649 5.371 34.836 5.207 35.209 4.878Z",
+ ),
+ "sunny" to
+ IconShapeModel(
+ key = "sunny",
+ title = "sunny",
+ pathString =
+ "M42.846 4.873C46.084 -.531 53.916 -.531 57.154 4.873L60.796 10.951C62.685 14.103 66.414 15.647 69.978 14.754L76.851 13.032C82.962 11.5 88.5 17.038 86.968 23.149L85.246 30.022C84.353 33.586 85.897 37.315 89.049 39.204L95.127 42.846C100.531 46.084 100.531 53.916 95.127 57.154L89.049 60.796C85.897 62.685 84.353 66.414 85.246 69.978L86.968 76.851C88.5 82.962 82.962 88.5 76.851 86.968L69.978 85.246C66.414 84.353 62.685 85.898 60.796 89.049L57.154 95.127C53.916 100.531 46.084 100.531 42.846 95.127L39.204 89.049C37.315 85.898 33.586 84.353 30.022 85.246L23.149 86.968C17.038 88.5 11.5 82.962 13.032 76.851L14.754 69.978C15.647 66.414 14.103 62.685 10.951 60.796L4.873 57.154C -.531 53.916 -.531 46.084 4.873 42.846L10.951 39.204C14.103 37.315 15.647 33.586 14.754 30.022L13.032 23.149C11.5 17.038 17.038 11.5 23.149 13.032L30.022 14.754C33.586 15.647 37.315 14.103 39.204 10.951L42.846 4.873Z",
+ ),
+ "circle" to
+ IconShapeModel(
+ key = "circle",
+ title = "circle",
+ pathString = "M50 0A50 50,0,1,1,50 100A50 50,0,1,1,50 0",
+ ),
+ "square" to
+ IconShapeModel(
+ key = "square",
+ title = "square",
+ pathString =
+ "M53.689 0.82L53.689.82C67.434.82 74.306.82 79.758 2.978 87.649 6.103 93.897 12.351 97.022 20.242 99.18 25.694 99.18 32.566 99.18 46.311V53.689C99.18 67.434 99.18 74.306 97.022 79.758 93.897 87.649 87.649 93.897 79.758 97.022 74.306 99.18 67.434 99.18 53.689 99.18H46.311C32.566 99.18 25.694 99.18 20.242 97.022 12.351 93.897 6.103 87.649 2.978 79.758.82 74.306.82 67.434.82 53.689L.82 46.311C.82 32.566.82 25.694 2.978 20.242 6.103 12.351 12.351 6.103 20.242 2.978 25.694.82 32.566.82 46.311.82Z",
+ ),
+ )
+ } else {
+ mapOf(
+ "circle" to
+ IconShapeModel(
+ key = "circle",
+ title = "circle",
+ pathString = "M50 0A50 50,0,1,1,50 100A50 50,0,1,1,50 0",
+ )
+ )
+ }
+}
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index cde72c1..daa6e67 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -22,7 +22,6 @@
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
import static com.android.launcher3.config.FeatureFlags.enableAppPairs;
-import static com.android.launcher3.config.FeatureFlags.enableSplitContextually;
import static com.android.launcher3.testing.shared.TestProtocol.TEST_INFO_RESPONSE_FIELD;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -245,8 +244,8 @@
}
case TestProtocol.REQUEST_GET_SPLIT_SELECTION_ACTIVE:
- response.putBoolean(TEST_INFO_RESPONSE_FIELD, enableSplitContextually()
- && Launcher.ACTIVITY_TRACKER.getCreatedContext().isSplitSelectionActive());
+ response.putBoolean(TEST_INFO_RESPONSE_FIELD,
+ Launcher.ACTIVITY_TRACKER.getCreatedContext().isSplitSelectionActive());
return response;
case TestProtocol.REQUEST_ENABLE_ROTATION:
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index 89057a2..98ba8c7 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -188,7 +188,7 @@
// Return early if an item is already being dragged (e.g. when long-pressing two shortcuts)
if (launcher.getDragController().isDragging()) return false;
// Return early if user is in the middle of selecting split-screen apps
- if (FeatureFlags.enableSplitContextually() && launcher.isSplitSelectionActive()) {
+ if (launcher.isSplitSelectionActive()) {
return false;
}
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index 0ff10c2..b69bc17 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -207,7 +207,7 @@
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
mLauncher.getStatsLogManager().logger().log(LAUNCHER_WORKSPACE_LONGPRESS);
mLauncher.showDefaultOptions(mTouchDownPoint.x, mTouchDownPoint.y);
- if (FeatureFlags.enableSplitContextually() && mLauncher.isSplitSelectionActive()) {
+ if (mLauncher.isSplitSelectionActive()) {
mLauncher.dismissSplitSelection(LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED);
}
} else {
diff --git a/src/com/android/launcher3/util/MultiTranslateDelegate.java b/src/com/android/launcher3/util/MultiTranslateDelegate.java
index 38c87c8..ce006c4 100644
--- a/src/com/android/launcher3/util/MultiTranslateDelegate.java
+++ b/src/com/android/launcher3/util/MultiTranslateDelegate.java
@@ -38,6 +38,7 @@
public static final int INDEX_TASKBAR_REVEAL_ANIM = 4;
public static final int INDEX_TASKBAR_PINNING_ANIM = 5;
public static final int INDEX_NAV_BAR_ANIM = 6;
+ public static final int INDEX_BUBBLE_BAR_ANIM = 7;
// Affect all items inside of a MultipageCellLayout
public static final int INDEX_CELLAYOUT_MULTIPAGE_SPACING = 3;
@@ -48,7 +49,7 @@
// Specific for hotseat items when adjusting for bubbles
public static final int INDEX_BUBBLE_ADJUSTMENT_ANIM = 3;
- public static final int COUNT = 7;
+ public static final int COUNT = 8;
private final MultiPropertyFactory<View> mTranslationX;
private final MultiPropertyFactory<View> mTranslationY;
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 6739387..22857b1 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -465,8 +465,7 @@
bounds.inset(blurSizeOutline / 2, blurSizeOutline / 2);
try (LauncherIcons li = LauncherIcons.obtain(l)) {
- Utilities.scaleRectAboutCenter(bounds, li.getNormalizer().getScale(drawable, null,
- null, null));
+ Utilities.scaleRectAboutCenter(bounds, li.getNormalizer().getScale(drawable));
}
bounds.inset(
diff --git a/tests/multivalentTests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt b/tests/multivalentTests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
index 954dc8f..bfbdb18 100644
--- a/tests/multivalentTests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
@@ -58,7 +58,7 @@
@Rule @JvmField val limitDevicesRule = LimitDevicesRule()
@Before
- fun setUp() {
+ open fun setUp() {
context = ApplicationProvider.getApplicationContext()
// make sure to reset values
useTwoPanels = false
@@ -83,7 +83,7 @@
protected fun initializeVarsForPhone(
isGestureMode: Boolean = true,
- isVerticalBar: Boolean = false
+ isVerticalBar: Boolean = false,
) {
val (x, y) = if (isVerticalBar) Pair(2400, 1080) else Pair(1080, 2400)
@@ -94,8 +94,8 @@
if (isVerticalBar) 118 else 0,
if (isVerticalBar) 74 else 118,
if (!isGestureMode && isVerticalBar) 126 else 0,
- if (isGestureMode) 63 else if (isVerticalBar) 0 else 126
- )
+ if (isGestureMode) 63 else if (isVerticalBar) 0 else 126,
+ ),
)
whenever(info.isTablet(any())).thenReturn(false)
@@ -121,7 +121,7 @@
PointF(80f, 104f),
PointF(80f, 104f),
PointF(80f, 104f),
- PointF(80f, 104f)
+ PointF(80f, 104f),
)
.toTypedArray()
@@ -143,7 +143,7 @@
PointF(80f, 104f),
PointF(80f, 104f),
PointF(80f, 104f),
- PointF(80f, 104f)
+ PointF(80f, 104f),
)
.toTypedArray()
allAppsIconSize = floatArrayOf(60f, 60f, 60f, 60f)
@@ -174,7 +174,7 @@
protected fun initializeVarsForTablet(
isLandscape: Boolean = false,
- isGestureMode: Boolean = true
+ isGestureMode: Boolean = true,
) {
val (x, y) = if (isLandscape) Pair(2560, 1600) else Pair(1600, 2560)
@@ -203,7 +203,7 @@
PointF(102f, 120f),
PointF(120f, 104f),
PointF(102f, 120f),
- PointF(102f, 120f)
+ PointF(102f, 120f),
)
.toTypedArray()
@@ -225,7 +225,7 @@
PointF(96f, 142f),
PointF(126f, 126f),
PointF(96f, 142f),
- PointF(96f, 142f)
+ PointF(96f, 142f),
)
.toTypedArray()
allAppsIconSize = FloatArray(4) { 60f }
@@ -288,7 +288,7 @@
PointF(80f, 104f),
PointF(80f, 104f),
PointF(68f, 116f),
- PointF(80f, 102f)
+ PointF(80f, 102f),
)
.toTypedArray()
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
index a9082e2..47110fa 100644
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
@@ -61,9 +61,11 @@
ModelDbController controller = model.getModelDbController();
// Migrate any previous data so that the DB state is correct
if (Flags.gridMigrationRefactor()) {
- controller.attemptMigrateDb(null /* restoreEventLogger */);
+ controller.attemptMigrateDb(
+ null /* restoreEventLogger */, model.getModelDelegate());
} else {
- controller.tryMigrateDB(null /* restoreEventLogger */);
+ controller.tryMigrateDB(null /* restoreEventLogger */,
+ model.getModelDelegate());
}
// Create DB again to load fresh data
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt b/tests/multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt
index 8d072d8..547d05e 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt
@@ -31,8 +31,9 @@
loadModelSync()
TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
modelDbController.run {
- if (Flags.gridMigrationRefactor()) attemptMigrateDb(null /* restoreEventLogger */)
- else tryMigrateDB(null /* restoreEventLogger */)
+ if (Flags.gridMigrationRefactor())
+ attemptMigrateDb(null /* restoreEventLogger */, modelDelegate)
+ else tryMigrateDB(null /* restoreEventLogger */, modelDelegate)
createEmptyDB()
clearEmptyDbFlag()
}
@@ -74,7 +75,7 @@
loadModelSync()
TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
val controller: ModelDbController = modelDbController
- controller.attemptMigrateDb(null /* restoreEventLogger */)
+ controller.attemptMigrateDb(null /* restoreEventLogger */, modelDelegate)
modelDbController.newTransaction().use { transaction ->
val values =
ContentValues().apply {
diff --git a/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt b/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt
index b4ee090..38fad6b 100644
--- a/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt
+++ b/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt
@@ -25,6 +25,7 @@
import com.android.launcher3.Flags
import com.android.launcher3.LauncherPrefs
import com.android.launcher3.model.ModelDbController
+import com.android.launcher3.model.ModelDelegate
import com.android.launcher3.provider.RestoreDbTask
import com.android.launcher3.util.Executors.MODEL_EXECUTOR
import com.android.launcher3.util.TestUtil
@@ -34,6 +35,7 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
/**
* Makes sure to test {@code RestoreDbTask#removeOldDBs}, we need to remove all the dbs that are not
@@ -49,6 +51,8 @@
@Rule
val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT)
+ val modelDelegate = mock<ModelDelegate>()
+
@Before
fun setUp() {
setFlagsRule.setFlags(true, Flags.FLAG_ENABLE_NARROW_GRID_RESTORE)
@@ -68,9 +72,9 @@
fun oldDatabasesNotPresentAfterRestore() {
val dbController = ModelDbController(getInstrumentation().targetContext)
if (Flags.gridMigrationRefactor()) {
- dbController.attemptMigrateDb(null)
+ dbController.attemptMigrateDb(null, modelDelegate)
} else {
- dbController.tryMigrateDB(null)
+ dbController.tryMigrateDB(null, modelDelegate)
}
TestUtil.runOnExecutorSync(MODEL_EXECUTOR) {
assert(backAndRestoreRule.getDatabaseFiles().size == 1) {
diff --git a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
index 20684b3..f6aa31a 100644
--- a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
@@ -55,7 +55,6 @@
*/
@Test
@PortraitLandscape
- @ScreenRecordRule.ScreenRecord // b/349439239
public void testDeleteFromWorkspace() {
for (String appName : new String[]{GMAIL_APP_NAME, STORE_APP_NAME, TEST_APP_NAME}) {
final HomeAppIcon homeAppIcon = createShortcutInCenterIfNotExist(appName);
diff --git a/tests/src/com/android/launcher3/model/GridMigrationTest.kt b/tests/src/com/android/launcher3/model/GridMigrationTest.kt
index b8ffe74..8bd0c60 100644
--- a/tests/src/com/android/launcher3/model/GridMigrationTest.kt
+++ b/tests/src/com/android/launcher3/model/GridMigrationTest.kt
@@ -32,6 +32,8 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
private val phoneContext = InstrumentationRegistry.getInstrumentation().targetContext
@@ -87,6 +89,8 @@
@Rule
val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT)
+ val modelDelegate = mock<ModelDelegate>()
+
@Before
fun setup() {
setFlagsRule.setFlags(true, Flags.FLAG_ONE_GRID_SPECS)
@@ -102,6 +106,7 @@
dst.dbHelper,
src.dbHelper.readableDatabase,
true,
+ modelDelegate,
)
} else {
GridSizeMigrationDBController.migrateGridIfNeeded(
@@ -111,6 +116,7 @@
dst.dbHelper,
src.dbHelper.readableDatabase,
true,
+ modelDelegate,
)
}
}
@@ -149,11 +155,12 @@
}
/**
- * Migrate src into dst and compare to target. This method validates 3 things:
+ * Migrate src into dst and compare to target. This method validates 4 things:
* 1. dst has the same number of items as src after the migration, meaning, none of the items
* were removed during the migration.
* 2. dst is valid, meaning that none of the items overlap with each other.
* 3. dst is equal to target to ensure we don't unintentionally change the migration logic.
+ * 4. migration notifies the complete callback.
*/
private fun runTest(src: GridMigrationData, dst: GridMigrationData, target: GridMigrationData) {
migrate(src, dst)
@@ -162,6 +169,7 @@
}
validateDb(dst)
compare(dst, target, src)
+ verify(modelDelegate).gridMigrationComplete(src.gridState, dst.gridState)
}
// Copying the src db for all tests.
diff --git a/tests/src/com/android/launcher3/tablet/TaplIsTabletTest.kt b/tests/src/com/android/launcher3/tablet/TaplIsTabletTest.kt
deleted file mode 100644
index a6de607..0000000
--- a/tests/src/com/android/launcher3/tablet/TaplIsTabletTest.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.tablet
-
-import android.platform.test.rule.AllowedDevices
-import android.platform.test.rule.DeviceProduct
-import com.android.launcher3.Launcher
-import com.android.launcher3.ui.AbstractLauncherUiTest
-import junit.framework.TestCase.assertFalse
-import junit.framework.TestCase.assertTrue
-import org.junit.Test
-
-class TaplIsTabletTest : AbstractLauncherUiTest<Launcher>() {
-
- /** Investigating b/366237798 by isolating and seeing flake rate of mLauncher.isTablet */
- @Test
- @AllowedDevices(
- DeviceProduct.CF_FOLDABLE,
- DeviceProduct.CF_TABLET,
- DeviceProduct.TANGORPRO,
- DeviceProduct.FELIX,
- DeviceProduct.COMET,
- )
- fun isTabletShouldBeTrue() {
- assertTrue(mLauncher.isTablet)
- }
-
- /** Investigating b/366237798 by isolating and seeing flake rate of mLauncher.isTablet */
- @Test
- @AllowedDevices(DeviceProduct.CF_PHONE, DeviceProduct.CHEETAH)
- fun isTabletShouldBeFalse() {
- assertFalse(mLauncher.isTablet)
- }
-}
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
index 460ffc4..3e3e643 100644
--- a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
@@ -51,7 +51,6 @@
@Test
@PortraitLandscape
public void testDragIcon() throws Throwable {
- mLauncher.enableDebugTracing(); // b/289161193
commitTransactionAndLoadHome(new FavoriteItemsTransaction(mTargetContext));
waitForLauncherCondition("Workspace didn't finish loading", l -> !l.isWorkspaceLoading());
@@ -72,7 +71,6 @@
TestUtil.DEFAULT_UI_TIMEOUT);
assertNotNull("Widget not found on the workspace", widget);
widget.launch(getAppPackageName());
- mLauncher.disableDebugTracing(); // b/289161193
}
/**
diff --git a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
index 2edd129..e544b19 100644
--- a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
@@ -37,7 +37,6 @@
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
import com.android.launcher3.util.LauncherLayoutBuilder;
import com.android.launcher3.util.TestUtil;
-import com.android.launcher3.util.rule.ScreenRecordRule;
import org.junit.After;
import org.junit.Before;
@@ -283,7 +282,6 @@
@Test
@PortraitLandscape
- @ScreenRecordRule.ScreenRecord // b/330232490
public void testEmptyPagesGetRemovedIfBothPagesAreEmpty() {
Workspace workspace = mLauncher.getWorkspace();