Merge "Fix back button sometimes not showing up in the initial setup screen" into main
diff --git a/go/quickstep/res/layout/overview_actions_container.xml b/go/quickstep/res/layout/overview_actions_container.xml
index df09124..b1a6202 100644
--- a/go/quickstep/res/layout/overview_actions_container.xml
+++ b/go/quickstep/res/layout/overview_actions_container.xml
@@ -121,6 +121,17 @@
android:layout_weight="1"
android:visibility="gone" />
+ </LinearLayout>
+
+ <!-- Unused. Included only for compatibility with parent class. -->
+ <LinearLayout
+ android:id="@+id/group_action_buttons"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/overview_actions_height"
+ android:layout_gravity="top|center_horizontal"
+ android:orientation="horizontal"
+ android:visibility="gone">
+
<Button
android:id="@+id/action_save_app_pair"
style="@style/GoOverviewActionButton"
@@ -128,8 +139,8 @@
android:layout_height="wrap_content"
android:drawableStart="@drawable/ic_save_app_pair_up_down"
android:text="@string/action_save_app_pair"
- android:theme="@style/ThemeControlHighlightWorkspaceColor"
- android:visibility="gone" />
+ android:theme="@style/ThemeControlHighlightWorkspaceColor" />
+
</LinearLayout>
</com.android.quickstep.views.GoOverviewActionsView>
\ No newline at end of file
diff --git a/quickstep/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml
index d086da4..7aaf744 100644
--- a/quickstep/res/layout/overview_actions_container.xml
+++ b/quickstep/res/layout/overview_actions_container.xml
@@ -45,14 +45,24 @@
android:theme="@style/ThemeControlHighlightWorkspaceColor"
android:visibility="gone" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/group_action_buttons"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/overview_actions_height"
+ android:layout_gravity="bottom|center_horizontal"
+ android:orientation="horizontal"
+ android:visibility="gone">
+
<Button
android:id="@+id/action_save_app_pair"
style="@style/OverviewActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/action_save_app_pair"
- android:theme="@style/ThemeControlHighlightWorkspaceColor"
- android:visibility="gone" />
+ android:theme="@style/ThemeControlHighlightWorkspaceColor" />
+
</LinearLayout>
</com.android.quickstep.views.OverviewActionsView>
\ No newline at end of file
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 9f648a7..cc3b30e 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -28,10 +28,7 @@
launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
launcher:hoverBorderColor="?androidprv:attr/materialColorPrimary">
- <com.android.quickstep.views.TaskThumbnailViewDeprecated
- android:id="@+id/snapshot"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
+ <include layout="@layout/task_thumbnail" />
<!-- Filtering affects only alpha instead of the visibility since visibility can be altered
separately through RecentsView#resetFromSplitSelectionState() -->
diff --git a/quickstep/res/layout/task_desktop.xml b/quickstep/res/layout/task_desktop.xml
index 36d7f86..89e9b3d 100644
--- a/quickstep/res/layout/task_desktop.xml
+++ b/quickstep/res/layout/task_desktop.xml
@@ -42,10 +42,7 @@
views that do not inherint from TaskView only or create a generic TaskView that have
N number of tasks.
-->
- <com.android.quickstep.views.TaskThumbnailViewDeprecated
- android:id="@+id/snapshot"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ <include layout="@layout/task_thumbnail"
android:visibility="gone" />
<ViewStub
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index ec657bd..87a0f70 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -33,15 +33,10 @@
launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
launcher:hoverBorderColor="?androidprv:attr/materialColorPrimary">
- <com.android.quickstep.views.TaskThumbnailViewDeprecated
- android:id="@+id/snapshot"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
+ <include layout="@layout/task_thumbnail"/>
- <com.android.quickstep.views.TaskThumbnailViewDeprecated
- android:id="@+id/bottomright_snapshot"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
+ <include layout="@layout/task_thumbnail"
+ android:id="@+id/bottomright_snapshot" />
<!-- Filtering affects only alpha instead of the visibility since visibility can be altered
separately through RecentsView#resetFromSplitSelectionState() -->
diff --git a/quickstep/res/layout/task_thumbnail.xml b/quickstep/res/layout/task_thumbnail.xml
new file mode 100644
index 0000000..f1a3d62
--- /dev/null
+++ b/quickstep/res/layout/task_thumbnail.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.quickstep.views.TaskThumbnailViewDeprecated
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/snapshot"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
\ No newline at end of file
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 5097ff9..af35fc3 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -95,7 +95,7 @@
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Einstellungen der Systemsteuerung"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Teilen"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
- <string name="action_split" msgid="2098009717623550676">"Teilen"</string>
+ <string name="action_split" msgid="2098009717623550676">"Splitscreen"</string>
<string name="action_save_app_pair" msgid="5974823919237645229">"App-Paar speichern"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Für Splitscreen auf weitere App tippen"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Für Splitscreen andere App auswählen"</string>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 159226e..0d43f1e 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -118,7 +118,7 @@
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostrar siempre la barra de tareas"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Para mostrar siempre la barra de tareas en la parte inferior, mantén pulsada la línea divisoria"</string>
<string name="taskbar_search_edu_title" msgid="5569194922234364530">"Mantén pulsada la tecla de acción para buscar lo que ves en pantalla"</string>
- <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"El producto usa la parte seleccionada de tu pantalla para hacer búsquedas. Se aplican la <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Política de Privacidad<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> y los <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Términos del Servicio<xliff:g id="END_TOS_LINK"></a></xliff:g> de Google."</string>
+ <string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Este producto usa la parte seleccionada de tu pantalla para hacer búsquedas. Se aplican la <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Política de Privacidad<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> y los <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Términos del Servicio<xliff:g id="END_TOS_LINK"></a></xliff:g> de Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Cerrar"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Hecho"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Inicio"</string>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 766dabb..c445bc8 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -95,7 +95,7 @@
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Süsteemi navigeerimisseaded"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Jaga"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Ekraanipilt"</string>
- <string name="action_split" msgid="2098009717623550676">"Eralda"</string>
+ <string name="action_split" msgid="2098009717623550676">"Jaga pooleks"</string>
<string name="action_save_app_pair" msgid="5974823919237645229">"Salvesta rakendusepaar"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Jagatud ekraanikuva kasutamiseks puudutage muud rakendust"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Valige jagatud ekraanikuva jaoks muu rakendus."</string>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index b0694c1..040976d 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -95,7 +95,7 @@
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Järjestelmän navigointiasetukset"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Jaa"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Kuvakaappaus"</string>
- <string name="action_split" msgid="2098009717623550676">"Jaa"</string>
+ <string name="action_split" msgid="2098009717623550676">"Jaettu näyttö"</string>
<string name="action_save_app_pair" msgid="5974823919237645229">"Tallenna pari"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Avaa jaettu näyttö napauttamalla toista sovellusta"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Käytä jaettua näyttöä valitsemalla toinen sovellus"</string>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index e696faf..ecde5a3 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -95,7 +95,7 @@
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"စနစ် လမ်းညွှန် ဆက်တင်များ"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"မျှဝေရန်"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
- <string name="action_split" msgid="2098009717623550676">"ခွဲထုတ်ရန်"</string>
+ <string name="action_split" msgid="2098009717623550676">"ခွဲရန်"</string>
<string name="action_save_app_pair" msgid="5974823919237645229">"အက်ပ်အတွဲ သိမ်းရန်"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"မျက်နှာပြင် ခွဲ၍ပြသရန် အက်ပ်နောက်တစ်ခုကို တို့ပါ"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းသုံးရန် နောက်အက်ပ်တစ်ခုရွေးပါ"</string>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index 1086f9f..727f3e7 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -95,7 +95,7 @@
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"系统导航设置"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"分享"</string>
<string name="action_screenshot" msgid="8171125848358142917">"屏幕截图"</string>
- <string name="action_split" msgid="2098009717623550676">"拆分"</string>
+ <string name="action_split" msgid="2098009717623550676">"分屏"</string>
<string name="action_save_app_pair" msgid="5974823919237645229">"保存应用组合"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"点按另一个应用即可使用分屏"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"另外选择一个应用才可使用分屏模式"</string>
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 2e78489..32e4097 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -44,7 +44,7 @@
import com.android.quickstep.util.TISBindHelper;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
+import com.android.quickstep.views.TaskView.TaskContainer;
import com.android.systemui.shared.recents.model.Task;
import java.io.PrintWriter;
@@ -259,14 +259,14 @@
if (foundTaskView != null) {
// There is already a running app of this type, use that as second app.
// Get index of task (0 or 1), in case it's a GroupedTaskView
- TaskIdAttributeContainer taskAttributes =
- foundTaskView.getTaskAttributesById(foundTask.key.id);
+ TaskContainer taskContainer =
+ foundTaskView.getTaskContainerById(foundTask.key.id);
recents.confirmSplitSelect(
foundTaskView,
foundTask,
- taskAttributes.getIconView().getDrawable(),
- taskAttributes.getThumbnailView(),
- taskAttributes.getThumbnailView().getThumbnail(),
+ taskContainer.getIconView().getDrawable(),
+ taskContainer.getThumbnailView(),
+ taskContainer.getThumbnailView().getThumbnail(),
null /* intent */,
null /* user */,
info);
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
index 90c3ea7..a59e81b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
@@ -158,6 +158,7 @@
override fun setAlpha(alpha: Int) {
paint.alpha = alpha
arrowDrawable.alpha = alpha
+ invalidateSelf()
}
override fun getAlpha(): Int {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index 66e5302..8c83508 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -403,9 +403,6 @@
}
if (bubbleToSelect != null) {
setSelectedBubbleInternal(bubbleToSelect);
- if (previouslySelectedBubble == null) {
- mBubbleStashController.animateToInitialState(update.expanded);
- }
}
if (update.shouldShowEducation) {
mBubbleBarViewController.prepareToShowEducation();
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index de93ba5..4334807 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -98,23 +98,6 @@
private static final float FADE_IN_ANIM_POSITION_SHIFT = 1 / 60f;
/**
- * Custom property to set translationX value for the bar view while a bubble is being dragged.
- * Skips applying translation to the dragged bubble.
- */
- private static final FloatProperty<BubbleBarView> BUBBLE_DRAG_TRANSLATION_X =
- new FloatProperty<>("bubbleDragTranslationX") {
- @Override
- public void setValue(BubbleBarView bubbleBarView, float translationX) {
- bubbleBarView.setTranslationXDuringBubbleDrag(translationX);
- }
-
- @Override
- public Float get(BubbleBarView bubbleBarView) {
- return bubbleBarView.mTranslationXDuringDrag;
- }
- };
-
- /**
* Custom property to set alpha value for the bar view while a bubble is being dragged.
* Skips applying alpha to the dragged bubble.
*/
@@ -189,8 +172,7 @@
@Nullable
private BubbleView mDraggedBubbleView;
- private float mTranslationXDuringDrag = 0f;
- private float mAlphaDuringDrag = 0f;
+ private float mAlphaDuringDrag = 1f;
private int mPreviousLayoutDirection = LayoutDirection.UNDEFINED;
@@ -264,6 +246,17 @@
});
}
+ @Override
+ public void setTranslationX(float translationX) {
+ super.setTranslationX(translationX);
+ if (mDraggedBubbleView != null) {
+ // Apply reverse of the translation as an offset to the dragged view. This ensures
+ // that the dragged bubble stays at the current location on the screen and its
+ // position is not affected by the parent translation.
+ mDraggedBubbleView.setOffsetX(-translationX);
+ }
+ }
+
/**
* Sets new icon size and spacing between icons and bubble bar borders.
*
@@ -322,11 +315,9 @@
final boolean onLeft = mBubbleBarLocation.isOnLeft(isLayoutRtl());
mBubbleBarBackground.setAnchorLeft(onLeft);
mRelativePivotX = onLeft ? 0f : 1f;
- if (getLayoutParams() instanceof LayoutParams lp) {
- lp.gravity = Gravity.BOTTOM | (onLeft ? Gravity.LEFT : Gravity.RIGHT);
- setLayoutParams(lp);
- }
- invalidate();
+ LayoutParams lp = (LayoutParams) getLayoutParams();
+ lp.gravity = Gravity.BOTTOM | (onLeft ? Gravity.LEFT : Gravity.RIGHT);
+ setLayoutParams(lp); // triggers a relayout
}
/**
@@ -340,11 +331,6 @@
* Update {@link BubbleBarLocation}
*/
public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
- if (mBubbleBarLocationAnimator != null) {
- mBubbleBarLocationAnimator.removeAllListeners();
- mBubbleBarLocationAnimator.cancel();
- mBubbleBarLocationAnimator = null;
- }
resetDragAnimation();
if (bubbleBarLocation != mBubbleBarLocation) {
mBubbleBarLocation = bubbleBarLocation;
@@ -361,6 +347,10 @@
}
mDragging = dragging;
setElevation(dragging ? mDragElevation : mBubbleElevation);
+ if (!mDragging) {
+ // Relayout after dragging to ensure that the dragged bubble is positioned correctly
+ requestLayout();
+ }
}
/**
@@ -459,14 +449,13 @@
}
private Animator getLocationUpdateFadeOutAnimator(BubbleBarLocation newLocation) {
- final FloatProperty<? super BubbleBarView> txProp = getLocationAnimTranslationXProperty();
final float shift =
getResources().getDisplayMetrics().widthPixels * FADE_OUT_ANIM_POSITION_SHIFT;
final boolean onLeft = newLocation.isOnLeft(isLayoutRtl());
- final float tx = txProp.get(this) + (onLeft ? -shift : shift);
+ final float tx = getTranslationX() + (onLeft ? -shift : shift);
- ObjectAnimator positionAnim = ObjectAnimator.ofFloat(this, txProp, tx).setDuration(
- FADE_OUT_ANIM_POSITION_DURATION_MS);
+ ObjectAnimator positionAnim = ObjectAnimator.ofFloat(this, VIEW_TRANSLATE_X, tx)
+ .setDuration(FADE_OUT_ANIM_POSITION_DURATION_MS);
positionAnim.setInterpolator(EMPHASIZED_ACCELERATE);
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(this, getLocationAnimAlphaProperty(), 0f)
@@ -505,7 +494,7 @@
.setEndValue(finalTx)
.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
.setStiffness(FADE_IN_ANIM_POSITION_SPRING_STIFFNESS)
- .build(this, getLocationAnimTranslationXProperty());
+ .build(this, VIEW_TRANSLATE_X);
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(this, getLocationAnimAlphaProperty(), 1f)
.setDuration(FADE_IN_ANIM_ALPHA_DURATION_MS);
@@ -516,15 +505,6 @@
}
/**
- * Get property that can be used to animate the translation-x value for the bar.
- * When a bubble is being dragged, uses {@link #BUBBLE_DRAG_TRANSLATION_X}.
- * Falls back to {@link com.android.launcher3.LauncherAnimUtils#VIEW_TRANSLATE_X} otherwise.
- */
- private FloatProperty<? super BubbleBarView> getLocationAnimTranslationXProperty() {
- return mDraggedBubbleView == null ? VIEW_TRANSLATE_X : BUBBLE_DRAG_TRANSLATION_X;
- }
-
- /**
* Get property that can be used to animate the alpha value for the bar.
* When a bubble is being dragged, uses {@link #BUBBLE_DRAG_ALPHA}.
* Falls back to {@link com.android.launcher3.LauncherAnimUtils#VIEW_ALPHA} otherwise.
@@ -534,31 +514,6 @@
}
/**
- * Set translation-x value for the bar while a bubble is being dragged.
- * We can not update translation on the bar directly because the dragged bubble would be
- * affected as well. As it is a child view.
- * Instead, while a bubble is being dragged, set translation on each child view, that is not the
- * dragged view. And set a translation on the background.
- * This allows for the dragged bubble view to remain in position while the bar moves during
- * animation.
- */
- private void setTranslationXDuringBubbleDrag(float translationX) {
- mTranslationXDuringDrag = translationX;
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- BubbleView view = (BubbleView) getChildAt(i);
- if (view != mDraggedBubbleView) {
- view.setBubbleBarTranslationX(translationX);
- }
- }
- if (mBubbleBarBackground != null) {
- mTempBackgroundBounds.set(mBubbleBarBackground.getBounds());
- mTempBackgroundBounds.offsetTo((int) translationX, 0);
- mBubbleBarBackground.setBounds(mTempBackgroundBounds);
- }
- }
-
- /**
* Set alpha value for the bar while a bubble is being dragged.
* We can not update the alpha on the bar directly because the dragged bubble would be affected
* as well. As it is a child view.
@@ -587,7 +542,6 @@
mBubbleBarLocationAnimator.cancel();
mBubbleBarLocationAnimator = null;
}
- setTranslationXDuringBubbleDrag(0f);
setAlphaDuringBubbleDrag(1f);
setTranslationX(0f);
setAlpha(1f);
@@ -706,6 +660,10 @@
// Skip the dragged bubble. Its translation is managed by the drag controller.
continue;
}
+ // Clear out drag translation and offset
+ bv.setDragTranslationX(0f);
+ bv.setOffsetX(0f);
+
bv.setTranslationY(ty);
// the position of the bubble when the bar is fully expanded
@@ -851,10 +809,6 @@
public void setDraggedBubble(@Nullable BubbleView view) {
if (mDraggedBubbleView != null) {
mDraggedBubbleView.setZ(0);
- if (view == null) {
- // We are clearing the dragged bubble, reset drag
- resetDragAnimation();
- }
}
mDraggedBubbleView = view;
if (view != null) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 0b74e15..ac02f1f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -406,10 +406,21 @@
return;
}
+ if (!(b instanceof BubbleBarBubble bubble)) {
+ return;
+ }
+
boolean isInApp = mTaskbarStashController.isInApp();
+ // if this is the first bubble, animate to the initial state. one bubble is the overflow
+ // so check for at most 2 children.
+ if (mBarView.getChildCount() <= 2) {
+ mBubbleBarViewAnimator.animateToInitialState(bubble, isInApp, isExpanding);
+ return;
+ }
+
// only animate the new bubble if we're in an app and not auto expanding
- if (b instanceof BubbleBarBubble && isInApp && !isExpanding && !isExpanded()) {
- mBubbleBarViewAnimator.animateBubbleInForStashed((BubbleBarBubble) b);
+ if (isInApp && !isExpanding && !isExpanded()) {
+ mBubbleBarViewAnimator.animateBubbleInForStashed(bubble);
}
} else {
Log.w(TAG, "addBubble, bubble was null!");
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
index 49f114a..287e906 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
@@ -60,6 +60,7 @@
private final float mBubbleFocusedScale;
private final float mBubbleCapturedScale;
private final float mDismissCapturedScale;
+ private final FloatPropertyCompat<View> mTranslationXProperty;
/**
* Should be initialised for each dragged view
@@ -81,9 +82,28 @@
if (view instanceof BubbleBarView) {
mBubbleFocusedScale = SCALE_BUBBLE_BAR_FOCUSED;
mBubbleCapturedScale = mDismissCapturedScale;
+ mTranslationXProperty = DynamicAnimation.TRANSLATION_X;
} else {
mBubbleFocusedScale = SCALE_BUBBLE_FOCUSED;
mBubbleCapturedScale = SCALE_BUBBLE_CAPTURED;
+ // Wrap BubbleView.DRAG_TRANSLATION_X as it can't be cast to FloatPropertyCompat<View>
+ mTranslationXProperty = new FloatPropertyCompat<>(
+ BubbleView.DRAG_TRANSLATION_X.getName()) {
+ @Override
+ public float getValue(View object) {
+ if (object instanceof BubbleView bubbleView) {
+ return BubbleView.DRAG_TRANSLATION_X.get(bubbleView);
+ }
+ return 0;
+ }
+
+ @Override
+ public void setValue(View object, float value) {
+ if (object instanceof BubbleView bubbleView) {
+ BubbleView.DRAG_TRANSLATION_X.setValue(bubbleView, value);
+ }
+ }
+ };
}
}
@@ -120,7 +140,7 @@
mBubbleAnimator
.spring(DynamicAnimation.SCALE_X, 1f)
.spring(DynamicAnimation.SCALE_Y, 1f)
- .spring(DynamicAnimation.TRANSLATION_X, restingPosition.x, velocity.x,
+ .spring(mTranslationXProperty, restingPosition.x, velocity.x,
mTranslationConfig)
.spring(DynamicAnimation.TRANSLATION_Y, restingPosition.y, velocity.y,
mTranslationConfig)
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
index 1764f75..15de1b8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
@@ -104,7 +104,9 @@
}
@Override
- protected void onDragUpdate(float x, float y) {
+ protected void onDragUpdate(float x, float y, float newTx, float newTy) {
+ bubbleView.setDragTranslationX(newTx);
+ bubbleView.setTranslationY(newTy);
mBubblePinController.onDragUpdate(x, y);
}
@@ -145,12 +147,7 @@
private BubbleBarLocation mReleasedLocation = BubbleBarLocation.DEFAULT;
private final LocationChangeListener mLocationChangeListener =
- new LocationChangeListener() {
- @Override
- public void onRelease(@NonNull BubbleBarLocation location) {
- mReleasedLocation = location;
- }
- };
+ location -> mReleasedLocation = location;
@Override
protected boolean onTouchDown(@NonNull View view, @NonNull MotionEvent event) {
@@ -172,7 +169,9 @@
}
@Override
- protected void onDragUpdate(float x, float y) {
+ protected void onDragUpdate(float x, float y, float newTx, float newTy) {
+ bubbleBarView.setTranslationX(newTx);
+ bubbleBarView.setTranslationY(newTy);
mBubbleBarPinController.onDragUpdate(x, y);
}
@@ -265,8 +264,7 @@
* Called when bubble is dragged to new coordinates.
* Not called while bubble is stuck to the dismiss target.
*/
- protected void onDragUpdate(float x, float y) {
- }
+ protected abstract void onDragUpdate(float x, float y, float newTx, float newTy);
/**
* Called when the dragging interaction has ended and all the animations have completed
@@ -411,9 +409,9 @@
private void drag(@NonNull View view, @NonNull MotionEvent event, float dx, float dy,
float x, float y) {
if (mBubbleDismissController.handleTouchEvent(event)) return;
- view.setTranslationX(mViewInitialPosition.x + dx);
- view.setTranslationY(mViewInitialPosition.y + dy);
- onDragUpdate(x, y);
+ final float newTx = mViewInitialPosition.x + dx;
+ final float newTy = mViewInitialPosition.y + dy;
+ onDragUpdate(x, y, newTx, newTy);
}
private void stopDragging(@NonNull View view, @NonNull MotionEvent event) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
index 4b3416c..d0462aa 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
@@ -123,21 +123,17 @@
}
/**
- * Animates the bubble bar and handle to their initial state, transitioning from the state where
- * both views are invisible. Called when the first bubble is added or when the device is
+ * Animates the handle (or bubble bar depending on state) to be visible after the device is
* unlocked.
*
* <p>Normally either the bubble bar or the handle is visible,
* and {@link #showBubbleBar(boolean)} and {@link #stashBubbleBar()} are used to transition
* between these two states. But the transition from the state where both the bar and handle
* are invisible is slightly different.
- *
- * <p>The initial state will depend on the current state of the device, i.e. overview, home etc
- * and whether bubbles are requested to be expanded.
*/
- public void animateToInitialState(boolean expanding) {
+ private void animateAfterUnlock() {
AnimatorSet animatorSet = new AnimatorSet();
- if (expanding || mBubblesShowingOnHome || mBubblesShowingOnOverview) {
+ if (mBubblesShowingOnHome || mBubblesShowingOnOverview) {
mIsStashed = false;
animatorSet.playTogether(mIconScaleForStash.animateToValue(1),
mIconTranslationYForStash.animateToValue(getBubbleBarTranslationY()),
@@ -217,7 +213,7 @@
if (isSysuiLocked != mIsSysuiLocked) {
mIsSysuiLocked = isSysuiLocked;
if (!mIsSysuiLocked && mBarViewController.hasBubbles()) {
- animateToInitialState(false /* expanding */);
+ animateAfterUnlock();
}
}
}
@@ -453,4 +449,9 @@
mIsStashed = isStashed;
onIsStashedChanged();
}
+
+ /** Set the translation Y for the stashed handle. */
+ public void setHandleTranslationY(float ty) {
+ mHandleViewController.setTranslationYForSwipe(ty);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index 3dc4ebc..61a6bce 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -22,11 +22,13 @@
import android.graphics.Outline;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.FloatProperty;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewOutlineProvider;
import android.widget.ImageView;
+import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.android.launcher3.R;
@@ -47,6 +49,25 @@
public static final int DEFAULT_PATH_SIZE = 100;
/**
+ * Property to update drag translation value.
+ *
+ * @see BubbleView#getDragTranslationX()
+ * @see BubbleView#setDragTranslationX(float)
+ */
+ public static final FloatProperty<BubbleView> DRAG_TRANSLATION_X = new FloatProperty<>(
+ "dragTranslationX") {
+ @Override
+ public void setValue(@NonNull BubbleView bubbleView, float value) {
+ bubbleView.setDragTranslationX(value);
+ }
+
+ @Override
+ public Float get(BubbleView bubbleView) {
+ return bubbleView.getDragTranslationX();
+ }
+ };
+
+ /**
* Flags that suppress the visibility of the 'new' dot or the app badge, for one reason or
* another. If any of these flags are set, the dot will not be shown.
* If {@link SuppressionFlag#BEHIND_STACK} then the app badge will not be shown.
@@ -66,8 +87,8 @@
private final ImageView mAppIcon;
private final int mBubbleSize;
- private float mBubbleBarTranslationX = 0f;
- private float mTranslationX = 0f;
+ private float mDragTranslationX;
+ private float mOffsetX;
private DotRenderer mDotRenderer;
private DotRenderer.DrawParams mDrawParams;
@@ -129,33 +150,37 @@
outline.setOval(inset, inset, inset + normalizedSize, inset + normalizedSize);
}
- @Override
- public void setTranslationX(float translationX) {
- // Overriding setting translationX as it can be a combination of the parent translation
- // and current view translation.
- // When a BubbleView is being dragged to pin the bubble bar to other side, we animate the
- // bar to the new location during the drag.
- // One part of the animation is updating the translation of the bubble bar. But doing
- // that also updates the translation for the child views, like the dragged bubble.
- // To get around that, we instead apply translation on each child view of bubble bar. It
- // is applied as bubble bar translation. This results in BubbleView's translation being a
- // sum of the translation it has and the parent bubble bar translation.
- mTranslationX = translationX;
- applyTranslation();
+ /**
+ * Set translation-x while this bubble is being dragged.
+ * Translation applied to the view is a sum of {@code translationX} and offset defined by
+ * {@link #setOffsetX(float)}.
+ */
+ public void setDragTranslationX(float translationX) {
+ mDragTranslationX = translationX;
+ applyDragTranslation();
}
/**
- * Translation of the bubble bar that hosts this bubble.
- * Is applied together with translation applied on the view through
- * {@link #setTranslationX(float)}.
+ * Get translation value applied via {@link #setDragTranslationX(float)}.
*/
- void setBubbleBarTranslationX(float translationX) {
- mBubbleBarTranslationX = translationX;
- applyTranslation();
+ public float getDragTranslationX() {
+ return mDragTranslationX;
}
- private void applyTranslation() {
- super.setTranslationX(mTranslationX + mBubbleBarTranslationX);
+ /**
+ * Set offset on x-axis while dragging.
+ * Used to counter parent translation in order to keep the dragged view at the current position
+ * on screen.
+ * Translation applied to the view is a sum of {@code offsetX} and translation defined by
+ * {@link #setDragTranslationX(float)}
+ */
+ public void setOffsetX(float offsetX) {
+ mOffsetX = offsetX;
+ applyDragTranslation();
+ }
+
+ private void applyDragTranslation() {
+ setTranslationX(mDragTranslationX + mOffsetX);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
index 66521c1..be935d8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
@@ -93,15 +93,15 @@
if (animator.isRunning()) animator.cancel()
// the animation of a new bubble is divided into 2 parts. The first part shows the bubble
// and the second part hides it after a delay.
- val showAnimation = buildShowAnimation()
- val hideAnimation = buildHideAnimation()
+ val showAnimation = buildHandleToBubbleBarAnimation()
+ val hideAnimation = buildBubbleBarToHandleAnimation()
animatingBubble = AnimatingBubble(bubbleView, showAnimation, hideAnimation)
scheduler.post(showAnimation)
scheduler.postDelayed(FLYOUT_DELAY_MS, hideAnimation)
}
/**
- * Returns a [Runnable] that starts the animation that shows the new or updated bubble.
+ * Returns a [Runnable] that starts the animation that morphs the handle to the bubble bar.
*
* Visually, the animation is divided into 2 parts. The stash handle starts animating up and
* fading out and then the bubble bar starts animating up and fading in.
@@ -114,7 +114,7 @@
* 3. The third part is the overshoot of the spring animation, where we make the bubble fully
* visible which helps avoiding further updates when we re-enter the second part.
*/
- private fun buildShowAnimation() = Runnable {
+ private fun buildHandleToBubbleBarAnimation() = Runnable {
// prepare the bubble bar for the animation
bubbleBarView.onAnimatingBubbleStarted()
bubbleBarView.visibility = VISIBLE
@@ -197,7 +197,8 @@
}
/**
- * Returns a [Runnable] that starts the animation that hides the bubble bar.
+ * Returns a [Runnable] that starts the animation that hides the bubble bar and morphs it into
+ * the stashed handle.
*
* Similarly to the show animation, this is visually divided into 2 parts. We first animate the
* bubble bar out, and then animate the stash handle in. At the end of the animation we reset
@@ -209,13 +210,14 @@
* 2. In the second part the bubble bar is fully hidden and the handle animates in.
* 3. The third part is the overshoot. The handle is made fully visible.
*/
- private fun buildHideAnimation() = Runnable {
+ private fun buildBubbleBarToHandleAnimation() = Runnable {
if (animatingBubble == null) return@Runnable
val offset = bubbleStashController.diffBetweenHandleAndBarCenters
val stashedHandleTranslationY =
bubbleStashController.stashedHandleTranslationForNewBubbleAnimation
// this is the total distance that both the stashed handle and the bar will be traveling
val totalTranslationY = bubbleStashController.bubbleBarTranslationYForTaskbar + offset
+ bubbleStashController.setHandleTranslationY(totalTranslationY)
val animator = bubbleStashController.stashedHandlePhysicsAnimator
animator.setDefaultSpringConfig(springConfig)
animator.spring(DynamicAnimation.TRANSLATION_Y, 0f)
@@ -259,6 +261,50 @@
animator.start()
}
+ /** Animates to the initial state of the bubble bar, when there are no previous bubbles. */
+ fun animateToInitialState(b: BubbleBarBubble, isInApp: Boolean, isExpanding: Boolean) {
+ val bubbleView = b.view
+ val animator = PhysicsAnimator.getInstance(bubbleView)
+ if (animator.isRunning()) animator.cancel()
+ // the animation of a new bubble is divided into 2 parts. The first part shows the bubble
+ // and the second part hides it after a delay if we are in an app.
+ val showAnimation = buildBubbleBarBounceAnimation()
+ val hideAnimation =
+ if (isInApp && !isExpanding) {
+ buildBubbleBarToHandleAnimation()
+ } else {
+ // in this case the bubble bar remains visible so not much to do. once we implement
+ // the flyout we'll update this runnable to hide it.
+ Runnable {
+ animatingBubble = null
+ bubbleStashController.showBubbleBarImmediate()
+ bubbleBarView.onAnimatingBubbleCompleted()
+ }
+ }
+ animatingBubble = AnimatingBubble(bubbleView, showAnimation, hideAnimation)
+ scheduler.post(showAnimation)
+ scheduler.postDelayed(FLYOUT_DELAY_MS, hideAnimation)
+ }
+
+ private fun buildBubbleBarBounceAnimation() = Runnable {
+ // prepare the bubble bar for the animation
+ bubbleBarView.onAnimatingBubbleStarted()
+ bubbleBarView.translationY = bubbleBarView.height.toFloat()
+ bubbleBarView.visibility = VISIBLE
+ bubbleBarView.alpha = 1f
+ bubbleBarView.scaleX = 1f
+ bubbleBarView.scaleY = 1f
+
+ val animator = PhysicsAnimator.getInstance(bubbleBarView)
+ animator.setDefaultSpringConfig(springConfig)
+ animator.spring(DynamicAnimation.TRANSLATION_Y, bubbleStashController.bubbleBarTranslationY)
+ animator.addEndListener { _, _, _, _, _, _, _ ->
+ // the bubble bar is now fully settled in. update taskbar touch region so it's touchable
+ bubbleStashController.updateTaskbarTouchRegion()
+ }
+ animator.start()
+ }
+
/** Handles clicking on the animating bubble while the animation is still playing. */
fun onBubbleClickedWhileAnimating() {
val hideAnimation = animatingBubble?.hideAnimation ?: return
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 6c1d4b1..317e6f2 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -21,7 +21,6 @@
import static com.android.launcher3.LauncherState.OVERVIEW_ACTIONS;
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_ACTIONS_FADE;
-import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import static com.android.quickstep.views.RecentsView.TASK_MODALNESS;
@@ -50,6 +49,7 @@
import com.android.quickstep.util.SplitAnimationTimings;
import com.android.quickstep.views.ClearAllButton;
import com.android.quickstep.views.LauncherRecentsView;
+import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
/**
@@ -167,8 +167,8 @@
propertySetter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
clearAllButtonAlpha, LINEAR);
float overviewButtonAlpha = state.areElementsVisible(mLauncher, OVERVIEW_ACTIONS) ? 1 : 0;
- propertySetter.setFloat(mLauncher.getActionsView().getVisibilityAlpha(),
- MULTI_PROPERTY_VALUE, overviewButtonAlpha, config.getInterpolator(
+ propertySetter.setFloat(mLauncher.getActionsView().getVisibilityAlphaSetter(),
+ OverviewActionsView.FLOAT_SETTER, overviewButtonAlpha, config.getInterpolator(
ANIM_OVERVIEW_ACTIONS_FADE, LINEAR));
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 527a776..fc0df76 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -248,7 +248,7 @@
TASK_THUMBNAIL_SPLASH_ALPHA.set(mRecentsView, fromState.showTaskThumbnailSplash() ? 1f : 0);
mRecentsView.setContentAlpha(1);
mRecentsView.setFullscreenProgress(fromState.getOverviewFullscreenProgress());
- mLauncher.getActionsView().getVisibilityAlpha().setValue(
+ mLauncher.getActionsView().getVisibilityAlphaSetter().accept(
(fromState.getVisibleElements(mLauncher) & OVERVIEW_ACTIONS) != 0 ? 1f : 0f);
mRecentsView.setTaskIconScaledDown(true);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index 05a55d0..16185f5 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -151,7 +151,7 @@
int sysuiFlags = 0;
TaskView tv = mOverviewPanel.getTaskViewAt(0);
if (tv != null) {
- sysuiFlags = tv.getThumbnail().getSysUiStatusNavFlags();
+ sysuiFlags = tv.getFirstThumbnailView().getSysUiStatusNavFlags();
}
mLauncher.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, sysuiFlags);
} else {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 300d697..26b528c 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -252,7 +252,7 @@
mTaskBeingDragged, maxDuration, currentInterpolator);
// Since the thumbnail is what is filling the screen, based the end displacement on it.
- View thumbnailView = mTaskBeingDragged.getThumbnail();
+ View thumbnailView = mTaskBeingDragged.getFirstThumbnailView();
mTempCords[1] = orientationHandler.getSecondaryDimension(thumbnailView);
dl.getDescendantCoordRelativeToSelf(thumbnailView, mTempCords);
mEndDisplacement = secondaryLayerDimension - mTempCords[1];
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 2ce40b4..28ae3d2 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -135,10 +135,11 @@
import com.android.quickstep.util.SwipePipToHomeAnimator;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
+import com.android.quickstep.views.DesktopTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.RecentsViewContainer;
import com.android.quickstep.views.TaskView;
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
+import com.android.quickstep.views.TaskView.TaskContainer;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -147,6 +148,7 @@
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
+import com.android.window.flags.Flags;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.startingsurface.SplashScreenExitAnimationUtils;
@@ -922,7 +924,7 @@
TaskView runningTask = mRecentsView.getRunningTaskView();
TaskView centermostTask = mRecentsView.getTaskViewNearestToCenterOfScreen();
int centermostTaskFlags = centermostTask == null ? 0
- : centermostTask.getThumbnail().getSysUiStatusNavFlags();
+ : centermostTask.getFirstThumbnailView().getSysUiStatusNavFlags();
boolean swipeUpThresholdPassed = windowProgress > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD;
boolean quickswitchThresholdPassed = centermostTask != runningTask;
@@ -1258,13 +1260,16 @@
? mRecentsView.getNextPageTaskView() : null;
TaskView currentPageTaskView = mRecentsView != null
? mRecentsView.getCurrentPageTaskView() : null;
- if (((nextPageTaskView != null && nextPageTaskView.isDesktopTask())
- || (currentPageTaskView != null && currentPageTaskView.isDesktopTask()))
- && endTarget == NEW_TASK) {
- // TODO(b/268075592): add support for quickswitch to/from desktop
- return LAST_TASK;
- }
+ if (Flags.enableDesktopWindowingMode()
+ && !(Flags.enableDesktopWindowingWallpaperActivity()
+ && Flags.enableDesktopWindowingQuickSwitch())) {
+ if ((nextPageTaskView instanceof DesktopTaskView
+ || currentPageTaskView instanceof DesktopTaskView)
+ && endTarget == NEW_TASK) {
+ return LAST_TASK;
+ }
+ }
return endTarget;
}
@@ -1421,14 +1426,27 @@
mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED);
setClampScrollOffset(false);
};
- if (mRecentsView != null && (mRecentsView.getCurrentPageTaskView() != null
- && !mRecentsView.getCurrentPageTaskView().isDesktopTask())) {
- ActiveGestureLog.INSTANCE.trackEvent(ActiveGestureErrorDetector.GestureEvent
- .SET_ON_PAGE_TRANSITION_END_CALLBACK);
- // TODO(b/268075592): add support for quickswitch to/from desktop
- mRecentsView.setOnPageTransitionEndCallback(onPageTransitionEnd);
+
+ if (Flags.enableDesktopWindowingMode()
+ && !(Flags.enableDesktopWindowingWallpaperActivity()
+ && Flags.enableDesktopWindowingQuickSwitch())) {
+ if (mRecentsView != null && (mRecentsView.getCurrentPageTaskView() != null
+ && !(mRecentsView.getCurrentPageTaskView() instanceof DesktopTaskView))) {
+ ActiveGestureLog.INSTANCE.trackEvent(ActiveGestureErrorDetector.GestureEvent
+ .SET_ON_PAGE_TRANSITION_END_CALLBACK);
+ mRecentsView.setOnPageTransitionEndCallback(onPageTransitionEnd);
+ } else {
+ onPageTransitionEnd.run();
+ }
} else {
- onPageTransitionEnd.run();
+ if (mRecentsView != null) {
+ ActiveGestureLog.INSTANCE.trackEvent(
+ ActiveGestureErrorDetector
+ .GestureEvent.SET_ON_PAGE_TRANSITION_END_CALLBACK);
+ mRecentsView.setOnPageTransitionEndCallback(onPageTransitionEnd);
+ } else {
+ onPageTransitionEnd.run();
+ }
}
animateToProgress(startShift, endShift, duration, interpolator, endTarget, velocityPxPerMs);
@@ -2250,13 +2268,14 @@
mRecentsAnimationController, mRecentsAnimationTargets);
});
- if ((mRecentsView.getNextPageTaskView() != null
- && mRecentsView.getNextPageTaskView().isDesktopTask())
- || (mRecentsView.getCurrentPageTaskView() != null
- && mRecentsView.getCurrentPageTaskView().isDesktopTask())) {
- // TODO(b/268075592): add support for quickswitch to/from desktop
- mRecentsViewScrollLinked = false;
- return;
+ if (Flags.enableDesktopWindowingMode()
+ && !(Flags.enableDesktopWindowingWallpaperActivity()
+ && Flags.enableDesktopWindowingQuickSwitch())) {
+ if (mRecentsView.getNextPageTaskView() instanceof DesktopTaskView
+ || mRecentsView.getCurrentPageTaskView() instanceof DesktopTaskView) {
+ mRecentsViewScrollLinked = false;
+ return;
+ }
}
// Disable scrolling in RecentsView for trackpad 3-finger swipe up gesture.
@@ -2287,15 +2306,15 @@
int[] taskIds = nextTask.getTaskIds();
ActiveGestureLog.CompoundString nextTaskLog = new ActiveGestureLog.CompoundString(
"Launching task: ");
- for (TaskIdAttributeContainer c : nextTask.getTaskIdAttributeContainers()) {
- if (c == null) {
+ for (TaskContainer container : nextTask.getTaskContainers()) {
+ if (container == null) {
continue;
}
nextTaskLog
.append("[id: ")
- .append(c.getTask().key.id)
+ .append(container.getTask().key.id)
.append(", pkg: ")
- .append(c.getTask().key.getPackageName())
+ .append(container.getTask().key.getPackageName())
.append("] | ");
}
mGestureState.updateLastStartedTaskIds(taskIds);
@@ -2407,7 +2426,7 @@
RemoteAnimationTarget taskTarget = taskTargetOptional.get();
TaskView taskView = mRecentsView == null
? null : mRecentsView.getTaskViewByTaskId(taskTarget.taskId);
- if (taskView == null || !taskView.getThumbnail().shouldShowSplashView()) {
+ if (taskView == null || !taskView.getFirstThumbnailView().shouldShowSplashView()) {
ActiveGestureLog.INSTANCE.addLog("Invalid task view splash state");
finishRecentsAnimationOnTasksAppeared(null /* onFinishComplete */);
return;
diff --git a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
index aab6aa1..e33ef7f 100644
--- a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
+++ b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
@@ -23,12 +23,12 @@
import com.android.launcher3.popup.SystemShortcut
import com.android.quickstep.views.RecentsView
import com.android.quickstep.views.RecentsViewContainer
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
+import com.android.quickstep.views.TaskView.TaskContainer
/** A menu item, "Desktop", that allows the user to bring the current app into Desktop Windowing. */
class DesktopSystemShortcut(
container: RecentsViewContainer,
- private val mTaskContainer: TaskIdAttributeContainer,
+ private val mTaskContainer: TaskContainer,
abstractFloatingViewHelper: AbstractFloatingViewHelper
) :
SystemShortcut<RecentsViewContainer>(
@@ -59,7 +59,7 @@
return object : TaskShortcutFactory {
override fun getShortcuts(
container: RecentsViewContainer,
- taskContainer: TaskIdAttributeContainer
+ taskContainer: TaskContainer
): List<DesktopSystemShortcut>? {
return if (!DesktopModeStatus.canEnterDesktopMode(container.asContext())) null
else if (!taskContainer.task.isDockable) null
diff --git a/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt b/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt
index f68f793..0f844e1 100644
--- a/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt
+++ b/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt
@@ -154,7 +154,7 @@
}
companion object {
- val configHelper by lazy { DeviceConfigHelper(::DeviceConfigWrapper) }
+ @JvmStatic val configHelper by lazy { DeviceConfigHelper(::DeviceConfigWrapper) }
@JvmStatic fun get() = configHelper.config
}
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index 4b5a15d..6a9f509 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -305,8 +305,8 @@
return null;
}
if (sourceTaskView == null
- || sourceTaskView.getTask() == null
- || sourceTaskView.getTask().key.getComponent() == null) {
+ || sourceTaskView.getFirstTask() == null
+ || sourceTaskView.getFirstTask().key.getComponent() == null) {
// Disable if it's an invalid task
return null;
}
@@ -323,8 +323,8 @@
}
return mContainer.getFirstMatchForAppClose(launchCookieItemId,
- sourceTaskView.getTask().key.getComponent().getPackageName(),
- UserHandle.of(sourceTaskView.getTask().key.userId),
+ sourceTaskView.getFirstTask().key.getComponent().getPackageName(),
+ UserHandle.of(sourceTaskView.getFirstTask().key.userId),
false /* supportsAllAppsState */);
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 4b4f914..54466f3 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -33,6 +33,7 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DIALOG_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_MAGNIFICATION_OVERLAP;
@@ -399,7 +400,8 @@
&& (mSystemUiStateFlags & SYSUI_STATE_MAGNIFICATION_OVERLAP) == 0
&& ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0
|| (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0)
- && (mSystemUiStateFlags & SYSUI_STATE_DEVICE_DREAMING) == 0;
+ && (mSystemUiStateFlags & SYSUI_STATE_DEVICE_DREAMING) == 0
+ && (mSystemUiStateFlags & SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION) == 0;
}
/**
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index d32c7a6..1a46fb6 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -46,7 +46,7 @@
import com.android.quickstep.views.RecentsViewContainer;
import com.android.quickstep.views.TaskThumbnailViewDeprecated;
import com.android.quickstep.views.TaskView;
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
+import com.android.quickstep.views.TaskView.TaskContainer;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -59,7 +59,7 @@
public class TaskOverlayFactory implements ResourceBasedOverride {
public static List<SystemShortcut> getEnabledShortcuts(TaskView taskView,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
final ArrayList<SystemShortcut> shortcuts = new ArrayList<>();
final RecentsViewContainer container =
RecentsViewContainer.containerFromContext(taskView.getContext());
@@ -292,7 +292,7 @@
@Override
public void onClick(View view) {
- saveScreenshot(mThumbnailView.getTaskView().getTask());
+ saveScreenshot(mThumbnailView.getTaskView().getFirstTask());
dismissTaskMenuView();
}
}
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index 8df4bdd..f052a9d 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -58,14 +58,13 @@
import com.android.quickstep.views.RecentsViewContainer;
import com.android.quickstep.views.TaskThumbnailViewDeprecated;
import com.android.quickstep.views.TaskView;
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
+import com.android.quickstep.views.TaskView.TaskContainer;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
import com.android.systemui.shared.recents.view.RecentsTransition;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
@@ -78,7 +77,7 @@
public interface TaskShortcutFactory {
@Nullable
default List<SystemShortcut> getShortcuts(RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
return null;
}
@@ -108,7 +107,7 @@
TaskShortcutFactory APP_INFO = new TaskShortcutFactory() {
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
TaskView taskView = taskContainer.getTaskView();
AppInfo.SplitAccessibilityInfo accessibilityInfo =
new AppInfo.SplitAccessibilityInfo(taskView.containsMultipleTasks(),
@@ -176,7 +175,7 @@
private final LauncherEvent mLauncherEvent;
public FreeformSystemShortcut(int iconRes, int textRes, RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer, LauncherEvent launcherEvent) {
+ TaskContainer taskContainer, LauncherEvent launcherEvent) {
super(iconRes, textRes, container, taskContainer.getItemInfo(),
taskContainer.getTaskView());
mLauncherEvent = launcherEvent;
@@ -199,7 +198,7 @@
}
private void startActivity() {
- final Task.TaskKey taskKey = mTaskView.getTask().key;
+ final Task.TaskKey taskKey = mTaskView.getFirstTask().key;
final int taskId = taskKey.id;
final ActivityOptions options = makeLaunchOptions(mTarget);
if (options != null) {
@@ -292,7 +291,7 @@
TaskShortcutFactory SPLIT_SELECT = new TaskShortcutFactory() {
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
DeviceProfile deviceProfile = container.getDeviceProfile();
final Task task = taskContainer.getTask();
final int intentFlags = task.key.baseIntent.getFlags();
@@ -327,7 +326,7 @@
@Nullable
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
DeviceProfile deviceProfile = container.getDeviceProfile();
final TaskView taskView = taskContainer.getTaskView();
final RecentsView recentsView = taskView.getRecentsView();
@@ -336,7 +335,7 @@
recentsView.isTaskInExpectedScrollPosition(recentsView.indexOfChild(taskView));
boolean shouldShowActionsButtonInstead =
isLargeTileFocusedTask && isInExpectedScrollPosition;
- boolean hasUnpinnableApp = Arrays.stream(taskView.getTaskIdAttributeContainers())
+ boolean hasUnpinnableApp = taskView.getTaskContainers().stream()
.anyMatch(att -> att != null && att.getItemInfo() != null
&& ((att.getItemInfo().runtimeStatusFlags
& ItemInfoWithIcon.FLAG_NOT_PINNABLE) != 0));
@@ -375,7 +374,7 @@
TaskShortcutFactory FREE_FORM = new TaskShortcutFactory() {
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
final Task task = taskContainer.getTask();
if (!task.isDockable) {
return null;
@@ -401,7 +400,7 @@
TaskShortcutFactory PIN = new TaskShortcutFactory() {
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
if (!SystemUiProxy.INSTANCE.get(container.asContext()).isActive()) {
return null;
}
@@ -423,7 +422,7 @@
private final TaskView mTaskView;
public PinSystemShortcut(RecentsViewContainer target,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
super(R.drawable.ic_pin, R.string.recent_task_option_pin, target,
taskContainer.getItemInfo(), taskContainer.getTaskView());
mTaskView = taskContainer.getTaskView();
@@ -433,7 +432,7 @@
public void onClick(View view) {
if (mTaskView.launchTaskAnimated() != null) {
SystemUiProxy.INSTANCE.get(mTarget.asContext()).startScreenPinning(
- mTaskView.getTask().key.id);
+ mTaskView.getFirstTask().key.id);
}
dismissTaskMenuView();
mTarget.getStatsLogManager().logger().withItemInfo(mTaskView.getItemInfo())
@@ -444,7 +443,7 @@
TaskShortcutFactory INSTALL = new TaskShortcutFactory() {
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
Task t = taskContainer.getTask();
return InstantAppResolver.newInstance(container.asContext()).isInstantApp(
t.getTopComponent().getPackageName(), t.getKey().userId)
@@ -457,7 +456,7 @@
TaskShortcutFactory WELLBEING = new TaskShortcutFactory() {
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
SystemShortcut<ActivityContext> wellbeingShortcut =
WellbeingModel.SHORTCUT_FACTORY.getShortcut(container,
taskContainer.getItemInfo(), taskContainer.getTaskView());
@@ -468,7 +467,7 @@
TaskShortcutFactory SCREENSHOT = new TaskShortcutFactory() {
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
boolean isTablet = container.getDeviceProfile().isTablet;
boolean isGridOnlyOverview = isTablet && Flags.enableGridOnlyOverview();
// Extra conditions if it's not grid-only overview
@@ -498,7 +497,7 @@
TaskShortcutFactory MODAL = new TaskShortcutFactory() {
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
- TaskIdAttributeContainer taskContainer) {
+ TaskContainer taskContainer) {
boolean isTablet = container.getDeviceProfile().isTablet;
boolean isGridOnlyOverview = isTablet && Flags.enableGridOnlyOverview();
// Extra conditions if it's not grid-only overview
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index d89d399..d2560e6 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -121,7 +121,7 @@
for (int i = 0; i < recentsView.getTaskViewCount(); i++) {
TaskView taskView = recentsView.getTaskViewAt(i);
if (recentsView.isTaskViewVisible(taskView)) {
- Task.TaskKey key = taskView.getTask().key;
+ Task.TaskKey key = taskView.getFirstTask().key;
if (componentName.equals(key.getComponent()) && userId == key.userId) {
return taskView;
}
@@ -334,7 +334,7 @@
// During animation we apply transformation on the thumbnailView (and not the rootView)
// to follow the TaskViewSimulator. So the final matrix applied on the thumbnailView is:
// Mt K(0)` K(t) Mt`
- TaskThumbnailViewDeprecated[] thumbnails = v.getThumbnails();
+ TaskThumbnailViewDeprecated[] thumbnails = v.getThumbnailViews();
// In case simulator copies and thumbnail size do no match, ensure we get the lesser.
// This ensures we do not create arrays with empty elements or attempt to references
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
index 2e76356..1bf129c 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -46,12 +46,10 @@
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.util.MultiPropertyFactory;
import com.android.quickstep.RecentsActivity;
import com.android.quickstep.views.ClearAllButton;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
-import com.android.quickstep.views.RecentsViewContainer;
/**
* State controller for fallback recents activity
@@ -98,8 +96,8 @@
setter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
clearAllButtonAlpha, LINEAR);
float overviewButtonAlpha = state.hasOverviewActions() ? 1 : 0;
- setter.setFloat(mActivity.getActionsView().getVisibilityAlpha(),
- MultiPropertyFactory.MULTI_PROPERTY_VALUE, overviewButtonAlpha, LINEAR);
+ setter.setFloat(mActivity.getActionsView().getVisibilityAlphaSetter(),
+ OverviewActionsView.FLOAT_SETTER, overviewButtonAlpha, LINEAR);
float[] scaleAndOffset = state.getOverviewScaleAndOffset(mActivity);
setter.setFloat(mRecentsView, RECENTS_SCALE_PROPERTY, scaleAndOffset[0],
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index e3e14ae..3cae4dc 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -392,6 +392,20 @@
case LAUNCHER_ALLAPPS_VERTICAL_SWIPE_END:
InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_ALL_APPS_SCROLL);
break;
+ case LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_BEGIN:
+ InteractionJankMonitorWrapper.begin(view, Cuj.CUJ_LAUNCHER_PRIVATE_SPACE_LOCK);
+ break;
+ case LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_END:
+ InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_PRIVATE_SPACE_LOCK);
+ break;
+ case LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_BEGIN:
+ InteractionJankMonitorWrapper.begin(
+ view,
+ Cuj.CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK);
+ break;
+ case LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_END:
+ InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK);
+ break;
default:
break;
}
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index a82031a..770a452 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -116,9 +116,9 @@
*/
public void saveAppPair(GroupedTaskView gtv) {
InteractionJankMonitorWrapper.begin(gtv, Cuj.CUJ_LAUNCHER_SAVE_APP_PAIR);
- TaskView.TaskIdAttributeContainer[] attributes = gtv.getTaskIdAttributeContainers();
- WorkspaceItemInfo recentsInfo1 = attributes[0].getItemInfo();
- WorkspaceItemInfo recentsInfo2 = attributes[1].getItemInfo();
+ List<TaskView.TaskContainer> containers = gtv.getTaskContainers();
+ WorkspaceItemInfo recentsInfo1 = containers.get(0).getItemInfo();
+ WorkspaceItemInfo recentsInfo2 = containers.get(1).getItemInfo();
WorkspaceItemInfo app1 = lookupLaunchableItem(recentsInfo1.getComponentKey());
WorkspaceItemInfo app2 = lookupLaunchableItem(recentsInfo2.getComponentKey());
diff --git a/quickstep/src/com/android/quickstep/util/AssistStateManager.java b/quickstep/src/com/android/quickstep/util/AssistStateManager.java
index 42db65f..7acb28d 100644
--- a/quickstep/src/com/android/quickstep/util/AssistStateManager.java
+++ b/quickstep/src/com/android/quickstep/util/AssistStateManager.java
@@ -33,8 +33,8 @@
public AssistStateManager() {}
- /** Whether search is available. */
- public boolean isSearchAvailable() {
+ /** Return {@code true} if the Settings toggle is enabled. */
+ public boolean isSettingsAllEntrypointsEnabled() {
return false;
}
@@ -43,14 +43,9 @@
return false;
}
- /** Whether CsHelper CtS invocation path is available. */
- public Optional<Boolean> isCsHelperAvailable() {
- return Optional.empty();
- }
-
- /** Whether VIS CtS invocation path is available. */
- public Optional<Boolean> isVisAvailable() {
- return Optional.empty();
+ /** Whether ContextualSearchService invocation path is available. */
+ public boolean isContextualSearchServiceAvailable() {
+ return false;
}
/** Get the Launcher overridden long press nav handle duration to trigger Assistant. */
@@ -90,11 +85,6 @@
return Optional.empty();
}
- /** Return {@code true} if the Settings toggle is enabled. */
- public boolean isSettingsAllEntrypointsEnabled() {
- return false;
- }
-
/** Dump states. */
public void dump(String prefix, PrintWriter writer) {}
diff --git a/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt b/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt
index 544c64d..d36dc7e 100644
--- a/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt
+++ b/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt
@@ -48,12 +48,14 @@
PropReader(
object : PropProvider {
override fun <T : Any> get(key: String, fallback: T): T {
- if (fallback is Int)
+ if (fallback is Int) {
+ allKeys.add(key)
return DeviceConfig.getInt(NAMESPACE_LAUNCHER, key, fallback) as T
- else if (fallback is Boolean)
+ } else if (fallback is Boolean) {
+ allKeys.add(key)
return DeviceConfig.getBoolean(NAMESPACE_LAUNCHER, key, fallback)
as T
- else return fallback
+ } else return fallback
}
}
)
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index ee2c2e1..40ea70f 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -69,7 +69,7 @@
import com.android.quickstep.views.SplitInstructionsView
import com.android.quickstep.views.TaskThumbnailViewDeprecated
import com.android.quickstep.views.TaskView
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
+import com.android.quickstep.views.TaskView.TaskContainer
import com.android.quickstep.views.TaskViewIcon
import com.android.wm.shell.shared.TransitionUtil
import java.util.Optional
@@ -114,7 +114,7 @@
} else if (splitSelectStateController.isDismissingFromSplitPair) {
// Initiating split from overview, but on a split pair
val taskView = taskViewSupplier.get()
- for (container: TaskIdAttributeContainer in taskView.taskIdAttributeContainers) {
+ for (container: TaskContainer in taskView.taskContainers) {
if (container.task.getKey().getId() == splitSelectStateController.initialTaskId) {
val drawable = getDrawable(container.iconView, splitSelectSource)
return SplitAnimInitProps(
@@ -134,15 +134,17 @@
} else {
// Initiating split from overview on fullscreen task TaskView
val taskView = taskViewSupplier.get()
- val drawable = getDrawable(taskView.iconView, splitSelectSource)
- return SplitAnimInitProps(
- taskView.thumbnail,
- taskView.thumbnail.thumbnail,
- drawable!!,
- fadeWithThumbnail = true,
- isStagedTask = true,
- taskView.iconView.asView()
- )
+ taskView.taskContainers.first().let {
+ val drawable = getDrawable(it.iconView, splitSelectSource)
+ return SplitAnimInitProps(
+ it.thumbnailView,
+ it.thumbnailView.thumbnail,
+ drawable!!,
+ fadeWithThumbnail = true,
+ isStagedTask = true,
+ iconView = it.iconView.asView()
+ )
+ }
}
}
@@ -173,7 +175,7 @@
* (opposite of that representing [taskIdAttributeContainer])
*/
fun addInitialSplitFromPair(
- taskIdAttributeContainer: TaskIdAttributeContainer,
+ taskIdAttributeContainer: TaskContainer,
builder: PendingAnimation,
deviceProfile: DeviceProfile,
taskViewWidth: Int,
@@ -561,8 +563,13 @@
// Launch split app pair animation
composeIconSplitLaunchAnimator(launchingIconView, info, t, finishCallback)
} else {
- composeFullscreenIconSplitLaunchAnimator(launchingIconView, info, t,
- finishCallback, appPairLaunchingAppIndex)
+ composeFullscreenIconSplitLaunchAnimator(
+ launchingIconView,
+ info,
+ t,
+ finishCallback,
+ appPairLaunchingAppIndex
+ )
}
} else {
// Fallback case: simple fade-in animation
@@ -629,18 +636,22 @@
/**
* @return -1 if [transitionInfo] contains both apps of the app pair to be animated, otherwise
- * the integer index corresponding to [launchingIconView]'s contents for the single app
- * to be animated
+ * the integer index corresponding to [launchingIconView]'s contents for the single app to be
+ * animated
*/
- fun hasChangesForBothAppPairs(launchingIconView: AppPairIcon,
- transitionInfo: TransitionInfo) : Int {
+ fun hasChangesForBothAppPairs(
+ launchingIconView: AppPairIcon,
+ transitionInfo: TransitionInfo
+ ): Int {
val intent1 = launchingIconView.info.getFirstApp().intent.component?.packageName
val intent2 = launchingIconView.info.getSecondApp().intent.component?.packageName
var launchFullscreenAppIndex = -1
for (change in transitionInfo.changes) {
val taskInfo: RunningTaskInfo = change.taskInfo ?: continue
- if (TransitionUtil.isOpeningType(change.mode) &&
- taskInfo.windowingMode == WINDOWING_MODE_FULLSCREEN) {
+ if (
+ TransitionUtil.isOpeningType(change.mode) &&
+ taskInfo.windowingMode == WINDOWING_MODE_FULLSCREEN
+ ) {
val baseIntent = taskInfo.baseIntent.component?.packageName
if (baseIntent == intent1) {
if (launchFullscreenAppIndex > -1) {
@@ -695,8 +706,12 @@
// If launching an app pair from Taskbar inside of an app context (no access to Launcher),
// use the scale-up animation
if (launchingIconView.context is TaskbarActivityContext) {
- composeScaleUpLaunchAnimation(transitionInfo, t, finishCallback,
- WINDOWING_MODE_MULTI_WINDOW)
+ composeScaleUpLaunchAnimation(
+ transitionInfo,
+ t,
+ finishCallback,
+ WINDOWING_MODE_MULTI_WINDOW
+ )
return
}
@@ -767,28 +782,32 @@
floatingView.bringToFront()
launchAnimation.play(
- getIconLaunchValueAnimator(t, dp, finishCallback, launcher, floatingView,
- rootCandidate))
+ getIconLaunchValueAnimator(t, dp, finishCallback, launcher, floatingView, rootCandidate)
+ )
launchAnimation.start()
}
/**
- * Similar to [composeIconSplitLaunchAnimator], but instructs [FloatingAppPairView] to animate
- * a single fullscreen icon + background instead of for a pair
+ * Similar to [composeIconSplitLaunchAnimator], but instructs [FloatingAppPairView] to animate a
+ * single fullscreen icon + background instead of for a pair
*/
@VisibleForTesting
fun composeFullscreenIconSplitLaunchAnimator(
- launchingIconView: AppPairIcon,
- transitionInfo: TransitionInfo,
- t: Transaction,
- finishCallback: Runnable,
- launchFullscreenIndex: Int
+ launchingIconView: AppPairIcon,
+ transitionInfo: TransitionInfo,
+ t: Transaction,
+ finishCallback: Runnable,
+ launchFullscreenIndex: Int
) {
// If launching an app pair from Taskbar inside of an app context (no access to Launcher),
// use the scale-up animation
if (launchingIconView.context is TaskbarActivityContext) {
- composeScaleUpLaunchAnimation(transitionInfo, t, finishCallback,
- WINDOWING_MODE_FULLSCREEN)
+ composeScaleUpLaunchAnimation(
+ transitionInfo,
+ t,
+ finishCallback,
+ WINDOWING_MODE_FULLSCREEN
+ )
return
}
@@ -799,16 +818,18 @@
// Create an AnimatorSet that will run both shell and launcher transitions together
val launchAnimation = AnimatorSet()
- val appInfo = launchingIconView.info
- .getContents()[launchFullscreenIndex] as WorkspaceItemInfo
+ val appInfo =
+ launchingIconView.info.getContents()[launchFullscreenIndex] as WorkspaceItemInfo
val intentToLaunch = appInfo.intent.component?.packageName
var rootCandidate: Change? = null
for (change in transitionInfo.changes) {
val taskInfo: RunningTaskInfo = change.taskInfo ?: continue
val baseIntent = taskInfo.baseIntent.component?.packageName
- if (TransitionUtil.isOpeningType(change.mode) &&
+ if (
+ TransitionUtil.isOpeningType(change.mode) &&
taskInfo.windowingMode == WINDOWING_MODE_FULLSCREEN &&
- baseIntent == intentToLaunch) {
+ baseIntent == intentToLaunch
+ ) {
rootCandidate = change
}
}
@@ -832,26 +853,28 @@
appIcon.setBounds(0, 0, dp.iconSizePx, dp.iconSizePx)
val floatingView =
- FloatingAppPairView.getFloatingAppPairView(
- launcher,
- drawableArea,
- appIcon,
- null /*appIcon2*/,
- 0 /*dividerPos*/
- )
+ FloatingAppPairView.getFloatingAppPairView(
+ launcher,
+ drawableArea,
+ appIcon,
+ null /*appIcon2*/,
+ 0 /*dividerPos*/
+ )
floatingView.bringToFront()
launchAnimation.play(
- getIconLaunchValueAnimator(t, dp, finishCallback, launcher, floatingView,
- rootCandidate))
+ getIconLaunchValueAnimator(t, dp, finishCallback, launcher, floatingView, rootCandidate)
+ )
launchAnimation.start()
}
- private fun getIconLaunchValueAnimator(t: Transaction,
- dp: com.android.launcher3.DeviceProfile,
- finishCallback: Runnable,
- launcher: QuickstepLauncher,
- floatingView: FloatingAppPairView,
- rootCandidate: Change) : ValueAnimator {
+ private fun getIconLaunchValueAnimator(
+ t: Transaction,
+ dp: com.android.launcher3.DeviceProfile,
+ finishCallback: Runnable,
+ launcher: QuickstepLauncher,
+ floatingView: FloatingAppPairView,
+ rootCandidate: Change
+ ): ValueAnimator {
val progressUpdater = ValueAnimator.ofFloat(0f, 1f)
val timings = AnimUtils.getDeviceAppPairLaunchTimings(dp.isTablet)
progressUpdater.setDuration(timings.getDuration().toLong())
@@ -860,12 +883,12 @@
// Shell animation: the apps are revealed toward end of the launch animation
progressUpdater.addUpdateListener { valueAnimator: ValueAnimator ->
val progress =
- Interpolators.clampToProgress(
- Interpolators.LINEAR,
- valueAnimator.animatedFraction,
- timings.appRevealStartOffset,
- timings.appRevealEndOffset
- )
+ Interpolators.clampToProgress(
+ Interpolators.LINEAR,
+ valueAnimator.animatedFraction,
+ timings.appRevealStartOffset,
+ timings.appRevealEndOffset
+ )
// Set the alpha of the shell layer (2 apps + divider)
t.setAlpha(rootCandidate.leash, progress)
@@ -873,65 +896,65 @@
}
progressUpdater.addUpdateListener(
- object : MultiValueUpdateListener() {
- var mDx =
- FloatProp(
- floatingView.startingPosition.left,
- dp.widthPx / 2f - floatingView.startingPosition.width() / 2f,
- Interpolators.clampToProgress(
- timings.getStagedRectXInterpolator(),
- timings.stagedRectSlideStartOffset,
- timings.stagedRectSlideEndOffset
- )
- )
- var mDy =
- FloatProp(
- floatingView.startingPosition.top,
- dp.heightPx / 2f - floatingView.startingPosition.height() / 2f,
- Interpolators.clampToProgress(
- Interpolators.EMPHASIZED,
- timings.stagedRectSlideStartOffset,
- timings.stagedRectSlideEndOffset
- )
- )
- var mScaleX =
- FloatProp(
- 1f /* start */,
- dp.widthPx / floatingView.startingPosition.width(),
- Interpolators.clampToProgress(
- Interpolators.EMPHASIZED,
- timings.stagedRectSlideStartOffset,
- timings.stagedRectSlideEndOffset
- )
- )
- var mScaleY =
- FloatProp(
- 1f /* start */,
- dp.heightPx / floatingView.startingPosition.height(),
- Interpolators.clampToProgress(
- Interpolators.EMPHASIZED,
- timings.stagedRectSlideStartOffset,
- timings.stagedRectSlideEndOffset
- )
- )
+ object : MultiValueUpdateListener() {
+ var mDx =
+ FloatProp(
+ floatingView.startingPosition.left,
+ dp.widthPx / 2f - floatingView.startingPosition.width() / 2f,
+ Interpolators.clampToProgress(
+ timings.getStagedRectXInterpolator(),
+ timings.stagedRectSlideStartOffset,
+ timings.stagedRectSlideEndOffset
+ )
+ )
+ var mDy =
+ FloatProp(
+ floatingView.startingPosition.top,
+ dp.heightPx / 2f - floatingView.startingPosition.height() / 2f,
+ Interpolators.clampToProgress(
+ Interpolators.EMPHASIZED,
+ timings.stagedRectSlideStartOffset,
+ timings.stagedRectSlideEndOffset
+ )
+ )
+ var mScaleX =
+ FloatProp(
+ 1f /* start */,
+ dp.widthPx / floatingView.startingPosition.width(),
+ Interpolators.clampToProgress(
+ Interpolators.EMPHASIZED,
+ timings.stagedRectSlideStartOffset,
+ timings.stagedRectSlideEndOffset
+ )
+ )
+ var mScaleY =
+ FloatProp(
+ 1f /* start */,
+ dp.heightPx / floatingView.startingPosition.height(),
+ Interpolators.clampToProgress(
+ Interpolators.EMPHASIZED,
+ timings.stagedRectSlideStartOffset,
+ timings.stagedRectSlideEndOffset
+ )
+ )
- override fun onUpdate(percent: Float, initOnly: Boolean) {
- floatingView.progress = percent
- floatingView.x = mDx.value
- floatingView.y = mDy.value
- floatingView.scaleX = mScaleX.value
- floatingView.scaleY = mScaleY.value
- floatingView.invalidate()
- }
+ override fun onUpdate(percent: Float, initOnly: Boolean) {
+ floatingView.progress = percent
+ floatingView.x = mDx.value
+ floatingView.y = mDy.value
+ floatingView.scaleX = mScaleX.value
+ floatingView.scaleY = mScaleY.value
+ floatingView.invalidate()
}
+ }
)
progressUpdater.addListener(
- object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator) {
- safeRemoveViewFromDragLayer(launcher, floatingView)
- finishCallback.run()
- }
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ safeRemoveViewFromDragLayer(launcher, floatingView)
+ finishCallback.run()
}
+ }
)
return progressUpdater
@@ -939,9 +962,8 @@
/**
* This is a scale-up-and-fade-in animation (34% to 100%) for launching an app in Overview when
- * there is no visible associated tile to expand from.
- * [windowingMode] helps determine whether we are looking for a split or a single fullscreen
- * [Change]
+ * there is no visible associated tile to expand from. [windowingMode] helps determine whether
+ * we are looking for a split or a single fullscreen [Change]
*/
@VisibleForTesting
fun composeScaleUpLaunchAnimation(
@@ -1095,12 +1117,12 @@
animator.setDuration(QuickstepTransitionManager.SPLIT_LAUNCH_DURATION.toLong())
animator.addUpdateListener { valueAnimator: ValueAnimator ->
val progress =
- Interpolators.clampToProgress(
- Interpolators.LINEAR,
- valueAnimator.animatedFraction,
- 0.8f,
- 1f
- )
+ Interpolators.clampToProgress(
+ Interpolators.LINEAR,
+ valueAnimator.animatedFraction,
+ 0.8f,
+ 1f
+ )
for (leash in openingTargets) {
animTransaction.setAlpha(leash, progress)
}
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index 4915b62..57bc2d7 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -16,7 +16,7 @@
package com.android.quickstep.views;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
@@ -31,7 +31,6 @@
import android.graphics.drawable.shapes.RoundRectShape;
import android.util.AttributeSet;
import android.util.Log;
-import android.util.SparseArray;
import android.view.View;
import android.widget.FrameLayout;
@@ -43,6 +42,7 @@
import com.android.launcher3.desktop.DesktopRecentsTransitionController;
import com.android.launcher3.util.CancellableTask;
import com.android.launcher3.util.RunnableList;
+import com.android.launcher3.util.ViewPool;
import com.android.quickstep.BaseContainerInterface;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.TaskThumbnailCache;
@@ -70,14 +70,6 @@
private static final boolean DEBUG = false;
- @NonNull
- private List<Task> mTasks = new ArrayList<>();
-
- private final ArrayList<TaskThumbnailViewDeprecated> mSnapshotViews = new ArrayList<>();
-
- /** Maps {@code taskIds} to corresponding {@link TaskThumbnailViewDeprecated}s */
- private final SparseArray<TaskThumbnailViewDeprecated> mSnapshotViewMap = new SparseArray<>();
-
private final ArrayList<CancellableTask<?>> mPendingThumbnailRequests = new ArrayList<>();
private final TaskView.FullscreenDrawParams mSnapshotDrawParams;
@@ -88,6 +80,8 @@
private final PointF mTempPointF = new PointF();
+ private final ViewPool<TaskThumbnailViewDeprecated> mTaskthumbnailViewPool;
+
public DesktopTaskView(Context context) {
this(context, null);
}
@@ -110,6 +104,10 @@
return QuickStepContract.getWindowCornerRadius(context);
}
};
+ // As DesktopTaskView is inflated in background, use initialSize=0 to avoid initPool.
+ mTaskthumbnailViewPool = new ViewPool<>(context, this, R.layout.task_thumbnail,
+ /* maxSize= */10, /* initialSize= */ 0);
+ mTaskContainers = new ArrayList<>();
}
@Override
@@ -146,8 +144,7 @@
mContainer.getDragLayer().getDescendantRectRelativeToSelf(mBackgroundView, bounds);
} else {
bounds.set(mBackgroundView.getLeft(), mBackgroundView.getTop(),
- mBackgroundView.getRight(),
- mBackgroundView.getBottom());
+ mBackgroundView.getRight(), mBackgroundView.getBottom());
}
return Unit.INSTANCE;
}
@@ -171,83 +168,36 @@
}
cancelPendingLoadTasks();
- mTasks = new ArrayList<>(tasks);
- mSnapshotViewMap.clear();
-
- // Ensure there are equal number of snapshot views and tasks.
- // More tasks than views, add views. More views than tasks, remove views.
- // TODO(b/251586230): use a ViewPool for creating TaskThumbnailViews
- if (mSnapshotViews.size() > mTasks.size()) {
- int diff = mSnapshotViews.size() - mTasks.size();
- for (int i = 0; i < diff; i++) {
- TaskThumbnailViewDeprecated snapshotView = mSnapshotViews.remove(0);
- removeView(snapshotView);
- }
- } else if (mSnapshotViews.size() < mTasks.size()) {
- int diff = mTasks.size() - mSnapshotViews.size();
- for (int i = 0; i < diff; i++) {
- TaskThumbnailViewDeprecated snapshotView =
- new TaskThumbnailViewDeprecated(getContext());
- mSnapshotViews.add(snapshotView);
- // Add snapshots from to position after the initial child views.
- addView(snapshotView, mChildCountAtInflation,
+ ((ArrayList<TaskContainer>) mTaskContainers).ensureCapacity(tasks.size());
+ for (int i = 0; i < tasks.size(); i++) {
+ Task task = tasks.get(i);
+ TaskThumbnailViewDeprecated thumbnailView;
+ if (i >= mTaskContainers.size()) {
+ thumbnailView = mTaskthumbnailViewPool.getView();
+ // Add thumbnailView from to position after the initial child views.
+ addView(thumbnailView, mChildCountAtInflation,
new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
+ } else {
+ thumbnailView = mTaskContainers.get(i).getThumbnailView();
+ }
+ thumbnailView.bind(task);
+ TaskContainer taskContainer = new TaskContainer(task, thumbnailView, mIconView,
+ STAGE_POSITION_UNDEFINED, /*digitalWellBeingToast=*/ null);
+ if (i >= mTaskContainers.size()) {
+ mTaskContainers.add(taskContainer);
+ } else {
+ mTaskContainers.set(i, taskContainer);
}
}
-
- for (int i = 0; i < mTasks.size(); i++) {
- Task task = mTasks.get(i);
- TaskThumbnailViewDeprecated snapshotView = mSnapshotViews.get(i);
- snapshotView.bind(task);
- mSnapshotViewMap.put(task.key.id, snapshotView);
+ while (mTaskContainers.size() > tasks.size()) {
+ TaskContainer taskContainer = mTaskContainers.remove(mTaskContainers.size() - 1);
+ removeView(taskContainer.getThumbnailView());
+ mTaskthumbnailViewPool.recycle(taskContainer.getThumbnailView());
}
- updateTaskIdContainer();
- updateTaskIdAttributeContainer();
-
setOrientationState(orientedState);
}
- private void updateTaskIdContainer() {
- mTaskIdContainer = new int[mTasks.size()];
- for (int i = 0; i < mTasks.size(); i++) {
- mTaskIdContainer[i] = mTasks.get(i).key.id;
- }
- }
-
- private void updateTaskIdAttributeContainer() {
- mTaskIdAttributeContainer = new TaskIdAttributeContainer[mTasks.size()];
- for (int i = 0; i < mTasks.size(); i++) {
- Task task = mTasks.get(i);
- TaskThumbnailViewDeprecated thumbnailView = mSnapshotViewMap.get(task.key.id);
- mTaskIdAttributeContainer[i] = createAttributeContainer(task, thumbnailView);
- }
- }
-
- private TaskIdAttributeContainer createAttributeContainer(Task task,
- TaskThumbnailViewDeprecated thumbnailView) {
- return new TaskIdAttributeContainer(task, thumbnailView, mIconView,
- STAGE_POSITION_UNDEFINED);
- }
-
- @Nullable
- @Override
- public Task getTask() {
- // TODO(b/249371338): returning first task. This won't work well with multiple tasks.
- return mTasks.size() > 0 ? mTasks.get(0) : null;
- }
-
- @Override
- public TaskThumbnailViewDeprecated getThumbnail() {
- // TODO(b/249371338): returning single thumbnail. This won't work well with multiple tasks.
- Task task = getTask();
- if (task != null) {
- return mSnapshotViewMap.get(task.key.id);
- }
- // Return the place holder snapshot views. Callers expect this to be non-null
- return mTaskThumbnailViewDeprecated;
- }
-
@Override
public void onTaskListVisibilityChanged(boolean visible, int changes) {
cancelPendingLoadTasks();
@@ -256,15 +206,12 @@
TaskThumbnailCache thumbnailCache = model.getThumbnailCache();
if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
- for (Task task : mTasks) {
+ for (TaskContainer container : mTaskContainers) {
CancellableTask<?> thumbLoadRequest =
- thumbnailCache.updateThumbnailInBackground(task, thumbnailData -> {
- TaskThumbnailViewDeprecated thumbnailView =
- mSnapshotViewMap.get(task.key.id);
- if (thumbnailView != null) {
- thumbnailView.setThumbnail(task, thumbnailData);
- }
- });
+ thumbnailCache.updateThumbnailInBackground(container.getTask(),
+ thumbnailData -> container.getThumbnailView().setThumbnail(
+ container.getTask(),
+ thumbnailData));
if (thumbLoadRequest != null) {
mPendingThumbnailRequests.add(thumbLoadRequest);
}
@@ -272,13 +219,10 @@
}
} else {
if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
- for (Task task : mTasks) {
- TaskThumbnailViewDeprecated thumbnailView = mSnapshotViewMap.get(task.key.id);
- if (thumbnailView != null) {
- thumbnailView.setThumbnail(null, null);
- }
+ for (TaskContainer container : mTaskContainers) {
+ container.getThumbnailView().setThumbnail(null, null);
// Reset the task thumbnail ref
- task.thumbnail = null;
+ container.getTask().thumbnail = null;
}
}
}
@@ -327,42 +271,19 @@
}
@Override
- public boolean isDesktopTask() {
- return true;
- }
-
- @Override
void refreshThumbnails(@Nullable HashMap<Integer, ThumbnailData> thumbnailDatas) {
// Sets new thumbnails based on the incoming data and refreshes the rest.
- // Create a copy of the thumbnail map, so we can track thumbnails that need refreshing.
- SparseArray<TaskThumbnailViewDeprecated> thumbnailsToRefresh = mSnapshotViewMap.clone();
if (thumbnailDatas != null) {
- for (Task task : mTasks) {
- int key = task.key.id;
- TaskThumbnailViewDeprecated thumbnailView = thumbnailsToRefresh.get(key);
- ThumbnailData thumbnailData = thumbnailDatas.get(key);
- if (thumbnailView != null && thumbnailData != null) {
- thumbnailView.setThumbnail(task, thumbnailData);
- // Remove this thumbnail from the list that should be refreshed.
- thumbnailsToRefresh.remove(key);
+ for (TaskContainer container : mTaskContainers) {
+ ThumbnailData thumbnailData = thumbnailDatas.get(container.getTask().key.id);
+ if (thumbnailData != null) {
+ container.getThumbnailView().setThumbnail(container.getTask(), thumbnailData);
+ } else {
+ // Refresh the rest that were not updated.
+ container.getThumbnailView().refresh();
}
}
}
-
- // Refresh the rest that were not updated.
- for (int i = 0; i < thumbnailsToRefresh.size(); i++) {
- thumbnailsToRefresh.valueAt(i).refresh();
- }
- }
-
- @Override
- public TaskThumbnailViewDeprecated[] getThumbnails() {
- TaskThumbnailViewDeprecated[] thumbnails =
- new TaskThumbnailViewDeprecated[mSnapshotViewMap.size()];
- for (int i = 0; i < thumbnails.length; i++) {
- thumbnails[i] = mSnapshotViewMap.valueAt(i);
- }
- return thumbnails;
}
@Override
@@ -370,11 +291,8 @@
resetPersistentViewTransforms();
// Clear any references to the thumbnail (it will be re-read either from the cache or the
// system on next bind)
- for (Task task : mTasks) {
- TaskThumbnailViewDeprecated thumbnailView = mSnapshotViewMap.get(task.key.id);
- if (thumbnailView != null) {
- thumbnailView.setThumbnail(task, null);
- }
+ for (TaskContainer container : mTaskContainers) {
+ container.getThumbnailView().setThumbnail(container.getTask(), null);
}
setOverlayEnabled(false);
onTaskListVisibilityChanged(false);
@@ -392,8 +310,7 @@
int thumbnailTopMarginPx = mContainer.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
containerHeight -= thumbnailTopMarginPx;
- int thumbnails = mSnapshotViewMap.size();
- if (thumbnails == 0) {
+ if (mTaskContainers.isEmpty()) {
return;
}
@@ -413,8 +330,8 @@
}
// Desktop tile is a shrunk down version of launcher and freeform task thumbnails.
- for (int i = 0; i < mTasks.size(); i++) {
- Task task = mTasks.get(i);
+ for (TaskContainer container : mTaskContainers) {
+ Task task = container.getTask();
Rect taskSize = task.appBounds;
if (taskSize == null) {
// Default to quarter of the desktop if we did not get app bounds.
@@ -424,7 +341,7 @@
int thumbWidth = (int) (taskSize.width() * scaleWidth);
int thumbHeight = (int) (taskSize.height() * scaleHeight);
- TaskThumbnailViewDeprecated thumbnailView = mSnapshotViewMap.get(task.key.id);
+ TaskThumbnailViewDeprecated thumbnailView = container.getThumbnailView();
if (thumbnailView != null) {
thumbnailView.measure(MeasureSpec.makeMeasureSpec(thumbWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(thumbHeight, MeasureSpec.EXACTLY));
@@ -466,9 +383,8 @@
} else {
mBackgroundView.setVisibility(VISIBLE);
}
- for (int i = 0; i < mSnapshotViewMap.size(); i++) {
- TaskThumbnailViewDeprecated thumbnailView = mSnapshotViewMap.valueAt(i);
- thumbnailView.getTaskOverlay().setFullscreenProgress(progress);
+ for (TaskContainer container : mTaskContainers) {
+ container.getThumbnailView().getTaskOverlay().setFullscreenProgress(progress);
}
// Animate icons and DWB banners in/out, except in QuickSwitch state, when tiles are
// oversized and banner would look disproportionately large.
@@ -482,33 +398,30 @@
@Override
protected void updateSnapshotRadius() {
super.updateSnapshotRadius();
- for (int i = 0; i < mSnapshotViewMap.size(); i++) {
- if (i == 0) {
- // All snapshots share the same params. Only update it with the first snapshot.
- updateFullscreenParams(mSnapshotDrawParams);
- }
- mSnapshotViewMap.valueAt(i).setFullscreenParams(mSnapshotDrawParams);
+ updateFullscreenParams(mSnapshotDrawParams);
+ for (TaskContainer container : mTaskContainers) {
+ container.getThumbnailView().setFullscreenParams(mSnapshotDrawParams);
}
}
@Override
public void setColorTint(float amount, int tintColor) {
- for (int i = 0; i < mSnapshotViewMap.size(); i++) {
- mSnapshotViewMap.valueAt(i).setDimAlpha(amount);
+ for (TaskContainer container : mTaskContainers) {
+ container.getThumbnailView().setDimAlpha(amount);
}
}
@Override
protected void applyThumbnailSplashAlpha() {
- for (int i = 0; i < mSnapshotViewMap.size(); i++) {
- mSnapshotViewMap.valueAt(i).setSplashAlpha(mTaskThumbnailSplashAlpha);
+ for (TaskContainer container : mTaskContainers) {
+ container.getThumbnailView().setSplashAlpha(mTaskThumbnailSplashAlpha);
}
}
@Override
void setThumbnailVisibility(int visibility, int taskId) {
- for (int i = 0; i < mSnapshotViewMap.size(); i++) {
- mSnapshotViewMap.valueAt(i).setVisibility(visibility);
+ for (TaskContainer container : mTaskContainers) {
+ container.getThumbnailView().setVisibility(visibility);
}
}
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
index 82ba30b..f92b9dd 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -320,12 +320,12 @@
(FrameLayout.LayoutParams) mBanner.getLayoutParams();
DeviceProfile deviceProfile = mContainer.getDeviceProfile();
layoutParams.bottomMargin = ((ViewGroup.MarginLayoutParams)
- mTaskView.getThumbnail().getLayoutParams()).bottomMargin;
+ mTaskView.getFirstThumbnailView().getLayoutParams()).bottomMargin;
RecentsPagedOrientationHandler orientationHandler = mTaskView.getPagedOrientationHandler();
Pair<Float, Float> translations = orientationHandler
.getDwbLayoutTranslations(mTaskView.getMeasuredWidth(),
mTaskView.getMeasuredHeight(), mSplitBounds, deviceProfile,
- mTaskView.getThumbnails(), mTask.key.id, mBanner);
+ mTaskView.getThumbnailViews(), mTask.key.id, mBanner);
mSplitOffsetTranslationX = translations.first;
mSplitOffsetTranslationY = translations.second;
updateTranslationY();
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index b2a8503..1b4d22f 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -64,8 +64,6 @@
public class GroupedTaskView extends TaskView {
private static final String TAG = GroupedTaskView.class.getSimpleName();
- @Nullable
- private Task mSecondaryTask;
// TODO(b/336612373): Support new TTV for GroupedTaskView
private TaskThumbnailViewDeprecated mSnapshotView2;
private TaskViewIcon mIconView2;
@@ -92,6 +90,17 @@
mDigitalWellBeingToast2 = new DigitalWellBeingToast(mContainer, this);
}
+ /**
+ * Returns the second task bound to this TaskView.
+ *
+ * @deprecated Use {@link #mTaskContainers} instead.
+ */
+ @Deprecated
+ @Nullable
+ private Task getSecondTask() {
+ return mTaskContainers.size() > 1 ? mTaskContainers.get(1).getTask() : null;
+ }
+
@Override
public Unit getThumbnailBounds(@NonNull Rect bounds, boolean relativeToDragLayer) {
if (mSplitBoundsConfig == null) {
@@ -141,13 +150,11 @@
public void bind(Task primary, Task secondary, RecentsOrientedState orientedState,
@Nullable SplitBounds splitBoundsConfig) {
super.bind(primary, orientedState);
- mSecondaryTask = secondary;
- mTaskIdContainer = new int[]{mTaskIdContainer[0], secondary.key.id};
- mTaskIdAttributeContainer = new TaskIdAttributeContainer[]{
- mTaskIdAttributeContainer[0],
- new TaskIdAttributeContainer(secondary, mSnapshotView2,
- mIconView2, STAGE_POSITION_BOTTOM_OR_RIGHT)};
- mTaskIdAttributeContainer[0].setStagePosition(
+ mTaskContainers = Arrays.asList(
+ mTaskContainers.get(0),
+ new TaskContainer(secondary, findViewById(R.id.bottomright_snapshot),
+ mIconView2, STAGE_POSITION_BOTTOM_OR_RIGHT, mDigitalWellBeingToast2));
+ mTaskContainers.get(0).setStagePosition(
SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT);
mSnapshotView2.bind(secondary);
mSplitBoundsConfig = splitBoundsConfig;
@@ -169,12 +176,12 @@
public void setUpShowAllInstancesListener() {
// sets up the listener for the left/top task
super.setUpShowAllInstancesListener();
- if (mTaskIdAttributeContainer.length < 2) {
+ if (mTaskContainers.size() < 2) {
return;
}
// right/bottom task's base package name
- String taskPackageName = mTaskIdAttributeContainer[1].getTask().key.getPackageName();
+ String taskPackageName = mTaskContainers.get(1).getTask().key.getPackageName();
// icon of the right/bottom task
View showWindowsView = findViewById(R.id.show_windows_right);
@@ -190,20 +197,21 @@
TaskIconCache iconCache = model.getIconCache();
if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
- mThumbnailLoadRequest2 = thumbnailCache.updateThumbnailInBackground(mSecondaryTask,
- thumbnailData -> mSnapshotView2.setThumbnail(
- mSecondaryTask, thumbnailData
+ mThumbnailLoadRequest2 = thumbnailCache.updateThumbnailInBackground(
+ getSecondTask(),
+ thumbnailData -> mSnapshotView2.setThumbnail(getSecondTask(),
+ thumbnailData
));
}
if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
- mIconLoadRequest2 = iconCache.updateIconInBackground(mSecondaryTask,
+ mIconLoadRequest2 = iconCache.updateIconInBackground(getSecondTask(),
(task) -> {
setIcon(mIconView2, task.icon);
if (enableOverviewIconMenu()) {
setText(mIconView2, task.title);
}
- mDigitalWellBeingToast2.initialize(mSecondaryTask);
+ mDigitalWellBeingToast2.initialize(getSecondTask());
mDigitalWellBeingToast2.setSplitConfiguration(mSplitBoundsConfig);
mDigitalWellBeingToast.setSplitConfiguration(mSplitBoundsConfig);
});
@@ -213,7 +221,7 @@
mSnapshotView2.setThumbnail(null, null);
// Reset the task thumbnail reference as well (it will be fetched from the cache or
// reloaded next time we need it)
- mSecondaryTask.thumbnail = null;
+ getSecondTask().thumbnail = null;
}
if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
setIcon(mIconView2, null);
@@ -271,7 +279,7 @@
@Nullable
@Override
public RunnableList launchTaskAnimated() {
- if (mTask == null || mSecondaryTask == null) {
+ if (mTaskContainers.isEmpty()) {
return null;
}
@@ -304,8 +312,8 @@
private void launchTaskInternal(@NonNull Consumer<Boolean> callback, boolean isQuickswitch,
boolean launchingExistingTaskView) {
getRecentsView().getSplitSelectController().launchExistingSplitPair(
- launchingExistingTaskView ? this : null, mTask.key.id,
- mSecondaryTask.key.id, SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT,
+ launchingExistingTaskView ? this : null, getFirstTask().key.id,
+ getSecondTask().key.id, SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT,
callback, isQuickswitch, getSnapPosition());
Log.d(TAG, "launchTaskInternal - launchExistingSplitPair: " + Arrays.toString(
getTaskIds()));
@@ -314,10 +322,10 @@
@Override
void refreshThumbnails(@Nullable HashMap<Integer, ThumbnailData> thumbnailDatas) {
super.refreshThumbnails(thumbnailDatas);
- if (mSecondaryTask != null && thumbnailDatas != null) {
- final ThumbnailData thumbnailData = thumbnailDatas.get(mSecondaryTask.key.id);
+ if (getSecondTask() != null && thumbnailDatas != null) {
+ final ThumbnailData thumbnailData = thumbnailDatas.get(getSecondTask().key.id);
if (thumbnailData != null) {
- mSnapshotView2.setThumbnail(mSecondaryTask, thumbnailData);
+ mSnapshotView2.setThumbnail(getSecondTask(), thumbnailData);
return;
}
}
@@ -325,11 +333,6 @@
mSnapshotView2.refresh();
}
- @Override
- public TaskThumbnailViewDeprecated[] getThumbnails() {
- return new TaskThumbnailViewDeprecated[]{mTaskThumbnailViewDeprecated, mSnapshotView2};
- }
-
/**
* Returns taskId that split selection was initiated with,
* {@link ActivityTaskManager#INVALID_TASK_ID} if no tasks in this TaskView are part of
@@ -350,7 +353,7 @@
// below aren't reliable since both of those views may be gone/transformed
int initSplitTaskId = getThisTaskCurrentlyInSplitSelection();
if (initSplitTaskId != INVALID_TASK_ID) {
- return initSplitTaskId == mTask.key.id ? 1 : 0;
+ return initSplitTaskId == getFirstTask().key.id ? 1 : 0;
}
}
@@ -371,7 +374,7 @@
@Override
public void onRecycle() {
super.onRecycle();
- mSnapshotView2.setThumbnail(mSecondaryTask, null);
+ mSnapshotView2.setThumbnail(getSecondTask(), null);
mSplitBoundsConfig = null;
}
@@ -404,9 +407,8 @@
} else {
// Currently being split with this taskView, let the non-split selected thumbnail
// take up full thumbnail area
- Optional<TaskIdAttributeContainer> nonSplitContainer = Arrays.stream(
- mTaskIdAttributeContainer).filter(
- container -> container.getTask().key.id != initSplitTaskId).findAny();
+ Optional<TaskContainer> nonSplitContainer = mTaskContainers.stream().filter(
+ container -> container.getTask().key.id != initSplitTaskId).findAny();
nonSplitContainer.ifPresent(
taskIdAttributeContainer -> taskIdAttributeContainer.getThumbnailView().measure(
widthMeasureSpec, MeasureSpec.makeMeasureSpec(
@@ -492,10 +494,10 @@
}
private void updateSecondaryDwbPlacement() {
- if (mSecondaryTask == null) {
+ if (getSecondTask() == null) {
return;
}
- mDigitalWellBeingToast2.initialize(mSecondaryTask);
+ mDigitalWellBeingToast2.initialize(getSecondTask());
}
@Override
@@ -548,17 +550,11 @@
*/
@Override
void setThumbnailVisibility(int visibility, int taskId) {
- if (visibility == VISIBLE) {
- mTaskThumbnailViewDeprecated.setVisibility(visibility);
- mDigitalWellBeingToast.setBannerVisibility(visibility);
- mSnapshotView2.setVisibility(visibility);
- mDigitalWellBeingToast2.setBannerVisibility(visibility);
- } else if (mTaskIdContainer.length > 0 && mTaskIdContainer[0] == taskId) {
- mTaskThumbnailViewDeprecated.setVisibility(visibility);
- mDigitalWellBeingToast.setBannerVisibility(visibility);
- } else {
- mSnapshotView2.setVisibility(visibility);
- mDigitalWellBeingToast2.setBannerVisibility(visibility);
+ for (TaskContainer container : mTaskContainers) {
+ if (visibility == VISIBLE || container.getTask().key.id == taskId) {
+ container.getThumbnailView().setVisibility(visibility);
+ container.getDigitalWellBeingToast().setBannerVisibility(visibility);
+ }
}
}
}
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 5188d4a..8a917d6 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -20,6 +20,7 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.FloatProperty;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
@@ -33,9 +34,7 @@
import com.android.launcher3.Flags;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.DisplayController;
-import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.NavigationMode;
import com.android.quickstep.TaskOverlayFactory.OverlayUICallbacks;
@@ -43,12 +42,26 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.function.Consumer;
/**
* View for showing action buttons in Overview
*/
public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayout
implements OnClickListener, Insettable {
+ public static final FloatProperty<Consumer<Float>> FLOAT_SETTER =
+ new FloatProperty<>("floatSetter") {
+ @Override
+ public void setValue(Consumer<Float> consumer, float v) {
+ consumer.accept(v);
+ }
+
+ @Override
+ public Float get(Consumer<Float> consumer) {
+ return -1f;
+ }
+ };
private final Rect mInsets = new Rect();
@@ -89,30 +102,24 @@
private static final int INDEX_HIDDEN_FLAGS_ALPHA = 3;
private static final int INDEX_SHARE_TARGET_ALPHA = 4;
private static final int INDEX_SCROLL_ALPHA = 5;
- private static final int NUM_ALPHAS = 6;
-
- public @interface ScreenshotButtonHiddenFlags { }
- public static final int FLAG_MULTIPLE_TASKS_HIDE_SCREENSHOT = 1 << 0;
+ private static final int INDEX_GROUPED_ALPHA = 6;
+ private static final int INDEX_3P_LAUNCHER = 7;
+ private static final int NUM_ALPHAS = 8;
public @interface SplitButtonHiddenFlags { }
public static final int FLAG_SMALL_SCREEN_HIDE_SPLIT = 1 << 0;
- public static final int FLAG_MULTIPLE_TASKS_HIDE_SPLIT = 1 << 1;
- public @interface SplitButtonDisabledFlags { }
- public static final int FLAG_SINGLE_TASK_DISABLE_SPLIT = 1 << 0;
+ /** Holds MultiValueAlpha values for all actions buttons */
+ private final MultiValueAlpha[] mMultiValueAlphas = new MultiValueAlpha[2];
+ /** Index used for single-task actions in the mMultiValueAlphas array */
+ private static final int ACTIONS_ALPHAS = 0;
+ /** Index used for grouped-task actions in the mMultiValueAlphas array */
+ private static final int GROUP_ACTIONS_ALPHAS = 1;
- public @interface AppPairButtonHiddenFlags { }
- public static final int FLAG_SINGLE_TASK_HIDE_APP_PAIR = 1 << 0;
- public static final int FLAG_SMALL_SCREEN_HIDE_APP_PAIR = 1 << 1;
- public static final int FLAG_3P_LAUNCHER_HIDE_APP_PAIR = 1 << 2;
-
- private MultiValueAlpha mMultiValueAlpha;
-
+ /** Container for the action buttons below a focused, non-split Overview tile. */
protected LinearLayout mActionButtons;
- // The screenshot button is implemented as a Button in launcher3 and NexusLauncher, but is an
- // ImageButton in go launcher (does not share a common class with Button). Take care when
- // casting this.
- private View mScreenshotButton;
+ /** Container for the action buttons below a focused, split Overview tile. */
+ protected LinearLayout mGroupActionButtons;
private Button mSplitButton;
private Button mSaveAppPairButton;
@@ -122,21 +129,16 @@
@ActionsDisabledFlags
protected int mDisabledFlags;
- @ScreenshotButtonHiddenFlags
- private int mScreenshotButtonHiddenFlags;
-
@SplitButtonHiddenFlags
private int mSplitButtonHiddenFlags;
- @AppPairButtonHiddenFlags
- private int mAppPairButtonHiddenFlags;
-
@Nullable
protected T mCallbacks;
@Nullable
protected DeviceProfile mDp;
private final Rect mTaskSize = new Rect();
+ private boolean mIsGroupedTask = false;
public OverviewActionsView(Context context) {
this(context, null);
@@ -153,12 +155,21 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ // Initialize 2 view containers: one for single tasks, one for grouped tasks.
+ // These will take up the same space on the screen and alternate visibility as needed.
mActionButtons = findViewById(R.id.action_buttons);
- mMultiValueAlpha = new MultiValueAlpha(mActionButtons, NUM_ALPHAS);
- mMultiValueAlpha.setUpdateVisibility(true);
+ mGroupActionButtons = findViewById(R.id.group_action_buttons);
+ // Initialize a list to set alpha on mActionButtons and mGroupActionButtons simultaneously.
+ mMultiValueAlphas[ACTIONS_ALPHAS] = new MultiValueAlpha(mActionButtons, NUM_ALPHAS);
+ mMultiValueAlphas[GROUP_ACTIONS_ALPHAS] =
+ new MultiValueAlpha(mGroupActionButtons, NUM_ALPHAS);
+ Arrays.stream(mMultiValueAlphas).forEach(a -> a.setUpdateVisibility(true));
- mScreenshotButton = findViewById(R.id.action_screenshot);
- mScreenshotButton.setOnClickListener(this);
+ // The screenshot button is implemented as a Button in launcher3 and NexusLauncher, but is
+ // an ImageButton in go launcher (does not share a common class with Button). Take care when
+ // casting this.
+ View screenshotButton = findViewById(R.id.action_screenshot);
+ screenshotButton.setOnClickListener(this);
mSplitButton = findViewById(R.id.action_split);
mSplitButton.setOnClickListener(this);
mSaveAppPairButton = findViewById(R.id.action_save_app_pair);
@@ -209,7 +220,7 @@
mHiddenFlags &= ~visibilityFlags;
}
boolean isHidden = mHiddenFlags != 0;
- mMultiValueAlpha.get(INDEX_HIDDEN_FLAGS_ALPHA).setValue(isHidden ? 0 : 1);
+ setActionsAlpha(INDEX_HIDDEN_FLAGS_ALPHA, isHidden ? 0 : 1);
}
/**
@@ -236,12 +247,8 @@
* @param isGroupedTask True if the focused task is a grouped task.
*/
public void updateForGroupedTask(boolean isGroupedTask) {
- // Update flags to see if split button should be hidden.
- updateSplitButtonHiddenFlags(FLAG_MULTIPLE_TASKS_HIDE_SPLIT, isGroupedTask);
- // Update flags to see if screenshot button should be hidden.
- updateScreenshotButtonHiddenFlags(FLAG_MULTIPLE_TASKS_HIDE_SCREENSHOT, isGroupedTask);
- // Update flags to see if save app pair button should be hidden.
- updateAppPairButtonHiddenFlags(FLAG_SINGLE_TASK_HIDE_APP_PAIR, !isGroupedTask);
+ mIsGroupedTask = isGroupedTask;
+ updateActionButtonsVisibility();
}
/**
@@ -251,36 +258,30 @@
assert mDp != null;
// Update flags to see if split button should be hidden.
updateSplitButtonHiddenFlags(FLAG_SMALL_SCREEN_HIDE_SPLIT, !mDp.isTablet);
- // Update flags to see if save app pair button should be hidden.
- updateAppPairButtonHiddenFlags(FLAG_SMALL_SCREEN_HIDE_APP_PAIR, !mDp.isTablet);
+ updateActionButtonsVisibility();
+ }
+
+ private void updateActionButtonsVisibility() {
+ assert mDp != null;
+ boolean showSingleTaskActions = !mIsGroupedTask;
+ boolean showGroupActions = mIsGroupedTask && mDp.isTablet;
+ getActionsAlphas().get(INDEX_GROUPED_ALPHA).setValue(showSingleTaskActions ? 1 : 0);
+ getGroupActionsAlphas().get(INDEX_GROUPED_ALPHA).setValue(showGroupActions ? 1 : 0);
}
/**
* Updates flags to hide and show actions buttons for 1p/3p launchers.
*/
public void updateFor3pLauncher(boolean is3pLauncher) {
- updateAppPairButtonHiddenFlags(FLAG_3P_LAUNCHER_HIDE_APP_PAIR, is3pLauncher);
+ getGroupActionsAlphas().get(INDEX_3P_LAUNCHER).setValue(is3pLauncher ? 0 : 1);
}
- /**
- * Updates the proper flags to indicate whether the "Screenshot" button should be hidden.
- *
- * @param flag The flag to update.
- * @param enable Whether to enable the hidden flag: True will cause view to be hidden.
- */
- private void updateScreenshotButtonHiddenFlags(@ScreenshotButtonHiddenFlags int flag,
- boolean enable) {
- if (mScreenshotButton == null) return;
- if (enable) {
- mScreenshotButtonHiddenFlags |= flag;
- } else {
- mScreenshotButtonHiddenFlags &= ~flag;
- }
- int desiredVisibility = mScreenshotButtonHiddenFlags == 0 ? VISIBLE : GONE;
- if (mScreenshotButton.getVisibility() != desiredVisibility) {
- mScreenshotButton.setVisibility(desiredVisibility);
- mActionButtons.requestLayout();
- }
+ private MultiValueAlpha getActionsAlphas() {
+ return mMultiValueAlphas[ACTIONS_ALPHAS];
+ }
+
+ private MultiValueAlpha getGroupActionsAlphas() {
+ return mMultiValueAlphas[GROUP_ACTIONS_ALPHAS];
}
/**
@@ -304,56 +305,36 @@
}
}
- /**
- * Updates the proper flags to indicate whether the "Save app pair" button should be disabled.
- *
- * @param flag The flag to update.
- * @param enable Whether to enable the hidden flag: True will cause view to be hidden.
- */
- private void updateAppPairButtonHiddenFlags(
- @AppPairButtonHiddenFlags int flag, boolean enable) {
- if (!FeatureFlags.enableAppPairs()) {
- return;
- }
-
- if (mSaveAppPairButton == null) return;
- if (enable) {
- mAppPairButtonHiddenFlags |= flag;
- } else {
- mAppPairButtonHiddenFlags &= ~flag;
- }
- int desiredVisibility = mAppPairButtonHiddenFlags == 0 ? VISIBLE : GONE;
- if (mSaveAppPairButton.getVisibility() != desiredVisibility) {
- mSaveAppPairButton.setVisibility(desiredVisibility);
- mActionButtons.requestLayout();
- }
+ private void setActionsAlpha(int index, float value) {
+ Arrays.stream(mMultiValueAlphas).forEach(a -> a.get(index).setValue(value));
}
- public MultiProperty getContentAlpha() {
- return mMultiValueAlpha.get(INDEX_CONTENT_ALPHA);
+ public Consumer<Float> getContentAlphaSetter() {
+ return v -> setActionsAlpha(INDEX_CONTENT_ALPHA, v);
}
- public MultiProperty getVisibilityAlpha() {
- return mMultiValueAlpha.get(INDEX_VISIBILITY_ALPHA);
+ public Consumer<Float> getVisibilityAlphaSetter() {
+ return v -> setActionsAlpha(INDEX_VISIBILITY_ALPHA, v);
}
- public MultiProperty getFullscreenAlpha() {
- return mMultiValueAlpha.get(INDEX_FULLSCREEN_ALPHA);
+ public Consumer<Float> getFullscreenAlphaSetter() {
+ return v -> setActionsAlpha(INDEX_FULLSCREEN_ALPHA, v);
}
- public MultiProperty getShareTargetAlpha() {
- return mMultiValueAlpha.get(INDEX_SHARE_TARGET_ALPHA);
+ public Consumer<Float> getShareTargetAlphaSetter() {
+ return v -> setActionsAlpha(INDEX_SHARE_TARGET_ALPHA, v);
}
- public MultiProperty getIndexScrollAlpha() {
- return mMultiValueAlpha.get(INDEX_SCROLL_ALPHA);
+ public Consumer<Float> getIndexScrollAlphaSetter() {
+ return v -> setActionsAlpha(INDEX_SCROLL_ALPHA, v);
}
/**
* Returns the visibility of the overview actions buttons.
*/
- public @Visibility int getActionsButtonVisibility() {
- return mActionButtons.getVisibility();
+ public boolean areActionsButtonsVisible() {
+ return mActionButtons.getVisibility() == View.VISIBLE
+ || mGroupActionButtons.getVisibility() == View.VISIBLE;
}
/**
@@ -366,10 +347,17 @@
/** Updates vertical margins for different navigation mode or configuration changes. */
public void updateVerticalMargin(NavigationMode mode) {
+ updateActionBarPosition(mActionButtons);
+ updateActionBarPosition(mGroupActionButtons);
+ }
+
+ /** Positions actions buttons according to device settings and insets. */
+ private void updateActionBarPosition(LinearLayout actionBar) {
if (mDp == null) {
return;
}
- LayoutParams actionParams = (LayoutParams) mActionButtons.getLayoutParams();
+
+ LayoutParams actionParams = (LayoutParams) actionBar.getLayoutParams();
actionParams.setMargins(
actionParams.leftMargin, mDp.overviewActionsTopMarginPx,
actionParams.rightMargin, getBottomMargin());
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 077cd1b..b5ce7f7 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -204,7 +204,7 @@
import com.android.quickstep.util.TaskVisualsChangeListener;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.VibrationConstants;
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
+import com.android.quickstep.views.TaskView.TaskContainer;
import com.android.systemui.plugins.ResourceProvider;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -591,7 +591,7 @@
if (taskView == null) {
return;
}
- Task.TaskKey taskKey = taskView.getTask().key;
+ Task.TaskKey taskKey = taskView.getFirstTask().key;
UI_HELPER_EXECUTOR.execute(new CancellableTask<>(
() -> PackageManagerWrapper.getInstance()
.getActivityInfo(taskKey.getComponent(), taskKey.userId) == null,
@@ -991,8 +991,7 @@
if (mHandleTaskStackChanges) {
TaskView taskView = getTaskViewByTaskId(taskId);
if (taskView != null) {
- for (TaskIdAttributeContainer container :
- taskView.getTaskIdAttributeContainers()) {
+ for (TaskContainer container : taskView.getTaskContainers()) {
if (container == null || taskId != container.getTask().key.id) {
continue;
}
@@ -1007,11 +1006,12 @@
public void onTaskIconChanged(String pkg, UserHandle user) {
for (int i = 0; i < getTaskViewCount(); i++) {
TaskView tv = requireTaskViewAt(i);
- Task task = tv.getTask();
+ Task task = tv.getFirstTask();
if (task != null && task.key != null && pkg.equals(task.key.getPackageName())
&& task.key.userId == user.getIdentifier()) {
task.icon = null;
- if (tv.getIconView().getDrawable() != null) {
+ TaskViewIcon firstIconView = tv.getFirstIconView();
+ if (firstIconView != null && firstIconView.getDrawable() != null) {
tv.onTaskListVisibilityChanged(true /* visible */);
}
}
@@ -1042,7 +1042,7 @@
continue;
}
// taskView could be a GroupedTaskView, so select the relevant task by ID
- TaskIdAttributeContainer taskAttributes = taskView.getTaskAttributesById(id);
+ TaskContainer taskAttributes = taskView.getTaskContainerById(id);
if (taskAttributes == null) {
continue;
}
@@ -1731,7 +1731,7 @@
int[] currentTaskIds;
TaskView currentTaskView = getTaskViewAt(mCurrentPage);
- if (currentTaskView != null && currentTaskView.getTask() != null) {
+ if (currentTaskView != null && currentTaskView.getFirstTask() != null) {
currentTaskIds = currentTaskView.getTaskIds();
} else {
currentTaskIds = new int[0];
@@ -2019,7 +2019,7 @@
mClearAllButton.setFullscreenProgress(fullscreenProgress);
// Fade out the actions view quickly (0.1 range)
- mActionsView.getFullscreenAlpha().setValue(
+ mActionsView.getFullscreenAlphaSetter().accept(
mapToRange(fullscreenProgress, 0, 0.1f, 1f, 0f, LINEAR));
}
@@ -2270,8 +2270,8 @@
}
private void animateActionsViewAlpha(float alphaValue, long duration) {
- mActionsViewAlphaAnimator = ObjectAnimator.ofFloat(
- mActionsView.getVisibilityAlpha(), MULTI_PROPERTY_VALUE, alphaValue);
+ mActionsViewAlphaAnimator = ObjectAnimator.ofFloat(mActionsView.getVisibilityAlphaSetter(),
+ OverviewActionsView.FLOAT_SETTER, alphaValue);
mActionsViewAlphaAnimatorFinalValue = alphaValue;
mActionsViewAlphaAnimator.setDuration(duration);
// Set autocancel to prevent race-conditiony setting of alpha from other animations
@@ -2290,7 +2290,7 @@
mClearAllButton.onRecentsViewScroll(scroll, mOverviewGridEnabled);
// Clear all button alpha was set by the previous line.
- mActionsView.getIndexScrollAlpha().setValue(1 - mClearAllButton.getScrollAlpha());
+ mActionsView.getIndexScrollAlphaSetter().accept(1 - mClearAllButton.getScrollAlpha());
}
@Override
@@ -2354,8 +2354,8 @@
// Update the task data for the in/visible children
for (int i = 0; i < getTaskViewCount(); i++) {
TaskView taskView = requireTaskViewAt(i);
- TaskIdAttributeContainer[] containers = taskView.getTaskIdAttributeContainers();
- if (containers.length == 0) {
+ List<TaskContainer> containers = taskView.getTaskContainers();
+ if (containers.isEmpty()) {
continue;
}
int index = indexOfChild(taskView);
@@ -2367,8 +2367,8 @@
}
if (visible) {
// Default update all non-null tasks, then remove running ones
- List<Task> tasksToUpdate = Arrays.stream(containers).filter(Objects::nonNull)
- .map(TaskIdAttributeContainer::getTask)
+ List<Task> tasksToUpdate = containers.stream()
+ .map(TaskContainer::getTask)
.collect(Collectors.toCollection(ArrayList::new));
if (mTmpRunningTasks != null) {
for (Task t : mTmpRunningTasks) {
@@ -2393,7 +2393,7 @@
mHasVisibleTaskData.put(task.key.id, visible);
}
} else {
- for (TaskIdAttributeContainer container : containers) {
+ for (TaskContainer container : containers) {
if (container == null) {
continue;
}
@@ -3816,7 +3816,7 @@
if (success) {
if (shouldRemoveTask) {
- if (dismissedTaskView.getTask() != null) {
+ if (dismissedTaskView.getFirstTask() != null) {
if (dismissedTaskView.isRunningTask()) {
finishRecentsAnimation(true /* toRecents */, false /* shouldPip */,
() -> removeTaskInternal(dismissedTaskViewId));
@@ -4295,7 +4295,7 @@
int alphaInt = Math.round(alpha * 255);
mEmptyMessagePaint.setAlpha(alphaInt);
mEmptyIcon.setAlpha(alphaInt);
- mActionsView.getContentAlpha().setValue(mContentAlpha);
+ mActionsView.getContentAlphaSetter().accept(mContentAlpha);
if (alpha > 0) {
setVisibility(VISIBLE);
@@ -4730,7 +4730,7 @@
*/
public void resetModalVisuals() {
if (mSelectedTask != null) {
- mSelectedTask.getThumbnail().getTaskOverlay().resetModalVisuals();
+ mSelectedTask.getFirstThumbnailView().getTaskOverlay().resetModalVisuals();
}
}
@@ -4749,7 +4749,7 @@
StatsLogManager.EventEnum splitEvent) {
mSplitHiddenTaskView = taskView;
mSplitSelectStateController.setInitialTaskSelect(null /*intent*/,
- stagePosition, taskView.getItemInfo(), splitEvent, taskView.mTask.key.id);
+ stagePosition, taskView.getItemInfo(), splitEvent, taskView.getFirstTask().key.id);
mSplitSelectStateController.setAnimateCurrentTaskDismissal(
true /*animateCurrentTaskDismissal*/);
mSplitHiddenTaskViewIndex = indexOfChild(taskView);
@@ -4800,11 +4800,11 @@
// Animate pair thumbnail into full thumbnail
boolean primaryTaskSelected = mSplitHiddenTaskView.getTaskIds()[0]
== mSplitSelectStateController.getInitialTaskId();
- TaskIdAttributeContainer taskIdAttributeContainer = mSplitHiddenTaskView
- .getTaskIdAttributeContainers()[primaryTaskSelected ? 1 : 0];
- TaskThumbnailViewDeprecated thumbnail = taskIdAttributeContainer.getThumbnailView();
+ TaskContainer taskContainer = mSplitHiddenTaskView
+ .getTaskContainers().get(primaryTaskSelected ? 1 : 0);
+ TaskThumbnailViewDeprecated thumbnail = taskContainer.getThumbnailView();
mSplitSelectStateController.getSplitAnimationController()
- .addInitialSplitFromPair(taskIdAttributeContainer, builder,
+ .addInitialSplitFromPair(taskContainer, builder,
mContainer.getDeviceProfile(),
mSplitHiddenTaskView.getWidth(), mSplitHiddenTaskView.getHeight(),
primaryTaskSelected);
@@ -5202,7 +5202,7 @@
updateGridProperties();
updateScrollSynchronously();
- int targetSysUiFlags = tv.getThumbnail().getSysUiStatusNavFlags();
+ int targetSysUiFlags = tv.getFirstThumbnailView().getSysUiStatusNavFlags();
final boolean[] passedOverviewThreshold = new boolean[] {false};
ValueAnimator progressAnim = ValueAnimator.ofFloat(0, 1);
progressAnim.addUpdateListener(animator -> {
@@ -5266,7 +5266,7 @@
} else {
tv.launchTask(this::onTaskLaunchAnimationEnd);
}
- Task task = tv.getTask();
+ Task task = tv.getFirstTask();
if (task != null) {
mContainer.getStatsLogManager().logger().withItemInfo(tv.getItemInfo())
.log(LAUNCHER_TASK_LAUNCH_SWIPE_DOWN);
@@ -5899,7 +5899,7 @@
}
taskView.setShowScreenshot(true);
- for (TaskIdAttributeContainer container : taskView.getTaskIdAttributeContainers()) {
+ for (TaskContainer container : taskView.getTaskContainers()) {
if (container == null) {
continue;
}
@@ -6269,7 +6269,7 @@
/**
* Moves the provided task into desktop mode, and invoke {@code successCallback} if succeeded.
*/
- public void moveTaskToDesktop(TaskIdAttributeContainer taskContainer,
+ public void moveTaskToDesktop(TaskContainer taskContainer,
Runnable successCallback) {
if (!DesktopModeStatus.canEnterDesktopMode(mContext)) {
return;
@@ -6278,7 +6278,7 @@
() -> moveTaskToDesktopInternal(taskContainer, successCallback)));
}
- private void moveTaskToDesktopInternal(TaskIdAttributeContainer taskContainer,
+ private void moveTaskToDesktopInternal(TaskContainer taskContainer,
Runnable successCallback) {
if (mDesktopRecentsTransitionController == null) {
return;
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 443f83c..d0bf2c2 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -56,7 +56,7 @@
import com.android.quickstep.TaskUtils;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
import com.android.quickstep.util.TaskCornerRadius;
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
+import com.android.quickstep.views.TaskView.TaskContainer;
/**
* Contains options for a recent task when long-pressing its icon.
@@ -76,7 +76,7 @@
private ValueAnimator mRevealAnimator;
@Nullable private Runnable mOnClosingStartCallback;
private TaskView mTaskView;
- private TaskIdAttributeContainer mTaskContainer;
+ private TaskContainer mTaskContainer;
private LinearLayout mOptionLayout;
private float mMenuTranslationYBeforeOpen;
private float mMenuTranslationXBeforeOpen;
@@ -163,7 +163,10 @@
}
}
- public static boolean showForTask(TaskIdAttributeContainer taskContainer,
+ /**
+ * Show a task menu for the given taskContainer.
+ */
+ public static boolean showForTask(TaskContainer taskContainer,
@Nullable Runnable onClosingStartCallback) {
RecentsViewContainer container = RecentsViewContainer.containerFromContext(
taskContainer.getTaskView().getContext());
@@ -173,11 +176,14 @@
return taskMenuView.populateAndShowForTask(taskContainer);
}
- public static boolean showForTask(TaskIdAttributeContainer taskContainer) {
+ /**
+ * Show a task menu for the given taskContainer.
+ */
+ public static boolean showForTask(TaskContainer taskContainer) {
return showForTask(taskContainer, null);
}
- private boolean populateAndShowForTask(TaskIdAttributeContainer taskContainer) {
+ private boolean populateAndShowForTask(TaskContainer taskContainer) {
if (isAttachedToWindow()) {
return false;
}
@@ -198,7 +204,7 @@
return true;
}
- private void addMenuOptions(TaskIdAttributeContainer taskContainer) {
+ private void addMenuOptions(TaskContainer taskContainer) {
if (enableOverviewIconMenu()) {
removeView(mTaskName);
} else {
@@ -226,7 +232,7 @@
mOptionLayout.addView(menuOptionView);
}
- private void orientAroundTaskView(TaskIdAttributeContainer taskContainer) {
+ private void orientAroundTaskView(TaskContainer taskContainer) {
RecentsView recentsView = mContainer.getOverviewPanel();
RecentsPagedOrientationHandler orientationHandler =
recentsView.getPagedOrientationHandler();
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
index a138db0..7adc32e 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -37,14 +37,14 @@
import com.android.launcher3.popup.SystemShortcut
import com.android.launcher3.util.Themes
import com.android.quickstep.TaskOverlayFactory
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
+import com.android.quickstep.views.TaskView.TaskContainer
class TaskMenuViewWithArrow<T> : ArrowPopup<T> where T : RecentsViewContainer, T : Context {
companion object {
const val TAG = "TaskMenuViewWithArrow"
fun <T> showForTask(
- taskContainer: TaskIdAttributeContainer,
+ taskContainer: TaskContainer,
alignedOptionIndex: Int = 0
): Boolean where T : RecentsViewContainer, T : Context {
val container: RecentsViewContainer =
@@ -87,7 +87,7 @@
private lateinit var taskView: TaskView
private lateinit var optionLayout: LinearLayout
- private lateinit var taskContainer: TaskIdAttributeContainer
+ private lateinit var taskContainer: TaskContainer
private var optionMeasuredHeight = 0
private val arrowHorizontalPadding: Int
@@ -141,7 +141,7 @@
}
private fun populateAndShowForTask(
- taskContainer: TaskIdAttributeContainer,
+ taskContainer: TaskContainer,
alignedOptionIndex: Int
): Boolean {
if (isAttachedToWindow) {
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java
index 9802beb..21c6ca8 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java
@@ -53,6 +53,7 @@
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.SystemUiController.SystemUiControllerFlags;
+import com.android.launcher3.util.ViewPool;
import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
import com.android.quickstep.views.TaskView.FullscreenDrawParams;
@@ -66,7 +67,7 @@
* @deprecated This class will be replaced by the new [TaskThumbnailView].
*/
@Deprecated
-public class TaskThumbnailViewDeprecated extends View {
+public class TaskThumbnailViewDeprecated extends View implements ViewPool.Reusable {
private static final MainThreadInitializedObject<FullscreenDrawParams> TEMP_PARAMS =
new MainThreadInitializedObject<>(FullscreenDrawParams::new);
@@ -606,4 +607,9 @@
}
return mThumbnailData.isRealSnapshot && !mTask.isLocked;
}
+
+ @Override
+ public void onRecycle() {
+ // Do nothing
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index f789686..26f313a 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -326,9 +326,6 @@
}
};
- @Nullable
- protected Task mTask;
- @Nullable // can be null when enableRefactorTaskThumbnail() == true
protected TaskThumbnailViewDeprecated mTaskThumbnailViewDeprecated;
protected TaskThumbnailView mTaskThumbnailView;
protected TaskViewIcon mIconView;
@@ -371,9 +368,7 @@
private float mStableAlpha = 1;
private int mTaskViewId = -1;
- protected int[] mTaskIdContainer = new int[0];
- protected TaskIdAttributeContainer[] mTaskIdAttributeContainer =
- new TaskIdAttributeContainer[0];
+ protected List<TaskContainer> mTaskContainers = Collections.emptyList();
private boolean mShowScreenshot;
private boolean mBorderEnabled;
@@ -501,16 +496,19 @@
public void notifyIsRunningTaskUpdated() {
// TODO(b/335649589): TaskView's VM will already have access to TaskThumbnailView's VM
// so there will be no need to access TaskThumbnailView's VM through the TaskThumbnailView
- if (mTask != null) {
+ if (!mTaskContainers.isEmpty()) {
bindTaskThumbnailView();
}
}
/**
- * Builds proto for logging
+ * Builds proto for logging.
+ *
+ * @deprecated Use {@link #getItemInfo(Task)} instead.
*/
+ @Deprecated
public WorkspaceItemInfo getItemInfo() {
- return getItemInfo(mTask);
+ return getItemInfo(getFirstTask());
}
/**
@@ -687,11 +685,9 @@
*/
public void bind(Task task, RecentsOrientedState orientedState) {
cancelPendingLoadTasks();
- mTask = task;
- mTaskIdContainer = new int[]{mTask.key.id};
- mTaskIdAttributeContainer = new TaskIdAttributeContainer[]{
- new TaskIdAttributeContainer(task, mTaskThumbnailViewDeprecated, mIconView,
- STAGE_POSITION_UNDEFINED)};
+ mTaskContainers = Collections.singletonList(
+ new TaskContainer(task, mTaskThumbnailViewDeprecated, mIconView,
+ STAGE_POSITION_UNDEFINED, mDigitalWellBeingToast));
if (enableRefactorTaskThumbnail()) {
bindTaskThumbnailView();
} else {
@@ -703,17 +699,17 @@
private void bindTaskThumbnailView() {
// TODO(b/335649589): TaskView's VM will already have access to TaskThumbnailView's VM
// so there will be no need to access TaskThumbnailView's VM through the TaskThumbnailView
- mTaskThumbnailView.getViewModel().bind(new TaskThumbnail(mTask, isRunningTask()));
+ mTaskThumbnailView.getViewModel().bind(new TaskThumbnail(getFirstTask(), isRunningTask()));
}
/**
* Sets up an on-click listener and the visibility for show_windows icon on top of the task.
*/
public void setUpShowAllInstancesListener() {
- if (mTaskIdAttributeContainer.length == 0) {
+ if (mTaskContainers.isEmpty()) {
return;
}
- String taskPackageName = mTaskIdAttributeContainer[0].mTask.key.getPackageName();
+ String taskPackageName = mTaskContainers.get(0).getTask().key.getPackageName();
// icon of the top/left task
View showWindowsView = findViewById(R.id.show_windows);
@@ -755,50 +751,62 @@
filterView.setOnClickListener(callback);
}
- public TaskIdAttributeContainer[] getTaskIdAttributeContainers() {
- return mTaskIdAttributeContainer;
+ /**
+ * Returns a list of all TaskContainers in the TaskView.
+ */
+ public List<TaskContainer> getTaskContainers() {
+ return mTaskContainers;
}
+ /**
+ * Returns the first task bound to this TaskView.
+ *
+ * @deprecated Use {@link #mTaskContainers} instead.
+ */
+ @Deprecated
@Nullable
- public Task getTask() {
- return mTask;
+ public Task getFirstTask() {
+ return !mTaskContainers.isEmpty() ? mTaskContainers.get(0).getTask() : null;
}
/**
* Check if given {@code taskId} is tracked in this view
*/
public boolean containsTaskId(int taskId) {
- return Arrays.stream(mTaskIdContainer).anyMatch(myTaskId -> myTaskId == taskId);
+ return getTaskContainerById(taskId) != null;
}
/**
* Returns a copy of integer array containing taskIds of all tasks in the TaskView.
*/
public int[] getTaskIds() {
- return Arrays.copyOf(mTaskIdContainer, mTaskIdContainer.length);
+ return mTaskContainers.stream().mapToInt(
+ container -> container.getTask().key.id).toArray();
}
public boolean containsMultipleTasks() {
- return mTaskIdContainer.length > 1;
+ return mTaskContainers.size() > 1;
}
/**
- * Returns the TaskIdAttributeContainer corresponding to a given taskId, or null if the TaskView
- * does not contain a Task with that ID.
+ * Returns the TaskContainer corresponding to a given taskId, or null if the TaskView does
+ * not contain a Task with that ID.
*/
@Nullable
- public TaskIdAttributeContainer getTaskAttributesById(int taskId) {
- for (TaskIdAttributeContainer attributes : mTaskIdAttributeContainer) {
- if (attributes.getTask().key.id == taskId) {
- return attributes;
- }
- }
-
- return null;
+ public TaskContainer getTaskContainerById(int taskId) {
+ return mTaskContainers.stream().filter(
+ container -> container.getTask().key.id == taskId).findFirst().orElse(null);
}
- public TaskThumbnailViewDeprecated getThumbnail() {
- return mTaskThumbnailViewDeprecated;
+ /**
+ * Returns the first thumbnailView of the TaskView.
+ *
+ * @deprecated Use {@link #mTaskContainers} instead.
+ */
+ @Deprecated
+ public TaskThumbnailViewDeprecated getFirstThumbnailView() {
+ return !mTaskContainers.isEmpty() ? mTaskContainers.get(0).getThumbnailView()
+ : mTaskThumbnailViewDeprecated;
}
void refreshThumbnails(@Nullable HashMap<Integer, ThumbnailData> thumbnailDatas) {
@@ -806,10 +814,10 @@
// TODO(b/334825222) add thumbnail logic
return;
}
- if (mTask != null && thumbnailDatas != null) {
- final ThumbnailData thumbnailData = thumbnailDatas.get(mTask.key.id);
+ if (getFirstTask() != null && thumbnailDatas != null) {
+ final ThumbnailData thumbnailData = thumbnailDatas.get(getFirstTask().key.id);
if (thumbnailData != null) {
- mTaskThumbnailViewDeprecated.setThumbnail(mTask, thumbnailData);
+ mTaskThumbnailViewDeprecated.setThumbnail(getFirstTask(), thumbnailData);
return;
}
}
@@ -817,19 +825,27 @@
mTaskThumbnailViewDeprecated.refresh();
}
- /** TODO(b/197033698) Remove all usages of above method and migrate to this one */
- public TaskThumbnailViewDeprecated[] getThumbnails() {
- return new TaskThumbnailViewDeprecated[]{mTaskThumbnailViewDeprecated};
+ public TaskThumbnailViewDeprecated[] getThumbnailViews() {
+ return mTaskContainers.stream().map(
+ TaskContainer::getThumbnailView).toArray(
+ TaskThumbnailViewDeprecated[]::new);
}
- public TaskViewIcon getIconView() {
- return mIconView;
+ /**
+ * Returns the first iconView of the TaskView.
+ *
+ * @deprecated Use {@link #mTaskContainers} instead.
+ */
+ @Deprecated
+ @Nullable
+ public TaskViewIcon getFirstIconView() {
+ return !mTaskContainers.isEmpty() ? mTaskContainers.get(0).getIconView() : null;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
RecentsView recentsView = getRecentsView();
- if (recentsView == null || getTask() == null) {
+ if (recentsView == null || getFirstTask() == null) {
return false;
}
SplitSelectStateController splitSelectStateController =
@@ -837,7 +853,7 @@
// Disable taps for split selection animation unless we have multiple tasks
boolean disableTapsForSplitSelect =
splitSelectStateController.isSplitSelectActive()
- && splitSelectStateController.getInitialTaskId() == getTask().key.id
+ && splitSelectStateController.getInitialTaskId() == getFirstTask().key.id
&& !containsMultipleTasks();
if (disableTapsForSplitSelect) {
return false;
@@ -850,19 +866,21 @@
}
private void onClick(View view) {
- if (getTask() == null) {
+ if (getFirstTask() == null) {
Log.d("b/310064698", "onClick - task is null");
return;
}
if (confirmSecondSplitSelectApp()) {
- Log.d("b/310064698", mTask + " - onClick - split select is active");
+ Log.d("b/310064698",
+ Arrays.toString(getTaskIds()) + " - onClick - split select is active");
return;
}
RunnableList callbackList = launchTasks();
- Log.d("b/310064698", mTask + " - onClick - callbackList: " + callbackList);
+ Log.d("b/310064698",
+ Arrays.toString(getTaskIds()) + " - onClick - callbackList: " + callbackList);
if (callbackList != null) {
- callbackList.add(() -> Log.d("b/310064698", Arrays.toString(
- getTaskIds()) + " - onClick - launchCompleted"));
+ callbackList.add(() -> Log.d("b/310064698",
+ Arrays.toString(getTaskIds()) + " - onClick - launchCompleted"));
}
mContainer.getStatsLogManager().logger().withItemInfo(getItemInfo())
.log(LAUNCHER_TASK_LAUNCH_TAP);
@@ -874,10 +892,10 @@
*/
protected boolean confirmSecondSplitSelectApp() {
int index = getLastSelectedChildTaskIndex();
- if (index >= mTaskIdAttributeContainer.length) {
+ if (index >= mTaskContainers.size()) {
return false;
}
- TaskIdAttributeContainer container = mTaskIdAttributeContainer[index];
+ TaskContainer container = mTaskContainers.get(index);
if (container != null) {
return getRecentsView().confirmSplitSelect(this, container.getTask(),
container.getIconView().getDrawable(), container.getThumbnailView(),
@@ -903,14 +921,15 @@
*/
@Nullable
public RunnableList launchTaskAnimated() {
- if (mTask != null) {
+ if (getFirstTask() != null) {
TestLogging.recordEvent(
- TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
+ TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", Arrays.toString(
+ getTaskIds()));
ActivityOptionsWrapper opts = mContainer.getActivityLaunchOptions(this, null);
opts.options.setLaunchDisplayId(
getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
if (ActivityManagerWrapper.getInstance()
- .startActivityFromRecents(mTask.key, opts.options)) {
+ .startActivityFromRecents(getFirstTask().key, opts.options)) {
Log.d(TAG, "launchTaskAnimated - startActivityFromRecents: " + Arrays.toString(
getTaskIds()));
ActiveGestureLog.INSTANCE.trackEvent(EXPECTING_TASK_APPEARED);
@@ -938,7 +957,7 @@
return null;
}
} else {
- Log.d(TAG, "launchTaskAnimated - mTask is null" + Arrays.toString(getTaskIds()));
+ Log.d(TAG, "launchTaskAnimated - getTask() is null" + Arrays.toString(getTaskIds()));
return null;
}
}
@@ -954,9 +973,10 @@
* Starts the task associated with this view without any animation
*/
public void launchTask(@NonNull Consumer<Boolean> callback, boolean isQuickswitch) {
- if (mTask != null) {
+ if (getFirstTask() != null) {
TestLogging.recordEvent(
- TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
+ TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", Arrays.toString(
+ getTaskIds()));
TaskRemovedDuringLaunchListener failureListener = new TaskRemovedDuringLaunchListener(
getContext().getApplicationContext());
@@ -964,7 +984,7 @@
// We only listen for failures to launch in quickswitch because the during this
// gesture launcher is in the background state, vs other launches which are in
// the actual overview state
- failureListener.register(mContainer, mTask.key.id, () -> {
+ failureListener.register(mContainer, getFirstTask().key.id, () -> {
notifyTaskLaunchFailed(TAG);
RecentsView rv = getRecentsView();
if (rv != null) {
@@ -997,7 +1017,7 @@
if (!enableRefactorTaskThumbnail()) {
opts.setDisableStartingWindow(mTaskThumbnailViewDeprecated.shouldShowSplashView());
}
- Task.TaskKey key = mTask.key;
+ Task.TaskKey key = getFirstTask().key;
UI_HELPER_EXECUTOR.execute(() -> {
if (!ActivityManagerWrapper.getInstance().startActivityFromRecents(key, opts)) {
// If the call to start activity failed, then post the result immediately,
@@ -1013,7 +1033,7 @@
});
} else {
callback.accept(false);
- Log.d(TAG, "launchTask - mTask is null" + Arrays.toString(getTaskIds()));
+ Log.d(TAG, "launchTask - getTask() is null" + Arrays.toString(getTaskIds()));
}
}
@@ -1069,7 +1089,8 @@
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
- if (mTask != null && mTask.key.displayId != getRootViewDisplayId()) {
+ if (getFirstTask() != null
+ && getFirstTask().key.displayId != getRootViewDisplayId()) {
launchTaskAnimated();
}
mIsClickableAsLiveTile = true;
@@ -1110,7 +1131,7 @@
* @param visible If this task view will be visible to the user in overview or hidden
*/
public void onTaskListVisibilityChanged(boolean visible, @TaskDataChanges int changes) {
- if (mTask == null) {
+ if (getFirstTask() == null) {
return;
}
cancelPendingLoadTasks();
@@ -1123,15 +1144,16 @@
if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
mThumbnailLoadRequest = thumbnailCache.updateThumbnailInBackground(
- mTask, thumbnail -> {
+ getFirstTask(), thumbnail -> {
if (!enableRefactorTaskThumbnail()) {
// TODO(b/334825222) add thumbnail state
- mTaskThumbnailViewDeprecated.setThumbnail(mTask, thumbnail);
+ mTaskThumbnailViewDeprecated.setThumbnail(getFirstTask(),
+ thumbnail);
}
});
}
if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
- mIconLoadRequest = iconCache.updateIconInBackground(mTask,
+ mIconLoadRequest = iconCache.updateIconInBackground(getFirstTask(),
(task) -> {
setIcon(mIconView, task.icon);
if (enableOverviewIconMenu()) {
@@ -1151,7 +1173,7 @@
}
// Reset the task thumbnail reference as well (it will be fetched from the cache or
// reloaded next time we need it)
- mTask.thumbnail = null;
+ getFirstTask().thumbnail = null;
}
if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
setIcon(mIconView, null);
@@ -1195,9 +1217,8 @@
}
protected boolean showTaskMenuWithContainer(TaskViewIcon iconView) {
- Optional<TaskIdAttributeContainer> menuContainer = Arrays.stream(
- mTaskIdAttributeContainer).filter(
- container -> container.getIconView() == iconView).findAny();
+ Optional<TaskContainer> menuContainer = mTaskContainers.stream().filter(
+ container -> container.getIconView() == iconView).findAny();
if (menuContainer.isEmpty()) {
return false;
}
@@ -1270,7 +1291,7 @@
if (!enableRefactorTaskThumbnail()) {
mTaskThumbnailViewDeprecated.getTaskOverlay().updateOrientationState(orientationState);
}
- mDigitalWellBeingToast.initialize(mTask);
+ mDigitalWellBeingToast.initialize(getFirstTask());
}
/**
@@ -1281,11 +1302,6 @@
return deviceProfile.isTablet && !isFocusedTask();
}
- /** Whether this task view represents the desktop */
- public boolean isDesktopTask() {
- return false;
- }
-
/**
* Called to animate a smooth transition when going directly from an app into Overview (and
* vice versa). Icons fade in, and DWB banners slide in with a "shift up" animation.
@@ -1378,7 +1394,7 @@
if (enableRefactorTaskThumbnail()) {
notifyIsRunningTaskUpdated();
} else {
- mTaskThumbnailViewDeprecated.setThumbnail(mTask, null);
+ mTaskThumbnailViewDeprecated.setThumbnail(getFirstTask(), null);
}
setOverlayEnabled(false);
onTaskListVisibilityChanged(false);
@@ -1675,7 +1691,7 @@
getContext().getText(R.string.accessibility_close)));
final Context context = getContext();
- for (TaskIdAttributeContainer taskContainer : mTaskIdAttributeContainer) {
+ for (TaskContainer taskContainer : mTaskContainers) {
for (SystemShortcut s : TraceHelper.allowIpcs(
"TV.a11yInfo", () -> getEnabledShortcuts(this, taskContainer))) {
info.addAction(s.createAccessibilityAction(context));
@@ -1710,7 +1726,7 @@
return true;
}
- for (TaskIdAttributeContainer taskContainer : mTaskIdAttributeContainer) {
+ for (TaskContainer taskContainer : mTaskContainers) {
for (SystemShortcut s : getEnabledShortcuts(this,
taskContainer)) {
if (s.hasHandlerForAction(action)) {
@@ -1724,8 +1740,8 @@
}
@Nullable
- public RecentsView getRecentsView() {
- return (RecentsView) getParent();
+ public RecentsView<?, ?> getRecentsView() {
+ return (RecentsView<?, ?>) getParent();
}
RecentsPagedOrientationHandler getPagedOrientationHandler() {
@@ -1734,8 +1750,9 @@
private void notifyTaskLaunchFailed(String tag) {
String msg = "Failed to launch task";
- if (mTask != null) {
- msg += " (task=" + mTask.key.baseIntent + " userId=" + mTask.key.userId + ")";
+ if (getFirstTask() != null) {
+ msg += " (task=" + getFirstTask().key.baseIntent + " userId="
+ + getFirstTask().key.userId + ")";
}
Log.w(tag, msg);
Toast.makeText(getContext(), R.string.activity_not_available, LENGTH_SHORT).show();
@@ -1976,7 +1993,10 @@
}
}
- public class TaskIdAttributeContainer {
+ /**
+ * Holder for all Task dependent information.
+ */
+ public class TaskContainer {
private final TaskThumbnailViewDeprecated mThumbnailView;
private final Task mTask;
private final TaskViewIcon mIconView;
@@ -1984,15 +2004,18 @@
private @SplitConfigurationOptions.StagePosition int mStagePosition;
@IdRes
private final int mA11yNodeId;
+ private final DigitalWellBeingToast mDigitalWellBeingToast;
- public TaskIdAttributeContainer(Task task, TaskThumbnailViewDeprecated thumbnailView,
- TaskViewIcon iconView, int stagePosition) {
+ public TaskContainer(Task task, TaskThumbnailViewDeprecated thumbnailView,
+ TaskViewIcon iconView, int stagePosition,
+ DigitalWellBeingToast digitalWellBeingToast) {
this.mTask = task;
this.mThumbnailView = thumbnailView;
this.mIconView = iconView;
this.mStagePosition = stagePosition;
this.mA11yNodeId = (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) ?
R.id.split_bottomRight_appInfo : R.id.split_topLeft_appInfo;
+ this.mDigitalWellBeingToast = digitalWellBeingToast;
}
public TaskThumbnailViewDeprecated getThumbnailView() {
@@ -2026,5 +2049,9 @@
public int getA11yNodeId() {
return mA11yNodeId;
}
+
+ public DigitalWellBeingToast getDigitalWellBeingToast() {
+ return mDigitalWellBeingToast;
+ }
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
index 7065075..2bcfa3f 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
@@ -264,6 +264,120 @@
assertThat(animatorScheduler.delayedBlock).isNull()
}
+ @Test
+ fun animateToInitialState_inApp() {
+ setUpBubbleBar()
+ setUpBubbleStashController()
+ whenever(bubbleStashController.bubbleBarTranslationY)
+ .thenReturn(BAR_TRANSLATION_Y_FOR_TASKBAR)
+
+ val handle = View(context)
+ val handleAnimator = PhysicsAnimator.getInstance(handle)
+ whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+
+ val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+
+ val animator =
+ BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.animateToInitialState(bubble, isInApp = true, isExpanding = false)
+ }
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+ assertThat(barAnimator.isRunning()).isFalse()
+ assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+ assertThat(bubbleBarView.alpha).isEqualTo(1)
+ assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
+
+ assertThat(animatorScheduler.delayedBlock).isNotNull()
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+ assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(bubbleBarView.alpha).isEqualTo(0)
+ assertThat(handle.translationY).isEqualTo(0)
+ assertThat(handle.alpha).isEqualTo(1)
+
+ verify(bubbleStashController).stashBubbleBarImmediate()
+ }
+
+ @Test
+ fun animateToInitialState_inApp_autoExpanding() {
+ setUpBubbleBar()
+ setUpBubbleStashController()
+ whenever(bubbleStashController.bubbleBarTranslationY)
+ .thenReturn(BAR_TRANSLATION_Y_FOR_TASKBAR)
+
+ val handle = View(context)
+ val handleAnimator = PhysicsAnimator.getInstance(handle)
+ whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+
+ val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+
+ val animator =
+ BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.animateToInitialState(bubble, isInApp = true, isExpanding = true)
+ }
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+ assertThat(barAnimator.isRunning()).isFalse()
+ assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+ assertThat(bubbleBarView.alpha).isEqualTo(1)
+ assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
+
+ assertThat(animatorScheduler.delayedBlock).isNotNull()
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
+
+ assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(bubbleBarView.alpha).isEqualTo(1)
+ assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
+
+ verify(bubbleStashController).showBubbleBarImmediate()
+ }
+
+ @Test
+ fun animateToInitialState_inHome() {
+ setUpBubbleBar()
+ setUpBubbleStashController()
+ whenever(bubbleStashController.bubbleBarTranslationY)
+ .thenReturn(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+
+ val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
+
+ val animator =
+ BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animator.animateToInitialState(bubble, isInApp = false, isExpanding = false)
+ }
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {}
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+ assertThat(barAnimator.isRunning()).isFalse()
+ assertThat(bubbleBarView.isAnimatingNewBubble).isTrue()
+ assertThat(bubbleBarView.alpha).isEqualTo(1)
+ assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+
+ assertThat(animatorScheduler.delayedBlock).isNotNull()
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
+
+ assertThat(bubbleBarView.isAnimatingNewBubble).isFalse()
+ assertThat(bubbleBarView.alpha).isEqualTo(1)
+ assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
+
+ verify(bubbleStashController).showBubbleBarImmediate()
+ }
+
private fun setUpBubbleBar() {
bubbleBarView = BubbleBarView(context)
InstrumentationRegistry.getInstrumentation().runOnMainSync {
@@ -322,3 +436,4 @@
private const val DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS = -20f
private const val HANDLE_TRANSLATION = -30f
private const val BAR_TRANSLATION_Y_FOR_TASKBAR = -50f
+private const val BAR_TRANSLATION_Y_FOR_HOTSEAT = -40f
diff --git a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
index 0f9d96c..d59aafb 100644
--- a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
@@ -16,12 +16,12 @@
package com.android.quickstep
-import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
-import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
-import com.android.dx.mockito.inline.extended.StaticMockitoSession
import android.content.ComponentName
import android.content.Intent
import android.platform.test.flag.junit.SetFlagsRule
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.android.launcher3.AbstractFloatingView
import com.android.launcher3.AbstractFloatingViewHelper
import com.android.launcher3.logging.StatsLogManager
@@ -39,12 +39,12 @@
import org.junit.Before
import org.junit.Rule
import org.junit.Test
-import org.mockito.quality.Strictness
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
+import org.mockito.quality.Strictness
/** Test for DesktopSystemShortcut */
class DesktopSystemShortcutTest {
@@ -64,15 +64,18 @@
private lateinit var mockitoSession: StaticMockitoSession
@Before
- fun setUp(){
- mockitoSession = mockitoSession().strictness(Strictness.LENIENT)
- .spyStatic(DesktopModeStatus::class.java).startMocking()
+ fun setUp() {
+ mockitoSession =
+ mockitoSession()
+ .strictness(Strictness.LENIENT)
+ .spyStatic(DesktopModeStatus::class.java)
+ .startMocking()
doReturn(true).`when` { DesktopModeStatus.enforceDeviceRestrictions() }
doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
}
@After
- fun tearDown(){
+ fun tearDown() {
mockitoSession.finishMocking()
}
@@ -85,11 +88,12 @@
isDockable = true
}
val taskContainer =
- taskView.TaskIdAttributeContainer(
+ taskView.TaskContainer(
task,
null,
null,
- SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+ SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
+ null
)
val shortcuts = factory.getShortcuts(launcher, taskContainer)
@@ -106,11 +110,12 @@
isDockable = true
}
val taskContainer =
- taskView.TaskIdAttributeContainer(
+ taskView.TaskContainer(
task,
null,
null,
- SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+ SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
+ null
)
val shortcuts = factory.getShortcuts(launcher, taskContainer)
@@ -128,11 +133,12 @@
isDockable = true
}
val taskContainer =
- taskView.TaskIdAttributeContainer(
+ taskView.TaskContainer(
task,
null,
null,
- SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+ SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
+ null
)
val shortcuts = factory.getShortcuts(launcher, taskContainer)
@@ -148,11 +154,12 @@
isDockable = false
}
val taskContainer =
- taskView.TaskIdAttributeContainer(
+ taskView.TaskContainer(
task,
null,
null,
- SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+ SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
+ null
)
val shortcuts = factory.getShortcuts(launcher, taskContainer)
@@ -168,11 +175,12 @@
isDockable = true
}
val taskContainer =
- taskView.TaskIdAttributeContainer(
+ taskView.TaskContainer(
task,
null,
null,
- SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+ SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
+ null
)
whenever(launcher.getOverviewPanel<LauncherRecentsView>()).thenReturn(recentsView)
diff --git a/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
index 4aa7cb0..37ab131 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
@@ -86,8 +86,8 @@
final TaskView task = getOnceNotNull("No latest task", launcher -> getLatestTask(launcher));
return getFromLauncher(launcher -> {
- assertTrue("Latest task is not Calculator",
- CALCULATOR_PACKAGE.equals(task.getTask().getTopComponent().getPackageName()));
+ assertTrue("Latest task is not Calculator", CALCULATOR_PACKAGE.equals(
+ task.getFirstTask().getTopComponent().getPackageName()));
return task.getDigitalWellBeingToast();
});
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
index efe773b..50f74c2 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
@@ -27,6 +27,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
+import com.android.launcher3.allapps.PrivateProfileManager;
import com.android.launcher3.tapl.HomeAllApps;
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.tapl.PrivateSpaceContainer;
@@ -34,6 +35,7 @@
import com.android.launcher3.util.rule.ScreenRecordRule;
import org.junit.After;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -164,6 +166,60 @@
}
}
+ @Test
+ @ScreenRecordRule.ScreenRecord // b/334946529
+ @Ignore("b/339179262")
+ public void testPrivateSpaceLockingBehaviour() throws IOException {
+ // Scroll to the bottom of All Apps
+ executeOnLauncher(launcher -> launcher.getAppsView().resetAndScrollToPrivateSpaceHeader());
+ HomeAllApps homeAllApps = mLauncher.getAllApps();
+
+ // Disable Private Space
+ togglePrivateSpace(PrivateProfileManager.STATE_DISABLED, homeAllApps);
+
+ homeAllApps.freeze();
+ try {
+ // Verify Locked View elements are present.
+ homeAllApps.getPrivateSpaceLockedView();
+ } finally {
+ // UnFreeze
+ homeAllApps.unfreeze();
+ }
+
+ // Enable Private Space
+ togglePrivateSpace(PrivateProfileManager.STATE_ENABLED, homeAllApps);
+
+ homeAllApps.freeze();
+ try {
+ // Verify UnLocked View elements are present.
+ homeAllApps.getPrivateSpaceUnlockedView();
+ } finally {
+ // UnFreeze
+ homeAllApps.unfreeze();
+ }
+ }
+
+ private void togglePrivateSpace(int state, HomeAllApps homeAllApps) {
+ homeAllApps.freeze();
+ try {
+ // Try Toggling Private Space
+ homeAllApps.togglePrivateSpace();
+ } finally {
+ // UnFreeze
+ homeAllApps.unfreeze();
+ }
+ PrivateProfileManager manager = getFromLauncher(l -> l.getAppsView()
+ .getPrivateProfileManager());
+ waitForLauncherCondition("Private profile toggle to state: " + state + " failed",
+ launcher -> {
+ manager.reset();
+ return manager.getCurrentState() == state;
+ },
+ LauncherInstrumentation.WAIT_TIME_MS);
+ // Wait for Launcher UI to be updated with Private Space Items.
+ waitForLauncherUIUpdate();
+ }
+
private void waitForPrivateSpaceSetup() {
waitForLauncherCondition("Private Profile not setup",
launcher -> launcher.getAppsView().hasPrivateProfile(),
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index 2a54057..bfd7bdb 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -130,7 +130,7 @@
.tapMenu()
.hasMenuItem("Save app pair"));
} else {
- overview.getOverviewActions().assertHasAction("Save app pair");
+ overview.getOverviewGroupActions().assertHasAction("Save app pair");
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt b/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
index de98703..f29df61 100644
--- a/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
@@ -35,7 +35,7 @@
import com.android.quickstep.views.IconView
import com.android.quickstep.views.TaskThumbnailViewDeprecated
import com.android.quickstep.views.TaskView
-import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
+import com.android.quickstep.views.TaskView.TaskContainer
import com.android.systemui.shared.recents.model.Task
import org.junit.Assert.assertEquals
import org.junit.Before
@@ -67,7 +67,7 @@
private val mockGroupedTaskView: GroupedTaskView = mock()
private val mockTask: Task = mock()
private val mockTaskKey: Task.TaskKey = mock()
- private val mockTaskIdAttributeContainer: TaskIdAttributeContainer = mock()
+ private val mockTaskContainer: TaskContainer = mock()
// AppPairIcon
private val mockAppPairIcon: AppPairIcon = mock()
private val mockContextThemeWrapper: ContextThemeWrapper = mock()
@@ -83,14 +83,15 @@
private val transitionInfo: TransitionInfo = mock()
private val transaction: Transaction = mock()
- lateinit var splitAnimationController: SplitAnimationController
+ private lateinit var splitAnimationController: SplitAnimationController
@Before
fun setup() {
- whenever(mockTaskView.thumbnail).thenReturn(mockThumbnailView)
+ whenever(mockTaskContainer.thumbnailView).thenReturn(mockThumbnailView)
whenever(mockThumbnailView.thumbnail).thenReturn(mockBitmap)
- whenever(mockTaskView.iconView).thenReturn(mockIconView)
+ whenever(mockTaskContainer.iconView).thenReturn(mockIconView)
whenever(mockIconView.drawable).thenReturn(mockTaskViewDrawable)
+ whenever(mockTaskView.taskContainers).thenReturn(List(1) { mockTaskContainer })
whenever(splitSelectSource.drawable).thenReturn(mockSplitSourceDrawable)
whenever(splitSelectSource.view).thenReturn(mockSplitSourceView)
@@ -177,14 +178,13 @@
// Remove icon view from GroupedTaskView
whenever(mockIconView.drawable).thenReturn(null)
- whenever(mockTaskIdAttributeContainer.task).thenReturn(mockTask)
- whenever(mockTaskIdAttributeContainer.iconView).thenReturn(mockIconView)
- whenever(mockTaskIdAttributeContainer.thumbnailView).thenReturn(mockThumbnailView)
+ whenever(mockTaskContainer.task).thenReturn(mockTask)
+ whenever(mockTaskContainer.iconView).thenReturn(mockIconView)
+ whenever(mockTaskContainer.thumbnailView).thenReturn(mockThumbnailView)
whenever(mockTask.getKey()).thenReturn(mockTaskKey)
whenever(mockTaskKey.getId()).thenReturn(taskId)
whenever(mockSplitSelectStateController.initialTaskId).thenReturn(taskId)
- whenever(mockGroupedTaskView.taskIdAttributeContainers)
- .thenReturn(Array(1) { mockTaskIdAttributeContainer })
+ whenever(mockGroupedTaskView.taskContainers).thenReturn(List(1) { mockTaskContainer })
val splitAnimInitProps: SplitAnimationController.Companion.SplitAnimInitProps =
splitAnimationController.getFirstAnimInitViews(
{ mockGroupedTaskView },
@@ -277,9 +277,7 @@
doNothing()
.whenever(spySplitAnimationController)
.composeIconSplitLaunchAnimator(any(), any(), any(), any())
- doReturn(-1)
- .whenever(spySplitAnimationController)
- .hasChangesForBothAppPairs(any(), any())
+ doReturn(-1).whenever(spySplitAnimationController).hasChangesForBothAppPairs(any(), any())
spySplitAnimationController.playSplitLaunchAnimation(
null /* launchingTaskView */,
@@ -305,41 +303,10 @@
val spySplitAnimationController = spy(splitAnimationController)
whenever(mockAppPairIcon.context).thenReturn(mockContextThemeWrapper)
doNothing()
- .whenever(spySplitAnimationController)
- .composeFullscreenIconSplitLaunchAnimator(any(), any(), any(), any(), any())
- doReturn(0)
- .whenever(spySplitAnimationController)
- .hasChangesForBothAppPairs(any(), any())
-
- spySplitAnimationController.playSplitLaunchAnimation(
- null /* launchingTaskView */,
- mockAppPairIcon,
- taskId,
- taskId2,
- null /* apps */,
- null /* wallpapers */,
- null /* nonApps */,
- stateManager,
- depthController,
- transitionInfo,
- transaction,
- {} /* finishCallback */
- )
-
- verify(spySplitAnimationController)
- .composeFullscreenIconSplitLaunchAnimator(any(), any(), any(), any(), eq(0))
- }
-
- @Test
- fun playsAppropriateSplitLaunchAnimation_playsIconLaunchFromTaskbarCMultiWindow() {
- val spySplitAnimationController = spy(splitAnimationController)
- whenever(mockAppPairIcon.context).thenReturn(mockTaskbarActivityContext)
- doNothing()
.whenever(spySplitAnimationController)
- .composeScaleUpLaunchAnimation(any(), any(), any(), any())
- doReturn(-1)
- .whenever(spySplitAnimationController)
- .hasChangesForBothAppPairs(any(), any())
+ .composeFullscreenIconSplitLaunchAnimator(any(), any(), any(), any(), any())
+ doReturn(0).whenever(spySplitAnimationController).hasChangesForBothAppPairs(any(), any())
+
spySplitAnimationController.playSplitLaunchAnimation(
null /* launchingTaskView */,
mockAppPairIcon,
@@ -355,8 +322,35 @@
{} /* finishCallback */
)
- verify(spySplitAnimationController).composeScaleUpLaunchAnimation(any(), any(), any(),
- eq(WINDOWING_MODE_MULTI_WINDOW))
+ verify(spySplitAnimationController)
+ .composeFullscreenIconSplitLaunchAnimator(any(), any(), any(), any(), eq(0))
+ }
+
+ @Test
+ fun playsAppropriateSplitLaunchAnimation_playsIconLaunchFromTaskbarCMultiWindow() {
+ val spySplitAnimationController = spy(splitAnimationController)
+ whenever(mockAppPairIcon.context).thenReturn(mockTaskbarActivityContext)
+ doNothing()
+ .whenever(spySplitAnimationController)
+ .composeScaleUpLaunchAnimation(any(), any(), any(), any())
+ doReturn(-1).whenever(spySplitAnimationController).hasChangesForBothAppPairs(any(), any())
+ spySplitAnimationController.playSplitLaunchAnimation(
+ null /* launchingTaskView */,
+ mockAppPairIcon,
+ taskId,
+ taskId2,
+ null /* apps */,
+ null /* wallpapers */,
+ null /* nonApps */,
+ stateManager,
+ depthController,
+ transitionInfo,
+ transaction,
+ {} /* finishCallback */
+ )
+
+ verify(spySplitAnimationController)
+ .composeScaleUpLaunchAnimation(any(), any(), any(), eq(WINDOWING_MODE_MULTI_WINDOW))
}
@Test
@@ -364,28 +358,26 @@
val spySplitAnimationController = spy(splitAnimationController)
whenever(mockAppPairIcon.context).thenReturn(mockTaskbarActivityContext)
doNothing()
- .whenever(spySplitAnimationController)
- .composeScaleUpLaunchAnimation(any(), any(), any(), any())
- doReturn(0)
- .whenever(spySplitAnimationController)
- .hasChangesForBothAppPairs(any(), any())
+ .whenever(spySplitAnimationController)
+ .composeScaleUpLaunchAnimation(any(), any(), any(), any())
+ doReturn(0).whenever(spySplitAnimationController).hasChangesForBothAppPairs(any(), any())
spySplitAnimationController.playSplitLaunchAnimation(
- null /* launchingTaskView */,
- mockAppPairIcon,
- taskId,
- taskId2,
- null /* apps */,
- null /* wallpapers */,
- null /* nonApps */,
- stateManager,
- depthController,
- transitionInfo,
- transaction,
- {} /* finishCallback */
+ null /* launchingTaskView */,
+ mockAppPairIcon,
+ taskId,
+ taskId2,
+ null /* apps */,
+ null /* wallpapers */,
+ null /* nonApps */,
+ stateManager,
+ depthController,
+ transitionInfo,
+ transaction,
+ {} /* finishCallback */
)
- verify(spySplitAnimationController).composeScaleUpLaunchAnimation(any(), any(), any(),
- eq(WINDOWING_MODE_FULLSCREEN))
+ verify(spySplitAnimationController)
+ .composeScaleUpLaunchAnimation(any(), any(), any(), eq(WINDOWING_MODE_FULLSCREEN))
}
@Test
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 28fb119..8b69318 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na početni ekran"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Dodali ste vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> na početni ekran"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Predlozi"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Neophodne aplikacije"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Osnovno"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Novosti i časopisi"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zona za opuštanje"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Zabava"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index b05002d..736eaab 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Přidat na plochu"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> byl přidán na plochu"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Návrhy"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Základní"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Nejdůležitější aplikace"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Zprávy a časopisy"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Vaše klidová zóna"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Zábava"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 4aaa44b..623b183 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -48,7 +48,7 @@
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Noticias y revistas"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zona de descanso"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entretenimiento"</string>
- <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
+ <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Redes sociales"</string>
<string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Salud y bienestar"</string>
<string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Clima"</string>
<string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sugerencias para ti"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index c91e510..4df953a 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -48,7 +48,7 @@
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Noticias y revistas"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Tu zona de descanso"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entretenimiento"</string>
- <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
+ <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Redes sociales"</string>
<string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Salud y actividad física"</string>
<string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"El tiempo"</string>
<string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sugerencias para ti"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 4f6f121..4c72f00 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Ajouter à l\'écran d\'accueil"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ajouté à l\'écran d\'accueil"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Les bases"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Indispensables"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Actualités et magazines"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Votre espace détente"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Divertissement"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index b6af6b3..da6a711 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj do ekranu głównego"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widżet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> został dodany do ekranu głównego"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugestie"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Niezbędne"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Najbardziej przydatne"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Wiadomości i czasopisma"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Strefa relaksu"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Rozrywka"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index bb82b67..9eaae37 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Додај на почетни екран"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Додали сте виџет <xliff:g id="WIDGET_NAME">%1$s</xliff:g> на почетни екран"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Предлози"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Неопходне апликације"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Основно"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Новости и часописи"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Зона за опуштање"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Забава"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 2975e97..a18aab6 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"添加到主屏幕"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"已将“<xliff:g id="WIDGET_NAME">%1$s</xliff:g>”微件添加到主屏幕"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"建议"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"必备"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"必备之选"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"新闻与杂志"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"您的休闲区"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"娱乐"</string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c971223..c3d4273 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -485,7 +485,7 @@
<!-- Description for Private Space Transition button -->
<string name="ps_container_transition">Private Space Transitioning</string>
<!-- Title for Private Space install app icon -->
- <string name="ps_add_button_label">Install apps</string>
+ <string name="ps_add_button_label">Install</string>
<!-- Content description for install app icon -->
<string name="ps_add_button_content_description">Install apps to Private Space</string>
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 009d709..b89d05e 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -96,7 +96,9 @@
import static com.android.launcher3.popup.SystemShortcut.WIDGETS;
import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
+import static com.android.launcher3.testing.shared.TestProtocol.CLOCK_ICON_DRAWABLE_LEAKING;
import static com.android.launcher3.testing.shared.TestProtocol.LAUNCHER_ACTIVITY_STOPPED_MESSAGE;
+import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.ItemInfoMatcher.forFolderMatch;
import static com.android.launcher3.util.SettingsCache.TOUCHPAD_NATURAL_SCROLLING;
@@ -421,6 +423,7 @@
@Override
@TargetApi(Build.VERSION_CODES.S)
protected void onCreate(Bundle savedInstanceState) {
+ testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onCreate: instance=" + this);
mStartupLatencyLogger = createStartupLatencyLogger(
sIsNewProcess
? LockedUserState.get(this).isUserUnlockedAtLauncherStartup()
@@ -1079,6 +1082,7 @@
@Override
protected void onStart() {
+ testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onStart: instance=" + this);
TraceHelper.INSTANCE.beginSection(ON_START_EVT);
super.onStart();
if (!mDeferOverlayCallbacks) {
@@ -1092,6 +1096,7 @@
@Override
@CallSuper
protected void onDeferredResumed() {
+ testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onDeferredResumed: instance=" + this);
logStopAndResume(true /* isResume */);
// Process any items that were added while Launcher was away.
@@ -1279,6 +1284,7 @@
@Override
protected void onResume() {
+ testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onResume: instance=" + this);
TraceHelper.INSTANCE.beginSection(ON_RESUME_EVT);
super.onResume();
@@ -1294,6 +1300,7 @@
@Override
protected void onPause() {
+ testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onPause: instance=" + this);
// Ensure that items added to Launcher are queued until Launcher returns
ItemInstallQueue.INSTANCE.get(this).pauseModelPush(FLAG_ACTIVITY_PAUSED);
@@ -1776,6 +1783,7 @@
@Override
public void onDestroy() {
+ testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onDestroy: instance=" + this);
super.onDestroy();
ACTIVITY_TRACKER.onActivityDestroyed(this);
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 03de334..869b995 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -206,7 +206,7 @@
}
private void refreshAndReloadLauncher() {
- LauncherIcons.clearPool();
+ LauncherIcons.clearPool(mContext);
mIconCache.updateIconParams(
mInvariantDeviceProfile.fillResIconDpi, mInvariantDeviceProfile.iconBitmapSize);
mModel.forceReload();
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index ae0e80c..53f9cfc 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -20,7 +20,6 @@
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
-import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PRIVATESPACE;
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_ICON;
@@ -28,8 +27,12 @@
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER;
import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING;
import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_BEGIN;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_END;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_LOCK_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_BEGIN;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_END;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
@@ -635,8 +638,6 @@
return;
}
ViewGroup settingsAndLockGroup = mPSHeader.findViewById(R.id.settingsAndLockGroup);
- ViewGroup lockButton = mPSHeader.findViewById(R.id.ps_lock_unlock_button);
- TextView lockText = lockButton.findViewById(R.id.lock_text);
if (settingsAndLockGroup.getLayoutTransition() == null) {
// Set a new transition if the current ViewGroup does not already contain one as each
// transition should only happen once when applied.
@@ -646,21 +647,30 @@
LayoutTransition.CHANGING,
expand ? SETTINGS_AND_LOCK_GROUP_TRANSITION_DELAY : NO_DELAY);
PropertySetter headerSetter = new AnimatedPropertySetter();
- ImageButton settingsButton = mPSHeader.findViewById(R.id.ps_settings_button);
- updateSettingsGearAlpha(settingsButton, expand, headerSetter);
- updateLockTextAlpha(lockText, expand, headerSetter);
+ headerSetter.add(updateSettingsGearAlpha(expand));
+ headerSetter.add(updateLockTextAlpha(expand));
AnimatorSet animatorSet = headerSetter.buildAnim();
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
+ mStatsLogManager.logger().sendToInteractionJankMonitor(
+ expand
+ ? LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_BEGIN
+ : LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_BEGIN,
+ mAllApps.getActiveRecyclerView());
// Animate the collapsing of the text at the same time while updating lock button.
- lockText.setVisibility(expand ? VISIBLE : GONE);
+ mPSHeader.findViewById(R.id.lock_text).setVisibility(expand ? VISIBLE : GONE);
setAnimationRunning(true);
}
});
animatorSet.addListener(forEndCallback(() -> {
setAnimationRunning(false);
getMainRecyclerView().setChildAttachedConsumer(child -> child.setAlpha(1));
+ mStatsLogManager.logger().sendToInteractionJankMonitor(
+ expand
+ ? LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_END
+ : LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_END,
+ mAllApps.getActiveRecyclerView());
if (!expand) {
// Call onAppsUpdated() because it may be canceled when this animation occurs.
mAllApps.getPersonalAppList().onAppsUpdated();
@@ -728,19 +738,44 @@
}
/** Change the settings gear alpha when expanded or collapsed. */
- private void updateSettingsGearAlpha(ImageButton settingsButton, boolean expand,
- PropertySetter setter) {
- float toAlpha = expand ? 1 : 0;
- setter.setFloat(settingsButton, VIEW_ALPHA, toAlpha, Interpolators.LINEAR)
- .setDuration(SETTINGS_OPACITY_DURATION).setStartDelay(expand ?
- SETTINGS_OPACITY_DELAY : NO_DELAY);
+ private ValueAnimator updateSettingsGearAlpha(boolean expand) {
+ if (mPSHeader == null) {
+ return new ValueAnimator();
+ }
+ float from = expand ? 0 : 1;
+ float to = expand ? 1 : 0;
+ ValueAnimator settingsAlphaAnim = ObjectAnimator.ofFloat(from, to);
+ settingsAlphaAnim.setDuration(SETTINGS_OPACITY_DURATION);
+ settingsAlphaAnim.setStartDelay(expand ? SETTINGS_OPACITY_DELAY : NO_DELAY);
+ settingsAlphaAnim.setInterpolator(Interpolators.LINEAR);
+ settingsAlphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ mPSHeader.findViewById(R.id.ps_settings_button)
+ .setAlpha((float) valueAnimator.getAnimatedValue());
+ }
+ });
+ return settingsAlphaAnim;
}
- private void updateLockTextAlpha(TextView textView, boolean expand, PropertySetter setter) {
- float toAlpha = expand ? 1 : 0;
- setter.setFloat(textView, VIEW_ALPHA, toAlpha, Interpolators.LINEAR)
- .setDuration(expand ? TEXT_UNLOCK_OPACITY_DURATION : TEXT_LOCK_OPACITY_DURATION)
- .setStartDelay(expand ? LOCK_TEXT_OPACITY_DELAY : NO_DELAY);
+ private ValueAnimator updateLockTextAlpha(boolean expand) {
+ if (mPSHeader == null) {
+ return new ValueAnimator();
+ }
+ float from = expand ? 0 : 1;
+ float to = expand ? 1 : 0;
+ ValueAnimator alphaAnim = ObjectAnimator.ofFloat(from, to);
+ alphaAnim.setDuration(expand ? TEXT_UNLOCK_OPACITY_DURATION : TEXT_LOCK_OPACITY_DURATION);
+ alphaAnim.setStartDelay(expand ? LOCK_TEXT_OPACITY_DELAY : NO_DELAY);
+ alphaAnim.setInterpolator(Interpolators.LINEAR);
+ alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ mPSHeader.findViewById(R.id.lock_text).setAlpha(
+ (float) valueAnimator.getAnimatedValue());
+ }
+ });
+ return alphaAnim;
}
void expandPrivateSpace() {
diff --git a/src/com/android/launcher3/allapps/UserProfileManager.java b/src/com/android/launcher3/allapps/UserProfileManager.java
index 6a1f37a..3351ee3 100644
--- a/src/com/android/launcher3/allapps/UserProfileManager.java
+++ b/src/com/android/launcher3/allapps/UserProfileManager.java
@@ -52,11 +52,11 @@
@Retention(RetentionPolicy.SOURCE)
public @interface UserProfileState { }
+ protected final StatsLogManager mStatsLogManager;
@UserProfileState
private int mCurrentState;
private final UserManager mUserManager;
- private final StatsLogManager mStatsLogManager;
private final UserCache mUserCache;
protected UserProfileManager(UserManager userManager,
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 1f388c2..ae8f1d5 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -76,7 +76,6 @@
import com.android.launcher3.celllayout.CellPosMapper;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.WidgetItem;
@@ -107,7 +106,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.ConcurrentLinkedQueue;
/**
* Utility class for generating the preview of Launcher for a given InvariantDeviceProfile.
@@ -126,44 +124,12 @@
*/
public static class PreviewContext extends SandboxContext {
- private final InvariantDeviceProfile mIdp;
- private final ConcurrentLinkedQueue<LauncherIconsForPreview> mIconPool =
- new ConcurrentLinkedQueue<>();
-
public PreviewContext(Context base, InvariantDeviceProfile idp) {
super(base);
- mIdp = idp;
putObject(InvariantDeviceProfile.INSTANCE, idp);
putObject(LauncherAppState.INSTANCE,
new LauncherAppState(this, null /* iconCacheFileName */));
}
-
- /**
- * Creates a new LauncherIcons for the preview, skipping the global pool
- */
- public LauncherIcons newLauncherIcons(Context context) {
- LauncherIconsForPreview launcherIconsForPreview = mIconPool.poll();
- if (launcherIconsForPreview != null) {
- return launcherIconsForPreview;
- }
- return new LauncherIconsForPreview(context, mIdp.fillResIconDpi, mIdp.iconBitmapSize,
- -1 /* poolId */);
- }
-
- private final class LauncherIconsForPreview extends LauncherIcons {
-
- private LauncherIconsForPreview(Context context, int fillResIconDpi, int iconBitmapSize,
- int poolId) {
- super(context, fillResIconDpi, iconBitmapSize, poolId);
- }
-
- @Override
- public void recycle() {
- // Clear any temporary state variables
- clear();
- mIconPool.offer(this);
- }
- }
}
private final List<OnDeviceProfileChangeListener> mDpChangeListeners = new ArrayList<>();
diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java
index 7331c6f..e90a1e0 100644
--- a/src/com/android/launcher3/icons/LauncherIcons.java
+++ b/src/com/android/launcher3/icons/LauncherIcons.java
@@ -25,79 +25,53 @@
import com.android.launcher3.Flags;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.graphics.IconShape;
-import com.android.launcher3.graphics.LauncherPreviewRenderer;
import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.UserIconInfo;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
/**
* Wrapper class to provide access to {@link BaseIconFactory} and also to provide pool of this class
* that are threadsafe.
*/
public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
- private static final Object sPoolSync = new Object();
- private static LauncherIcons sPool;
- private static int sPoolId = 0;
+ private static final MainThreadInitializedObject<Pool> POOL =
+ new MainThreadInitializedObject<>(Pool::new);
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static LauncherIcons obtain(Context context) {
- if (context instanceof LauncherPreviewRenderer.PreviewContext) {
- return ((LauncherPreviewRenderer.PreviewContext) context).newLauncherIcons(context);
- }
-
- int poolId;
- synchronized (sPoolSync) {
- if (sPool != null) {
- LauncherIcons m = sPool;
- sPool = m.next;
- m.next = null;
- return m;
- }
- poolId = sPoolId;
- }
-
- InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(context);
- return new LauncherIcons(context, idp.fillResIconDpi, idp.iconBitmapSize, poolId);
+ return POOL.get(context).obtain();
}
- public static void clearPool() {
- synchronized (sPoolSync) {
- sPool = null;
- sPoolId++;
- }
+ public static void clearPool(Context context) {
+ POOL.get(context).close();
}
- private final int mPoolId;
-
- private LauncherIcons next;
+ private final ConcurrentLinkedQueue<LauncherIcons> mPool;
private MonochromeIconFactory mMonochromeIconFactory;
- protected LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize, int poolId) {
+ protected LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize,
+ ConcurrentLinkedQueue<LauncherIcons> pool) {
super(context, fillResIconDpi, iconBitmapSize,
IconShape.INSTANCE.get(context).getShape().enableShapeDetection());
mMonoIconEnabled = Themes.isThemedIconEnabled(context);
- mPoolId = poolId;
+ mPool = pool;
}
/**
* Recycles a LauncherIcons that may be in-use.
*/
public void recycle() {
- synchronized (sPoolSync) {
- if (sPoolId != mPoolId) {
- return;
- }
- // Clear any temporary state variables
- clear();
-
- next = sPool;
- sPool = this;
- }
+ clear();
+ mPool.add(this);
}
@Override
@@ -122,4 +96,33 @@
public void close() {
recycle();
}
+
+ private static class Pool implements SafeCloseable {
+
+ private final Context mContext;
+
+ @NonNull
+ private ConcurrentLinkedQueue<LauncherIcons> mPool = new ConcurrentLinkedQueue<>();
+
+ private Pool(Context context) {
+ mContext = context;
+ }
+
+ public LauncherIcons obtain() {
+ ConcurrentLinkedQueue<LauncherIcons> pool = mPool;
+ LauncherIcons m = pool.poll();
+
+ if (m == null) {
+ InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(mContext);
+ return new LauncherIcons(mContext, idp.fillResIconDpi, idp.iconBitmapSize, pool);
+ } else {
+ return m;
+ }
+ }
+
+ @Override
+ public void close() {
+ mPool = new ConcurrentLinkedQueue<>();
+ }
+ }
}
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 2f3c2b6..25eeacb 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -769,7 +769,19 @@
LAUNCHER_PRIVATE_SPACE_USER_INSTALLED_APPS_COUNT(1672),
@UiEvent(doc = "Number of preinstalled Private profile apps, shown under separator line")
- LAUNCHER_PRIVATE_SPACE_PREINSTALLED_APPS_COUNT(1673)
+ LAUNCHER_PRIVATE_SPACE_PREINSTALLED_APPS_COUNT(1673),
+
+ @UiEvent(doc = "Private space lock animation started")
+ LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_BEGIN(1725),
+
+ @UiEvent(doc = "Private space lock animation finished")
+ LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_END(1726),
+
+ @UiEvent(doc = "Private space unlock animation started")
+ LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_BEGIN(1727),
+
+ @UiEvent(doc = "Private space unlock animation finished")
+ LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_END(1728)
// ADD MORE
;
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 8892a18..eabacbf 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -166,6 +166,13 @@
}
}
+ @Override
+ protected float getShiftRange() {
+ // We add the extra height added during predictive back / swipe up to the shift range, so
+ // that the idle interpolator knows to animate the view off fully.
+ return mContent.getHeight() + getBottomOffsetPx();
+ }
+
/**
* Click handler for tap to add button.
*/
diff --git a/tests/Android.bp b/tests/Android.bp
index 5ec2263..11177de 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -105,6 +105,7 @@
android_library {
name: "Launcher3TestResources",
resource_dirs: ["res"],
+ asset_dirs: ["assets"],
// TODO(b/319712088): re-enable use_resource_processor
use_resource_processor: false,
}
diff --git a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index 8c47332..74b3ccc 100644
--- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -179,6 +179,8 @@
public static final String WIDGET_CONFIG_NULL_EXTRA_INTENT = "b/324419890";
public static final String ACTIVITY_NOT_RESUMED_AFTER_BACK = "b/322823209";
public static final String OVERVIEW_SELECT_TOOLTIP_MISALIGNED = "b/332485341";
+ public static final String CLOCK_ICON_DRAWABLE_LEAKING = "b/319168409";
+
public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display";
public static final String REQUEST_IS_EMULATE_DISPLAY_RUNNING = "is-emulate-display-running";
diff --git a/tests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java
diff --git a/tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
diff --git a/tests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
similarity index 97%
rename from tests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
index 13dfd5e..c32461e 100644
--- a/tests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
@@ -22,6 +22,8 @@
import android.view.View
import androidx.core.view.get
import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
import com.android.launcher3.CellLayout
import com.android.launcher3.celllayout.board.CellLayoutBoard
import com.android.launcher3.celllayout.board.IconPoint
@@ -34,6 +36,7 @@
import org.junit.Assert
import org.junit.Rule
import org.junit.Test
+import org.junit.runner.RunWith
private class HotseatReorderTestCase(
val startBoard: CellLayoutBoard,
@@ -44,6 +47,8 @@
}
}
+@SmallTest
+@RunWith(AndroidJUnit4::class)
class HotseatReorderUnitTest {
private val applicationContext: Context =
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTestCase.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTestCase.java
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTestCase.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTestCase.java
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt
similarity index 95%
rename from tests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt
index 0bec1b2..a9355ec 100644
--- a/tests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt
@@ -141,11 +141,14 @@
ReorderPreviewAnimation.MODE_PREVIEW,
AnimationValues(dx = 0, dy = 0, scale = 100)
)
- testAnimationAtGivenProgress(
- PREVIEW_DURATION * 99,
- ReorderPreviewAnimation.MODE_PREVIEW,
- AnimationValues(dx = 5, dy = -10, scale = 96)
- )
+ // (b/339313407) Temporarily disable this test as the behavior is
+ // inconsistent between Soong & Gradle builds.
+ //
+ // testAnimationAtGivenProgress(
+ // PREVIEW_DURATION * 99,
+ // ReorderPreviewAnimation.MODE_PREVIEW,
+ // AnimationValues(dx = 5, dy = -10, scale = 96)
+ // )
testAnimationAtGivenProgress(
PREVIEW_DURATION * 98,
ReorderPreviewAnimation.MODE_PREVIEW,
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderTestCase.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderTestCase.java
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/ReorderTestCase.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderTestCase.java
diff --git a/tests/src/com/android/launcher3/celllayout/UnitTestCellLayoutBuilderRule.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/UnitTestCellLayoutBuilderRule.kt
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/UnitTestCellLayoutBuilderRule.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/UnitTestCellLayoutBuilderRule.kt
diff --git a/tests/src/com/android/launcher3/celllayout/testgenerator/DeterministicRandomGenerator.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/DeterministicRandomGenerator.kt
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/testgenerator/DeterministicRandomGenerator.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/DeterministicRandomGenerator.kt
diff --git a/tests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt
diff --git a/tests/src/com/android/launcher3/celllayout/testgenerator/RandomMultiBoardGenerator.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/RandomMultiBoardGenerator.kt
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/testgenerator/RandomMultiBoardGenerator.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/testgenerator/RandomMultiBoardGenerator.kt
diff --git a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
index e459956..89a4544 100644
--- a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
+++ b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
@@ -244,7 +244,6 @@
SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
.getShortcut(mTestContext, mAppInfo, mView);
- verify(mPrivateProfileManager, times(2)).getProfileUser();
assertNull(systemShortcut);
}
@@ -266,7 +265,6 @@
SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
.getShortcut(mTestContext, mAppInfo, mView);
- verify(mPrivateProfileManager, times(3)).getProfileUser();
verify(mPrivateProfileManager).isEnabled();
assertNotNull(systemShortcut);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index f3ec852..71cd19d 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -58,6 +58,7 @@
private static final String FAST_SCROLLER_RES_ID = "fast_scroller";
private static final Pattern EVENT_ALT_ESC_UP = Pattern.compile(
"Key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_ESCAPE.*?metaState=0");
+ private static final String UNLOCK_BUTTON_VIEW_RES_ID = "ps_lock_unlock_button";
private final int mHeight;
private final int mIconHeight;
@@ -433,7 +434,28 @@
public PrivateSpaceContainer getPrivateSpaceUnlockedView() {
final UiObject2 allAppsContainer = verifyActiveContainer();
final UiObject2 appListRecycler = getAppListRecycler(allAppsContainer);
- return new PrivateSpaceContainer(mLauncher, appListRecycler, this);
+ return new PrivateSpaceContainer(mLauncher, appListRecycler, this, true);
+ }
+
+ /** Returns PrivateSpaceContainer in locked state, if present in view. */
+ @NonNull
+ public PrivateSpaceContainer getPrivateSpaceLockedView() {
+ final UiObject2 allAppsContainer = verifyActiveContainer();
+ final UiObject2 appListRecycler = getAppListRecycler(allAppsContainer);
+ return new PrivateSpaceContainer(mLauncher, appListRecycler, this, false);
+ }
+
+ /**
+ * Toggles Lock/Unlock of Private Space, changing the All Apps Ui.
+ */
+ public void togglePrivateSpace() {
+ final UiObject2 allAppsContainer = verifyActiveContainer();
+ final UiObject2 appListRecycler = getAppListRecycler(allAppsContainer);
+ UiObject2 unLockButtonView = mLauncher.waitForObjectInContainer(appListRecycler,
+ UNLOCK_BUTTON_VIEW_RES_ID);
+ mLauncher.waitForObjectEnabled(unLockButtonView, "Private Space Unlock Button");
+ mLauncher.assertTrue("PS Unlock Button is non-clickable", unLockButtonView.isClickable());
+ unLockButtonView.click();
}
protected abstract void verifyVisibleContainerOnDismiss();
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 68829e0..2e3944d 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -359,6 +359,21 @@
}
/**
+ * Gets Overview Actions specific to grouped tasks.
+ *
+ * @return The Overview group actions bar
+ */
+ @NonNull
+ public OverviewActions getOverviewGroupActions() {
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to get overview group actions")) {
+ verifyActiveContainer();
+ UiObject2 groupActions = mLauncher.waitForOverviewObject("group_action_buttons");
+ return new OverviewActions(groupActions, mLauncher);
+ }
+ }
+
+ /**
* Returns if clear all button is visible.
*/
public boolean isClearAllVisible() {
@@ -449,10 +464,18 @@
private void verifyActionsViewVisibility() {
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to assert overview actions view visibility")) {
+ boolean isTablet = mLauncher.isTablet();
+ OverviewTask task = isTablet ? getFocusedTaskForTablet() : getCurrentTask();
+
if (isActionsViewVisible()) {
- mLauncher.waitForOverviewObject("action_buttons");
+ if (task.isTaskSplit()) {
+ mLauncher.waitForOverviewObject("group_action_buttons");
+ } else {
+ mLauncher.waitForOverviewObject("action_buttons");
+ }
} else {
mLauncher.waitUntilOverviewObjectGone("action_buttons");
+ mLauncher.waitUntilOverviewObjectGone("group_action_buttons");
}
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index aa8d339..68b0a36 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -108,7 +108,7 @@
public final class LauncherInstrumentation {
private static final String TAG = "Tapl";
- private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 15;
+ private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 5;
private static final int GESTURE_STEP_MS = 16;
static final Pattern EVENT_PILFER_POINTERS = Pattern.compile("pilferPointers");
diff --git a/tests/tapl/com/android/launcher3/tapl/PrivateSpaceContainer.java b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceContainer.java
index 0e65ffb..a2814f0 100644
--- a/tests/tapl/com/android/launcher3/tapl/PrivateSpaceContainer.java
+++ b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceContainer.java
@@ -25,22 +25,30 @@
*/
public class PrivateSpaceContainer {
private static final String PS_HEADER_RES_ID = "ps_header_layout";
- private static final String INSTALL_APP_TITLE = "Install apps";
+ private static final String INSTALL_APP_TITLE = "Install";
private static final String DIVIDER_RES_ID = "private_space_divider";
private final LauncherInstrumentation mLauncher;
private final UiObject2 mAppListRecycler;
private final AllApps mAppList;
+ private final boolean mPrivateSpaceEnabled;
PrivateSpaceContainer(LauncherInstrumentation launcherInstrumentation,
- UiObject2 appListRecycler, AllApps appList) {
+ UiObject2 appListRecycler, AllApps appList, boolean privateSpaceEnabled) {
mLauncher = launcherInstrumentation;
mAppListRecycler = appListRecycler;
mAppList = appList;
+ mPrivateSpaceEnabled = privateSpaceEnabled;
- verifyHeaderIsPresent();
- verifyInstallAppButtonIsPresent();
- verifyDividerIsPresent();
+ if (mPrivateSpaceEnabled) {
+ verifyHeaderIsPresent();
+ verifyInstallAppButtonIsPresent();
+ verifyDividerIsPresent();
+ } else {
+ verifyHeaderIsPresent();
+ verifyInstallAppButtonIsNotPresent();
+ verifyDividerIsNotPresent();
+ }
}
// Assert PS Header is in view.
@@ -48,7 +56,7 @@
private void verifyHeaderIsPresent() {
final UiObject2 psHeader = mLauncher.waitForObjectInContainer(mAppListRecycler,
PS_HEADER_RES_ID);
- new PrivateSpaceHeader(mLauncher, psHeader, true);
+ new PrivateSpaceHeader(mLauncher, psHeader, mPrivateSpaceEnabled);
}
@@ -57,11 +65,21 @@
mAppList.getAppIcon(INSTALL_APP_TITLE);
}
+ // Assert Install App Item is not present in view.
+ private void verifyInstallAppButtonIsNotPresent() {
+ mLauncher.waitUntilLauncherObjectGone(DIVIDER_RES_ID);
+ }
+
// Assert Sys App Divider is present in view.
private void verifyDividerIsPresent() {
mLauncher.waitForObjectInContainer(mAppListRecycler, DIVIDER_RES_ID);
}
+ // Assert Sys App Divider is not present in view.
+ private void verifyDividerIsNotPresent() {
+ mLauncher.waitUntilLauncherObjectGone(DIVIDER_RES_ID);
+ }
+
/**
* Verifies that a user installed app is present above the divider.
*/
@@ -73,4 +91,4 @@
mLauncher.assertTrue("Installed App: " + appName + " is not above the divider",
iconCenter.y < dividerCenter.y);
}
-}
+}
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/PrivateSpaceHeader.java b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceHeader.java
index 3a7f038..cc64aae 100644
--- a/tests/tapl/com/android/launcher3/tapl/PrivateSpaceHeader.java
+++ b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceHeader.java
@@ -45,7 +45,7 @@
if (mPrivateSpaceEnabled) {
verifyUnlockedState();
} else {
- mLauncher.fail("Private Space found in non enabled state");
+ verifyLockedState();
}
}
@@ -74,4 +74,23 @@
mLauncher.assertEquals("PS lock text is incorrect", "Lock", lockText.getText());
}
+
+ /** Verify Locked State elements in Private Space Header */
+ private void verifyLockedState() {
+ UiObject2 headerText = mLauncher.waitForObjectInContainer(mPrivateSpaceHeader,
+ PS_HEADER_TEXT_RES_ID);
+ mLauncher.assertEquals("PS Header Text is incorrect ",
+ "Private", headerText.getText());
+
+ UiObject2 unLockButtonView = mLauncher.waitForObjectInContainer(mPrivateSpaceHeader,
+ UNLOCK_BUTTON_VIEW_RES_ID);
+ mLauncher.waitForObjectEnabled(unLockButtonView, "Private Space Unlock Button");
+ mLauncher.assertTrue("PS Unlock Button is non-clickable", unLockButtonView.isClickable());
+
+ mLauncher.waitForObjectInContainer(mPrivateSpaceHeader,
+ LOCK_ICON_RES_ID);
+
+ mLauncher.waitUntilLauncherObjectGone(SETTINGS_BUTTON_RES_ID);
+ mLauncher.waitUntilLauncherObjectGone(LOCK_TEXT_RES_ID);
+ }
}