Merge "Animate the position of the selected bubble arrow in the expanded bubble bar." into udc-dev
diff --git a/quickstep/res/drawable-sw600dp-land/gesture_tutorial_home_step_shape.xml b/quickstep/res/drawable-sw600dp-land/gesture_tutorial_home_step_shape.xml
index 4cccd09..fd14d34 100644
--- a/quickstep/res/drawable-sw600dp-land/gesture_tutorial_home_step_shape.xml
+++ b/quickstep/res/drawable-sw600dp-land/gesture_tutorial_home_step_shape.xml
@@ -17,11 +17,7 @@
android:height="67dp"
android:viewportWidth="232"
android:viewportHeight="67">
- <group>
- <clip-path
- android:pathData="M0,0h232v67h-232z"/>
- <path
- android:pathData="M180.9,0.6H51.1C22.9,0.6 0,23.4 0,51.7V67.6H232V51.7C232,23.4 209.1,0.6 180.9,0.6Z"
- android:fillColor="#4B67AE"/>
- </group>
+ <path
+ android:pathData="M180.9,0.6H51.1C22.9,0.6 0,23.4 0,51.7V67.6H232V51.7C232,23.4 209.1,0.6 180.9,0.6Z"
+ android:fillColor="#4B67AE"/>
</vector>
diff --git a/quickstep/res/drawable-sw600dp-land/gesture_tutorial_overview_step_shape.xml b/quickstep/res/drawable-sw600dp-land/gesture_tutorial_overview_step_shape.xml
index 7011f6c..f271c47 100644
--- a/quickstep/res/drawable-sw600dp-land/gesture_tutorial_overview_step_shape.xml
+++ b/quickstep/res/drawable-sw600dp-land/gesture_tutorial_overview_step_shape.xml
@@ -17,11 +17,7 @@
android:height="94dp"
android:viewportWidth="194"
android:viewportHeight="94">
- <group>
- <clip-path
- android:pathData="M0,0h194v94.09h-194z"/>
- <path
- android:pathData="M185.56,76.95C184.79,75.3 184.3,73.56 184.21,71.81L182.85,55.81C182.46,51.34 180.13,47.27 176.45,44.65L163.25,35.44C161.8,34.37 160.54,33.11 159.47,31.65L150.16,18.46C147.54,14.77 143.47,12.45 139,12.06L123,10.6C121.25,10.41 119.51,10.02 117.86,9.24L103.31,2.45C101.27,1.49 99.04,1 96.91,1C94.77,1 92.54,1.49 90.5,2.45L75.95,9.24C74.31,10.02 72.56,10.51 70.81,10.6L54.81,11.96C50.35,12.35 46.27,14.68 43.65,18.36L34.44,31.56C33.37,33.01 32.11,34.27 30.66,35.34L17.27,44.65C13.58,47.27 11.26,51.34 10.87,55.81L9.41,71.81C9.22,73.56 8.83,75.3 8.05,76.95L1.26,91.5C0.78,92.67 0.39,93.83 0.1,94.99H193.52C193.32,93.83 192.94,92.57 192.35,91.5L185.56,76.95Z"
- android:fillColor="#7E44AD"/>
- </group>
+ <path
+ android:pathData="M185.56,76.95C184.79,75.3 184.3,73.56 184.21,71.81L182.85,55.81C182.46,51.34 180.13,47.27 176.45,44.65L163.25,35.44C161.8,34.37 160.54,33.11 159.47,31.65L150.16,18.46C147.54,14.77 143.47,12.45 139,12.06L123,10.6C121.25,10.41 119.51,10.02 117.86,9.24L103.31,2.45C101.27,1.49 99.04,1 96.91,1C94.77,1 92.54,1.49 90.5,2.45L75.95,9.24C74.31,10.02 72.56,10.51 70.81,10.6L54.81,11.96C50.35,12.35 46.27,14.68 43.65,18.36L34.44,31.56C33.37,33.01 32.11,34.27 30.66,35.34L17.27,44.65C13.58,47.27 11.26,51.34 10.87,55.81L9.41,71.81C9.22,73.56 8.83,75.3 8.05,76.95L1.26,91.5C0.78,92.67 0.39,93.83 0.1,94.99H193.52C193.32,93.83 192.94,92.57 192.35,91.5L185.56,76.95Z"
+ android:fillColor="#7E44AD"/>
</vector>
diff --git a/quickstep/res/drawable-sw720dp-land/gesture_tutorial_home_step_shape.xml b/quickstep/res/drawable-sw720dp-land/gesture_tutorial_home_step_shape.xml
index 5becb8b..3e71a3d 100644
--- a/quickstep/res/drawable-sw720dp-land/gesture_tutorial_home_step_shape.xml
+++ b/quickstep/res/drawable-sw720dp-land/gesture_tutorial_home_step_shape.xml
@@ -17,11 +17,7 @@
android:height="73dp"
android:viewportWidth="362"
android:viewportHeight="73">
- <group>
- <clip-path
- android:pathData="M0,0h362v73h-362z"/>
- <path
- android:pathData="M282.3,0H79.7C38,0 3.7,32.1 0.3,73H361.7C358.3,32.1 324,0 282.3,0Z"
- android:fillColor="#4B67AE"/>
- </group>
+ <path
+ android:pathData="M282.3,0H79.7C38,0 3.7,32.1 0.3,73H361.7C358.3,32.1 324,0 282.3,0Z"
+ android:fillColor="#4B67AE"/>
</vector>
diff --git a/quickstep/res/drawable-sw720dp-land/gesture_tutorial_overview_step_shape.xml b/quickstep/res/drawable-sw720dp-land/gesture_tutorial_overview_step_shape.xml
index 7143089..2f11192 100644
--- a/quickstep/res/drawable-sw720dp-land/gesture_tutorial_overview_step_shape.xml
+++ b/quickstep/res/drawable-sw720dp-land/gesture_tutorial_overview_step_shape.xml
@@ -17,11 +17,7 @@
android:height="144dp"
android:viewportWidth="297"
android:viewportHeight="144">
- <group>
- <clip-path
- android:pathData="M0,0h297v144.04h-297z"/>
- <path
- android:pathData="M284.38,116.48C283.19,113.95 282.45,111.28 282.3,108.61L280.22,84.1C279.63,77.27 276.06,71.03 270.42,67.03L250.22,52.92C247.99,51.28 246.06,49.35 244.43,47.13L230.18,26.93C226.16,21.29 219.93,17.72 213.1,17.13L188.6,14.9C185.92,14.6 183.25,14.01 180.72,12.82L158.45,2.43C155.33,0.94 151.91,0.2 148.65,0.2C145.38,0.2 141.97,0.94 138.85,2.43L116.57,12.82C114.05,14.01 111.38,14.75 108.7,14.9L84.2,16.98C77.37,17.57 71.13,21.14 67.12,26.78L53.01,46.98C51.38,49.21 49.45,51.14 47.22,52.77L26.73,67.03C21.09,71.03 17.52,77.27 16.93,84.1L14.7,108.61C14.4,111.28 13.81,113.95 12.62,116.48L2.23,138.75C1.48,140.53 0.89,142.32 0.45,144.1H296.55C296.26,142.32 295.66,140.38 294.77,138.75L284.38,116.48Z"
- android:fillColor="#7E44AD"/>
- </group>
+ <path
+ android:pathData="M284.38,116.48C283.19,113.95 282.45,111.28 282.3,108.61L280.22,84.1C279.63,77.27 276.06,71.03 270.42,67.03L250.22,52.92C247.99,51.28 246.06,49.35 244.43,47.13L230.18,26.93C226.16,21.29 219.93,17.72 213.1,17.13L188.6,14.9C185.92,14.6 183.25,14.01 180.72,12.82L158.45,2.43C155.33,0.94 151.91,0.2 148.65,0.2C145.38,0.2 141.97,0.94 138.85,2.43L116.57,12.82C114.05,14.01 111.38,14.75 108.7,14.9L84.2,16.98C77.37,17.57 71.13,21.14 67.12,26.78L53.01,46.98C51.38,49.21 49.45,51.14 47.22,52.77L26.73,67.03C21.09,71.03 17.52,77.27 16.93,84.1L14.7,108.61C14.4,111.28 13.81,113.95 12.62,116.48L2.23,138.75C1.48,140.53 0.89,142.32 0.45,144.1H296.55C296.26,142.32 295.66,140.38 294.77,138.75L284.38,116.48Z"
+ android:fillColor="#7E44AD"/>
</vector>
diff --git a/quickstep/res/drawable/gesture_tutorial_back_step_shape.xml b/quickstep/res/drawable/gesture_tutorial_back_step_shape.xml
index 68c5eb1..5f951e4 100644
--- a/quickstep/res/drawable/gesture_tutorial_back_step_shape.xml
+++ b/quickstep/res/drawable/gesture_tutorial_back_step_shape.xml
@@ -17,11 +17,7 @@
android:height="208dp"
android:viewportWidth="83"
android:viewportHeight="208">
- <group>
- <clip-path
- android:pathData="M0,0h83.95v208h-83.95z"/>
- <path
- android:pathData="M23.53,169.2L31.09,165.56C76.7,143.55 76.7,64.45 31.09,42.35L23.53,38.71C13.55,33.95 5.06,25.56 -1,14.92V193.08C5.06,182.44 13.55,174.05 23.53,169.2Z"
- android:fillColor="#217500"/>
- </group>
+ <path
+ android:pathData="M23.53,169.2L31.09,165.56C76.7,143.55 76.7,64.45 31.09,42.35L23.53,38.71C13.55,33.95 5.06,25.56 -1,14.92V193.08C5.06,182.44 13.55,174.05 23.53,169.2Z"
+ android:fillColor="#217500"/>
</vector>
diff --git a/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml b/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
index 39c7e73..d24219d 100644
--- a/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
+++ b/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
@@ -28,11 +28,13 @@
android:layout_width="0dp"
android:layout_height="@dimen/gesture_tutorial_menu_button_height"
android:layout_marginEnd="@dimen/gesture_tutorial_menu_button_spacing"
+ android:layout_marginBottom="24dp"
android:background="@drawable/gesture_tutorial_menu_button_background"
android:clipToOutline="true"
android:backgroundTint="@color/gesture_home_tutorial_background"
app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/gesture_tutorial_menu_back_button">
@@ -40,6 +42,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/gesture_tutorial_home_step_shape"
+ android:scaleType="fitXY"
+ android:adjustViewBounds="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
@@ -64,11 +68,13 @@
android:layout_width="0dp"
android:layout_height="@dimen/gesture_tutorial_menu_button_height"
android:layout_marginEnd="@dimen/gesture_tutorial_menu_button_spacing"
+ android:layout_marginBottom="24dp"
android:background="@drawable/gesture_tutorial_menu_button_background"
android:clipToOutline="true"
android:backgroundTint="@color/gesture_back_tutorial_exiting_app"
app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/guideline"
app:layout_constraintStart_toEndOf="@id/gesture_tutorial_menu_home_button"
app:layout_constraintEnd_toStartOf="@id/gesture_tutorial_menu_overview_button">
@@ -77,6 +83,8 @@
android:layout_height="wrap_content"
android:src="@drawable/gesture_tutorial_back_step_shape"
android:layout_marginBottom="@dimen/gesture_tutorial_menu_back_shape_bottom_margin"
+ android:scaleType="fitXY"
+ android:adjustViewBounds="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
@@ -99,11 +107,13 @@
android:id="@+id/gesture_tutorial_menu_overview_button"
android:layout_width="0dp"
android:layout_height="@dimen/gesture_tutorial_menu_button_height"
+ android:layout_marginBottom="24dp"
android:background="@drawable/gesture_tutorial_menu_button_background"
android:clipToOutline="true"
android:backgroundTint="@color/gesture_overview_tutorial_background"
app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/guideline"
app:layout_constraintStart_toEndOf="@id/gesture_tutorial_menu_back_button"
app:layout_constraintEnd_toEndOf="parent">
@@ -111,6 +121,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/gesture_tutorial_overview_step_shape"
+ android:scaleType="fitXY"
+ android:adjustViewBounds="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
@@ -142,10 +154,8 @@
style="@style/TextAppearance.GestureTutorial.ButtonLabel"
android:id="@+id/gesture_tutorial_menu_done_button"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingVertical="16dp"
- android:paddingHorizontal="26dp"
- android:layout_marginVertical="@dimen/gesture_tutorial_menu_done_button_margin"
+ android:layout_height="40dp"
+ android:layout_marginVertical="16dp"
android:text="@string/gesture_tutorial_action_button_label"
android:background="@drawable/gesture_tutorial_action_button_background"
android:stateListAnimator="@null"
diff --git a/quickstep/res/layout/gesture_tutorial_step_menu.xml b/quickstep/res/layout/gesture_tutorial_step_menu.xml
index 2836259..cf1e4d7 100644
--- a/quickstep/res/layout/gesture_tutorial_step_menu.xml
+++ b/quickstep/res/layout/gesture_tutorial_step_menu.xml
@@ -42,6 +42,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/gesture_tutorial_home_step_shape"
+ android:scaleType="fitXY"
+ android:adjustViewBounds="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
@@ -79,6 +81,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/gesture_tutorial_back_step_shape"
+ android:scaleType="fitXY"
+ android:adjustViewBounds="true"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
@@ -116,6 +120,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/gesture_tutorial_overview_step_shape"
+ android:scaleType="fitXY"
+ android:adjustViewBounds="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
@@ -147,9 +153,8 @@
style="@style/TextAppearance.GestureTutorial.ButtonLabel"
android:id="@+id/gesture_tutorial_menu_done_button"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingVertical="16dp"
- android:paddingHorizontal="26dp"
+ android:layout_height="40dp"
+ android:layout_marginVertical="16dp"
android:text="@string/gesture_tutorial_action_button_label"
android:background="@drawable/gesture_tutorial_action_button_background"
android:stateListAnimator="@null"
diff --git a/quickstep/res/values-sw600dp-land/dimens.xml b/quickstep/res/values-sw600dp-land/dimens.xml
index 9853140..9cb3fec 100644
--- a/quickstep/res/values-sw600dp-land/dimens.xml
+++ b/quickstep/res/values-sw600dp-land/dimens.xml
@@ -26,6 +26,5 @@
<dimen name="gesture_tutorial_menu_button_spacing">24dp</dimen>
<dimen name="gesture_tutorial_menu_done_button_top_spacing">40dp</dimen>
<dimen name="gesture_tutorial_menu_back_shape_bottom_margin">49dp</dimen>
- <dimen name="gesture_tutorial_menu_done_button_margin">16dp</dimen>
</resources>
diff --git a/quickstep/res/values-sw720dp-land/dimens.xml b/quickstep/res/values-sw720dp-land/dimens.xml
index 1d02ab5..4634a2d 100644
--- a/quickstep/res/values-sw720dp-land/dimens.xml
+++ b/quickstep/res/values-sw720dp-land/dimens.xml
@@ -21,7 +21,5 @@
<dimen name="gesture_tutorial_menu_button_spacing">49dp</dimen>
<dimen name="gesture_tutorial_menu_done_button_top_spacing">24dp</dimen>
<dimen name="gesture_tutorial_menu_back_shape_bottom_margin">21dp</dimen>
- <dimen name="gesture_tutorial_menu_done_button_spacing">80dp</dimen>
- <dimen name="gesture_tutorial_menu_done_button_margin">0dp</dimen>
</resources>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 5d2df70..d69b155 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -134,7 +134,6 @@
<dimen name="gesture_tutorial_menu_done_button_top_spacing">0dp</dimen>
<dimen name="gesture_tutorial_menu_back_shape_bottom_margin">0dp</dimen>
<dimen name="gesture_tutorial_menu_done_button_spacing">72dp</dimen>
- <dimen name="gesture_tutorial_menu_done_button_margin">0dp</dimen>
<!-- Gesture Tutorial mock conversations -->
<dimen name="gesture_tutorial_message_icon_size">44dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 977163b..682fccd 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -1448,7 +1448,6 @@
*/
private Animator getFallbackClosingWindowAnimators(RemoteAnimationTarget[] appTargets) {
final int rotationChange = getRotationChange(appTargets);
- SurfaceTransactionApplier surfaceApplier = new SurfaceTransactionApplier(mDragLayer);
Matrix matrix = new Matrix();
Point tmpPos = new Point();
Rect tmpRect = new Rect();
@@ -1504,7 +1503,7 @@
.setAlpha(1f);
}
}
- surfaceApplier.scheduleApply(transaction);
+ transaction.getTransaction().apply();
}
});
@@ -1592,7 +1591,8 @@
boolean playFallBackAnimation = (launcherView == null
&& launcherIsForceInvisibleOrOpening)
|| mLauncher.getWorkspace().isOverlayShown()
- || hasMultipleTargetsWithMode(appTargets, MODE_CLOSING);
+ || hasMultipleTargetsWithMode(appTargets, MODE_CLOSING)
+ || mLauncher.isDestroyed();
boolean playWorkspaceReveal = true;
boolean skipAllAppsScale = false;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index 5abeac7..a442849 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -176,9 +176,9 @@
deepShortcutCount,
mPopupDataProvider.getNotificationKeysForItem(item),
systemShortcuts);
- icon.clearAccessibilityFocus();
}
+ icon.clearAccessibilityFocus();
container.addOnAttachStateChangeListener(
new PopupLiveUpdateHandler<BaseTaskbarContext>(context, container) {
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBubble.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBubble.kt
index b1633e7..3cd5f75 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBubble.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBubble.kt
@@ -30,7 +30,5 @@
val appName: String
) {
- fun getKey(): String {
- return info.key
- }
+ val key: String = info.key
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index a466548..6d19692 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -360,7 +360,7 @@
Path dotPath;
int dotColor;
- boolean isImportantConvo = false; // TODO: (b/269671451) needs to be added to BubbleInfo
+ boolean isImportantConvo = b.isImportantConversation();
ShortcutRequest.QueryResult result = new ShortcutRequest(context,
new UserHandle(b.getUserId()))
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
index 84a5228..5902912 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
@@ -92,6 +92,11 @@
}
@Override
+ public View.AccessibilityDelegate getAccessibilityDelegate() {
+ return mTaskbarContext.getAccessibilityDelegate();
+ }
+
+ @Override
public TaskbarDragController getDragController() {
return mDragController;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
index 1ac0742..aeac760 100644
--- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
@@ -186,7 +186,8 @@
public void launchTutorialMenu() {
mFragment = new MenuFragment();
getSupportFragmentManager().beginTransaction()
- .add(R.id.gesture_tutorial_fragment_container, mFragment)
+ .replace(R.id.gesture_tutorial_fragment_container, mFragment)
+ .runOnCommit(() -> mFragment.onAttachedToWindow())
.commit();
}
diff --git a/quickstep/src/com/android/quickstep/interaction/MenuFragment.java b/quickstep/src/com/android/quickstep/interaction/MenuFragment.java
index ccff30d..46f79b1 100644
--- a/quickstep/src/com/android/quickstep/interaction/MenuFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/MenuFragment.java
@@ -19,6 +19,7 @@
import static com.android.quickstep.interaction.GestureSandboxActivity.KEY_TUTORIAL_TYPE;
import static com.android.quickstep.interaction.GestureSandboxActivity.KEY_USE_TUTORIAL_MENU;
+import android.graphics.Rect;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@@ -27,17 +28,33 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.R;
/** Displays the gesture nav tutorial menu. */
public final class MenuFragment extends GestureSandboxFragment {
+ @NonNull private Rect mInsets = new Rect();
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mInsets = InvariantDeviceProfile.INSTANCE.get(getContext())
+ .getDeviceProfile(getContext()).getInsets();
+ }
+
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View root = inflater.inflate(
R.layout.gesture_tutorial_step_menu, container, false);
+ root.setPadding(
+ root.getPaddingLeft() + mInsets.left,
+ root.getPaddingTop() + mInsets.top,
+ root.getPaddingRight() + mInsets.right,
+ root.getPaddingBottom() + mInsets.bottom);
+
root.findViewById(R.id.gesture_tutorial_menu_home_button).setOnClickListener(
v -> launchTutorialStep(TutorialController.TutorialType.HOME_NAVIGATION));
root.findViewById(R.id.gesture_tutorial_menu_back_button).setOnClickListener(
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index 298d49a..fbb8109 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -494,6 +494,7 @@
private long mLatencyInMillis;
private int mQueryLength = -1;
private int mSubEventType = 0;
+ private int mCardinality = -1;
@Override
public StatsLatencyLogger withInstanceId(InstanceId instanceId) {
@@ -532,6 +533,12 @@
}
@Override
+ public StatsLatencyLogger withCardinality(int cardinality) {
+ this.mCardinality = cardinality;
+ return this;
+ }
+
+ @Override
public void log(EventEnum event) {
if (IS_VERBOSE) {
String name = (event instanceof Enum) ? ((Enum) event).name() :
@@ -549,7 +556,8 @@
mLatencyInMillis, // latency_in_millis
mType.getId(), //type
mQueryLength, // query_length
- mSubEventType // sub_event_type
+ mSubEventType, // sub_event_type
+ mCardinality // cardinality
);
}
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index ff5af28..f17f074 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -213,6 +213,7 @@
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
+import java.util.stream.Collectors;
/**
* A list of recent tasks.
@@ -1320,6 +1321,29 @@
return null;
}
+ /**
+ * Returns a {@link TaskView} that has taskIds matching {@code taskIds} or null if no match.
+ */
+ @Nullable
+ public TaskView getTaskViewByTaskIds(int[] taskIds) {
+ if (!hasAnyValidTaskIds(taskIds)) {
+ return null;
+ }
+
+ for (int i = 0; i < getTaskViewCount(); i++) {
+ TaskView taskView = requireTaskViewAt(i);
+ if (Arrays.equals(taskIds, taskView.getTaskIds())) {
+ return taskView;
+ }
+ }
+ return null;
+ }
+
+ /** Returns false if {@code taskIds} is null or contains invalid values, true otherwise */
+ private boolean hasAnyValidTaskIds(int[] taskIds) {
+ return taskIds != null && !Arrays.equals(taskIds, INVALID_TASK_IDS);
+ }
+
public void setOverviewStateEnabled(boolean enabled) {
mOverviewStateEnabled = enabled;
updateTaskStackListenerState();
@@ -1589,10 +1613,10 @@
return;
}
- int currentTaskId = INVALID_TASK_ID;
+ int[] currentTaskId = INVALID_TASK_IDS;
TaskView currentTaskView = getTaskViewAt(mCurrentPage);
if (currentTaskView != null && currentTaskView.getTask() != null) {
- currentTaskId = currentTaskView.getTask().key.id;
+ currentTaskId = currentTaskView.getTaskIds();
}
// Unload existing visible task data
@@ -1604,8 +1628,8 @@
// Save running task ID if it exists before rebinding all taskViews, otherwise the task from
// the runningTaskView currently bound could get assigned to another TaskView
- int runningTaskId = getTaskIdsForTaskViewId(mRunningTaskViewId)[0];
- int focusedTaskId = getTaskIdsForTaskViewId(mFocusedTaskViewId)[0];
+ int[] runningTaskId = getTaskIdsForTaskViewId(mRunningTaskViewId);
+ int[] focusedTaskId = getTaskIdsForTaskViewId(mFocusedTaskViewId);
// Removing views sets the currentPage to 0, so we save this and restore it after
// the new set of views are added
@@ -1699,7 +1723,7 @@
}
// Keep same previous focused task
- TaskView newFocusedTaskView = getTaskViewByTaskId(focusedTaskId);
+ TaskView newFocusedTaskView = getTaskViewByTaskIds(focusedTaskId);
// If the list changed, maybe the focused task doesn't exist anymore
if (newFocusedTaskView == null && getTaskViewCount() > 0) {
newFocusedTaskView = getTaskViewAt(0);
@@ -1716,10 +1740,10 @@
updateChildTaskOrientations();
TaskView newRunningTaskView = null;
- if (runningTaskId != INVALID_TASK_ID) {
+ if (hasAnyValidTaskIds(runningTaskId)) {
// Update mRunningTaskViewId to be the new TaskView that was assigned by binding
// the full list of tasks to taskViews
- newRunningTaskView = getTaskViewByTaskId(runningTaskId);
+ newRunningTaskView = getTaskViewByTaskIds(runningTaskId);
if (newRunningTaskView != null) {
mRunningTaskViewId = newRunningTaskView.getTaskViewId();
} else {
@@ -1731,15 +1755,15 @@
if (mNextPage != INVALID_PAGE) {
// Restore mCurrentPage but don't call setCurrentPage() as that clobbers the scroll.
mCurrentPage = previousCurrentPage;
- if (currentTaskId != INVALID_TASK_ID) {
- currentTaskView = getTaskViewByTaskId(currentTaskId);
+ if (hasAnyValidTaskIds(currentTaskId)) {
+ currentTaskView = getTaskViewByTaskIds(currentTaskId);
if (currentTaskView != null) {
targetPage = indexOfChild(currentTaskView);
}
}
} else {
// Set the current page to the running task, but not if settling on new task.
- if (runningTaskId != INVALID_TASK_ID) {
+ if (hasAnyValidTaskIds(runningTaskId)) {
targetPage = indexOfChild(newRunningTaskView);
} else if (getTaskViewCount() > 0) {
TaskView taskView = requireTaskViewAt(0);
@@ -2210,8 +2234,8 @@
// Update the task data for the in/visible children
for (int i = 0; i < getTaskViewCount(); i++) {
TaskView taskView = requireTaskViewAt(i);
- Task task = taskView.getTask();
- if (task == null) {
+ TaskIdAttributeContainer[] containers = taskView.getTaskIdAttributeContainers();
+ if (containers[0] == null && containers[1] == null) {
continue;
}
int index = indexOfChild(taskView);
@@ -2222,34 +2246,43 @@
visible = lower <= index && index <= upper;
}
if (visible) {
- boolean skipLoadingTask = false;
+ // Default update all non-null tasks, then remove running ones
+ List<Task> tasksToUpdate = Arrays.stream(containers).filter(Objects::nonNull)
+ .map(TaskIdAttributeContainer::getTask)
+ .collect(Collectors.toCollection(ArrayList::new));
if (mTmpRunningTasks != null) {
for (Task t : mTmpRunningTasks) {
- if (task == t) {
- // Skip loading if this is the task that we are animating into
- skipLoadingTask = true;
- break;
- }
+ // Skip loading if this is the task that we are animating into
+ // TODO(b/280812109) change this equality check to use A.equals(B)
+ tasksToUpdate.removeIf(task -> task == t);
}
}
- if (skipLoadingTask) {
+ if (tasksToUpdate.isEmpty()) {
continue;
}
- if (!mHasVisibleTaskData.get(task.key.id)) {
- // Ignore thumbnail update if it's current running task during the gesture
- // We snapshot at end of gesture, it will update then
- int changes = dataChanges;
- if (taskView == getRunningTaskView() && mGestureActive) {
- changes &= ~TaskView.FLAG_UPDATE_THUMBNAIL;
+ for (Task task : tasksToUpdate) {
+ if (!mHasVisibleTaskData.get(task.key.id)) {
+ // Ignore thumbnail update if it's current running task during the gesture
+ // We snapshot at end of gesture, it will update then
+ int changes = dataChanges;
+ if (taskView == getRunningTaskView() && mGestureActive) {
+ changes &= ~TaskView.FLAG_UPDATE_THUMBNAIL;
+ }
+ taskView.onTaskListVisibilityChanged(true /* visible */, changes);
}
- taskView.onTaskListVisibilityChanged(true /* visible */, changes);
+ mHasVisibleTaskData.put(task.key.id, visible);
}
- mHasVisibleTaskData.put(task.key.id, visible);
} else {
- if (mHasVisibleTaskData.get(task.key.id)) {
- taskView.onTaskListVisibilityChanged(false /* visible */, dataChanges);
+ for (TaskIdAttributeContainer container : containers) {
+ if (container == null) {
+ continue;
+ }
+
+ if (mHasVisibleTaskData.get(container.getTask().key.id)) {
+ taskView.onTaskListVisibilityChanged(false /* visible */, dataChanges);
+ }
+ mHasVisibleTaskData.delete(container.getTask().key.id);
}
- mHasVisibleTaskData.delete(task.key.id);
}
}
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 796cd62..134ef6c 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -92,6 +92,7 @@
import com.android.quickstep.RecentsModel;
import com.android.quickstep.RemoteAnimationTargets;
import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
+import com.android.quickstep.TaskAnimationManager;
import com.android.quickstep.TaskIconCache;
import com.android.quickstep.TaskOverlayFactory;
import com.android.quickstep.TaskThumbnailCache;
@@ -652,7 +653,7 @@
* index 0 will contain the taskId, index 1 will be -1 indicating a null taskID value
*/
public int[] getTaskIds() {
- return mTaskIdContainer;
+ return Arrays.copyOf(mTaskIdContainer, mTaskIdContainer.length);
}
public boolean containsMultipleTasks() {
@@ -802,6 +803,14 @@
recentsView.addSideTaskLaunchCallback(callbackList);
return callbackList;
}
+ if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
+ // If the recents transition is running (ie. in live tile mode), then the start
+ // of a new task will merge into the existing transition and it currently will
+ // not be run independently, so we need to rely on the onTaskAppeared() call
+ // for the new task to trigger the side launch callback to flush this runnable
+ // list (which is usually flushed when the app launch animation finishes)
+ recentsView.addSideTaskLaunchCallback(opts.onEndCallback);
+ }
return opts.onEndCallback;
} else {
notifyTaskLaunchFailed(TAG);
diff --git a/quickstep/tests/src/com/android/quickstep/AbstractTaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/AbstractTaplTestsTaskbar.java
new file mode 100644
index 0000000..9c0b2bf
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/AbstractTaplTestsTaskbar.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import static junit.framework.TestCase.assertEquals;
+
+import android.content.Context;
+import android.content.Intent;
+
+import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.tapl.Taskbar;
+import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.ui.TaplTestsLauncher3;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.LauncherLayoutBuilder;
+import com.android.launcher3.util.TestUtil;
+
+import org.junit.After;
+import org.junit.Assume;
+
+import java.util.List;
+
+public class AbstractTaplTestsTaskbar extends AbstractQuickStepTest {
+
+ protected static final String TEST_APP_NAME = "LauncherTestApp";
+ protected static final String TEST_APP_PACKAGE =
+ getInstrumentation().getContext().getPackageName();
+ protected static final String CALCULATOR_APP_PACKAGE =
+ resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR);
+
+ protected AutoCloseable mLauncherLayout;
+ protected boolean mTaskbarWasInTransientMode;
+
+
+ @Override
+ public void setUp() throws Exception {
+ Assume.assumeTrue(mLauncher.isTablet());
+ super.setUp();
+
+ LauncherLayoutBuilder layoutBuilder = new LauncherLayoutBuilder().atHotseat(0).putApp(
+ "com.google.android.apps.nexuslauncher.tests",
+ "com.android.launcher3.testcomponent.BaseTestingActivity");
+ mLauncherLayout = TestUtil.setLauncherDefaultLayout(mTargetContext, layoutBuilder);
+ TaplTestsLauncher3.initialize(this);
+
+ startAppFast(CALCULATOR_APP_PACKAGE);
+ mLauncher.enableBlockTimeout(true);
+ mLauncher.showTaskbarIfHidden();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ setTaskbarMode(mLauncher, mTaskbarWasInTransientMode);
+ mLauncher.enableBlockTimeout(false);
+ if (mLauncherLayout != null) {
+ mLauncherLayout.close();
+ }
+ }
+
+ protected static boolean isTaskbarInTransientMode(Context context) {
+ return DisplayController.isTransientTaskbar(context);
+ }
+
+ protected Taskbar getTaskbar() {
+ Taskbar taskbar = mLauncher.getLaunchedAppState().getTaskbar();
+ List<String> taskbarIconNames = taskbar.getIconNames();
+ List<String> hotseatIconNames = mLauncher.getHotseatIconNames();
+
+ assertEquals("Taskbar and hotseat icon counts do not match",
+ taskbarIconNames.size(), hotseatIconNames.size());
+
+ for (int i = 0; i < taskbarIconNames.size(); i++) {
+ assertEquals("Taskbar and Hotseat icons do not match",
+ taskbarIconNames, hotseatIconNames);
+ }
+
+ return taskbar;
+ }
+
+ protected static void setTaskbarMode(LauncherInstrumentation launcher,
+ boolean expectTransientTaskbar) {
+ launcher.enableTransientTaskbar(expectTransientTaskbar);
+ launcher.recreateTaskbar();
+ launcher.checkForAnomaly(true, true);
+ AbstractLauncherUiTest.checkDetectedLeaks(launcher);
+ }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
new file mode 100644
index 0000000..ee0eeb2
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class TaplTestsPersistentTaskbar extends AbstractTaplTestsTaskbar {
+
+ @Override
+ public void setUp() throws Exception {
+ mTaskbarWasInTransientMode = isTaskbarInTransientMode(mTargetContext);
+ setTaskbarMode(mLauncher, false);
+ super.setUp();
+ }
+
+ @Test
+ @TaskbarModeSwitch(mode = PERSISTENT)
+ public void testHideShowTaskbar() {
+ getTaskbar().hide();
+ mLauncher.getLaunchedAppState().showTaskbar();
+ }
+
+ @Test
+ @TaskbarModeSwitch(mode = PERSISTENT)
+ public void testHideTaskbarPersistsOnRecreate() {
+ getTaskbar().hide();
+ mLauncher.recreateTaskbar();
+ mLauncher.getLaunchedAppState().assertTaskbarHidden();
+ }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
index f5c78f6..021e118 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
@@ -15,121 +15,68 @@
*/
package com.android.quickstep;
-import static androidx.test.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.launcher3.config.FeatureFlags.ENABLE_CURSOR_HOVER_STATES;
-import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT;
-import static com.android.quickstep.TaskbarModeSwitchRule.Mode.TRANSIENT;
-
-import static junit.framework.TestCase.assertEquals;
-
-import android.content.Intent;
+import static com.android.quickstep.TaplTestsTaskbar.TaskbarMode.PERSISTENT;
+import static com.android.quickstep.TaplTestsTaskbar.TaskbarMode.TRANSIENT;
import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
-import com.android.launcher3.tapl.Taskbar;
-import com.android.launcher3.ui.TaplTestsLauncher3;
-import com.android.launcher3.util.LauncherLayoutBuilder;
-import com.android.launcher3.util.TestUtil;
+import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
-import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
-import org.junit.After;
-import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
-import java.util.List;
+import java.util.Arrays;
+import java.util.Collection;
@LargeTest
-@RunWith(AndroidJUnit4.class)
-public class TaplTestsTaskbar extends AbstractQuickStepTest {
+@RunWith(Parameterized.class)
+public class TaplTestsTaskbar extends AbstractTaplTestsTaskbar {
- private static final String TEST_APP_NAME = "LauncherTestApp";
- private static final String TEST_APP_PACKAGE =
- getInstrumentation().getContext().getPackageName();
- private static final String CALCULATOR_APP_PACKAGE =
- resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR);
+ private final TaplTestsTaskbar.TaskbarMode mTaskbarMode;
- private AutoCloseable mLauncherLayout;
+ public enum TaskbarMode {
+ TRANSIENT, PERSISTENT
+ }
+
+ @Parameterized.Parameters(name = "{0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][]{
+ {PERSISTENT}, {TRANSIENT}
+ });
+ }
+
+ public TaplTestsTaskbar(TaskbarMode mode) {
+ mTaskbarMode = mode;
+ }
@Override
public void setUp() throws Exception {
- Assume.assumeTrue(mLauncher.isTablet());
+ mTaskbarWasInTransientMode = isTaskbarInTransientMode(mTargetContext);
+ setTaskbarMode(mLauncher, isTaskbarTestModeTransient());
super.setUp();
-
- LauncherLayoutBuilder layoutBuilder = new LauncherLayoutBuilder().atHotseat(0).putApp(
- "com.google.android.apps.nexuslauncher.tests",
- "com.android.launcher3.testcomponent.BaseTestingActivity");
- mLauncherLayout = TestUtil.setLauncherDefaultLayout(mTargetContext, layoutBuilder);
- TaplTestsLauncher3.initialize(this);
-
- startAppFast(CALCULATOR_APP_PACKAGE);
- mLauncher.enableBlockTimeout(true);
- mLauncher.showTaskbarIfHidden();
}
- @After
- public void tearDown() throws Exception {
- mLauncher.enableBlockTimeout(false);
- if (mLauncherLayout != null) {
- mLauncherLayout.close();
+ @Test
+ public void testLaunchApp() {
+ getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
+ // We are using parameterized test runner to share code between different test cases with
+ // taskbar variants. But, sometimes we only need to assert things for particular Taskbar
+ // variants.
+ if (isTaskbarTestModeTransient() && mLauncher.getNavigationModel()
+ != LauncherInstrumentation.NavigationModel.THREE_BUTTON) {
+ mLauncher.getLaunchedAppState().assertTaskbarHidden();
}
}
@Test
- @TaskbarModeSwitch(mode = PERSISTENT)
- public void testHideShowTaskbar() {
- getTaskbar().hide();
- mLauncher.getLaunchedAppState().showTaskbar();
- }
-
- @Test
- @TaskbarModeSwitch(mode = PERSISTENT)
- public void testHideTaskbarPersistsOnRecreate() {
- getTaskbar().hide();
- mLauncher.recreateTaskbar();
- mLauncher.getLaunchedAppState().assertTaskbarHidden();
- }
-
- @Test
- @TaskbarModeSwitch(mode = PERSISTENT)
- public void testLaunchApp() throws Exception {
- getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
- }
-
- @Test
- @TaskbarModeSwitch(mode = TRANSIENT)
- public void testTransientLaunchApp() throws Exception {
- getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
- mLauncher.getLaunchedAppState().assertTaskbarHidden();
- }
-
- @Test
- @TaskbarModeSwitch(mode = PERSISTENT)
- public void testOpenMenu() throws Exception {
+ public void testOpenMenu() {
getTaskbar().getAppIcon(TEST_APP_NAME).openMenu();
}
@Test
- @TaskbarModeSwitch(mode = TRANSIENT)
- public void testTransientOpenMenu() throws Exception {
- getTaskbar().getAppIcon(TEST_APP_NAME).openMenu();
- }
-
- @Test
- @TaskbarModeSwitch(mode = PERSISTENT)
- public void testLaunchShortcut() throws Exception {
- getTaskbar().getAppIcon(TEST_APP_NAME)
- .openDeepShortcutMenu()
- .getMenuItem("Shortcut 1")
- .launch(TEST_APP_PACKAGE);
- }
-
- @Test
- @TaskbarModeSwitch(mode = TRANSIENT)
- public void testTransientLaunchShortcut() throws Exception {
+ public void testLaunchShortcut() {
getTaskbar().getAppIcon(TEST_APP_NAME)
.openDeepShortcutMenu()
.getMenuItem("Shortcut 1")
@@ -139,27 +86,21 @@
@Test
@ScreenRecord // b/231615831
@PortraitLandscape
- @TaskbarModeSwitch(mode = PERSISTENT)
- public void testLaunchAppInSplitscreen() throws Exception {
+ public void testLaunchAppInSplitscreen() {
getTaskbar().getAppIcon(TEST_APP_NAME).dragToSplitscreen(
TEST_APP_PACKAGE, CALCULATOR_APP_PACKAGE);
+ // We are using parameterized test runner to share code between different test cases with
+ // taskbar variants. But, sometimes we only need to assert things for particular Taskbar
+ // variants.
+ if (isTaskbarTestModeTransient()) {
+ mLauncher.getLaunchedAppState().assertTaskbarHidden();
+ }
}
@Test
@ScreenRecord // b/231615831
@PortraitLandscape
- @TaskbarModeSwitch(mode = TRANSIENT)
- public void testTransientLaunchAppInSplitscreen() throws Exception {
- getTaskbar().getAppIcon(TEST_APP_NAME).dragToSplitscreen(
- TEST_APP_PACKAGE, CALCULATOR_APP_PACKAGE);
- mLauncher.getLaunchedAppState().assertTaskbarHidden();
- }
-
- @Test
- @ScreenRecord // b/231615831
- @PortraitLandscape
- @TaskbarModeSwitch(mode = PERSISTENT)
- public void testLaunchShortcutInSplitscreen() throws Exception {
+ public void testLaunchShortcutInSplitscreen() {
getTaskbar().getAppIcon(TEST_APP_NAME)
.openDeepShortcutMenu()
.getMenuItem("Shortcut 1")
@@ -167,53 +108,17 @@
}
@Test
- @ScreenRecord // b/231615831
- @PortraitLandscape
- @TaskbarModeSwitch(mode = TRANSIENT)
- public void testTransientLaunchShortcutInSplitscreen() throws Exception {
- getTaskbar().getAppIcon(TEST_APP_NAME)
- .openDeepShortcutMenu()
- .getMenuItem("Shortcut 1")
- .dragToSplitscreen(TEST_APP_PACKAGE, CALCULATOR_APP_PACKAGE);
- }
-
- @Test
- @TaskbarModeSwitch(mode = PERSISTENT)
- public void testLaunchApp_FromTaskbarAllApps() throws Exception {
+ public void testLaunchApp_fromTaskbarAllApps() {
getTaskbar().openAllApps().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
}
@Test
- @TaskbarModeSwitch(mode = TRANSIENT)
- public void testTransientLaunchApp_FromTaskbarAllApps() throws Exception {
- getTaskbar().openAllApps().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
- }
-
- @Test
- @TaskbarModeSwitch(mode = PERSISTENT)
- public void testOpenMenu_FromTaskbarAllApps() throws Exception {
+ public void testOpenMenu_fromTaskbarAllApps() {
getTaskbar().openAllApps().getAppIcon(TEST_APP_NAME).openMenu();
}
@Test
- @TaskbarModeSwitch(mode = TRANSIENT)
- public void testTransientOpenMenu_FromTaskbarAllApps() throws Exception {
- getTaskbar().openAllApps().getAppIcon(TEST_APP_NAME).openMenu();
- }
-
- @Test
- @TaskbarModeSwitch(mode = PERSISTENT)
- public void testLaunchShortcut_FromTaskbarAllApps() throws Exception {
- getTaskbar().openAllApps()
- .getAppIcon(TEST_APP_NAME)
- .openDeepShortcutMenu()
- .getMenuItem("Shortcut 1")
- .launch(TEST_APP_PACKAGE);
- }
-
- @Test
- @TaskbarModeSwitch(mode = TRANSIENT)
- public void testTransientLaunchShortcut_FromTaskbarAllApps() throws Exception {
+ public void testLaunchShortcut_fromTaskbarAllApps() {
getTaskbar().openAllApps()
.getAppIcon(TEST_APP_NAME)
.openDeepShortcutMenu()
@@ -224,8 +129,7 @@
@Test
@ScreenRecord // b/231615831
@PortraitLandscape
- @TaskbarModeSwitch(mode = PERSISTENT)
- public void testLaunchAppInSplitscreen_FromTaskbarAllApps() throws Exception {
+ public void testLaunchAppInSplitscreen_fromTaskbarAllApps() {
getTaskbar().openAllApps()
.getAppIcon(TEST_APP_NAME)
.dragToSplitscreen(TEST_APP_PACKAGE, CALCULATOR_APP_PACKAGE);
@@ -234,18 +138,7 @@
@Test
@ScreenRecord // b/231615831
@PortraitLandscape
- @TaskbarModeSwitch(mode = TRANSIENT)
- public void testTransientLaunchAppInSplitscreen_FromTaskbarAllApps() throws Exception {
- getTaskbar().openAllApps()
- .getAppIcon(TEST_APP_NAME)
- .dragToSplitscreen(TEST_APP_PACKAGE, CALCULATOR_APP_PACKAGE);
- }
-
- @Test
- @ScreenRecord // b/231615831
- @PortraitLandscape
- @TaskbarModeSwitch(mode = PERSISTENT)
- public void testLaunchShortcutInSplitscreen_FromTaskbarAllApps() throws Exception {
+ public void testLaunchShortcutInSplitscreen_fromTaskbarAllApps() {
getTaskbar().openAllApps()
.getAppIcon(TEST_APP_NAME)
.openDeepShortcutMenu()
@@ -253,64 +146,7 @@
.dragToSplitscreen(TEST_APP_PACKAGE, CALCULATOR_APP_PACKAGE);
}
- @Test
- @ScreenRecord // b/231615831
- @PortraitLandscape
- @TaskbarModeSwitch(mode = TRANSIENT)
- public void testTransientLaunchShortcutInSplitscreen_FromTaskbarAllApps() throws Exception {
- getTaskbar().openAllApps()
- .getAppIcon(TEST_APP_NAME)
- .openDeepShortcutMenu()
- .getMenuItem("Shortcut 1")
- .dragToSplitscreen(TEST_APP_PACKAGE, CALCULATOR_APP_PACKAGE);
- }
-
- @Test
- @TaskbarModeSwitch(mode = TRANSIENT)
- public void testShowTaskbarUnstashHintOnHover() {
- try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_CURSOR_HOVER_STATES, true)) {
- getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
- mLauncher.getLaunchedAppState().hoverToShowTaskbarUnstashHint();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- @Test
- @TaskbarModeSwitch(mode = TRANSIENT)
- public void testUnstashTaskbarOnScreenBottomEdgeHover() {
- try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_CURSOR_HOVER_STATES, true)) {
- getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
- mLauncher.getLaunchedAppState().hoverScreenBottomEdgeToUnstashTaskbar();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- @Test
- @TaskbarModeSwitch(mode = TRANSIENT)
- public void testHoverBelowHintedTaskbarToUnstash() {
- try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_CURSOR_HOVER_STATES, true)) {
- getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
- mLauncher.getLaunchedAppState().hoverBelowHintedTaskbarToUnstash();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- private Taskbar getTaskbar() {
- Taskbar taskbar = mLauncher.getLaunchedAppState().getTaskbar();
- List<String> taskbarIconNames = taskbar.getIconNames();
- List<String> hotseatIconNames = mLauncher.getHotseatIconNames();
-
- assertEquals("Taskbar and hotseat icon counts do not match",
- taskbarIconNames.size(), hotseatIconNames.size());
-
- for (int i = 0; i < taskbarIconNames.size(); i++) {
- assertEquals("Taskbar and Hotseat icons do not match",
- taskbarIconNames, hotseatIconNames);
- }
-
- return taskbar;
+ private boolean isTaskbarTestModeTransient() {
+ return TRANSIENT == mTaskbarMode;
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java
new file mode 100644
index 0000000..6b61f18
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import static com.android.launcher3.config.FeatureFlags.ENABLE_CURSOR_HOVER_STATES;
+import static com.android.quickstep.TaskbarModeSwitchRule.Mode.TRANSIENT;
+
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.launcher3.util.TestUtil;
+import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class TaplTestsTransientTaskbar extends AbstractTaplTestsTaskbar {
+
+ @Override
+ public void setUp() throws Exception {
+ mTaskbarWasInTransientMode = isTaskbarInTransientMode(mTargetContext);
+ setTaskbarMode(mLauncher, true);
+ super.setUp();
+ }
+
+ @Test
+ @TaskbarModeSwitch(mode = TRANSIENT)
+ public void testShowTaskbarUnstashHintOnHover() {
+ try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_CURSOR_HOVER_STATES, true)) {
+ getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
+ mLauncher.getLaunchedAppState().hoverToShowTaskbarUnstashHint();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Test
+ @TaskbarModeSwitch(mode = TRANSIENT)
+ public void testUnstashTaskbarOnScreenBottomEdgeHover() {
+ try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_CURSOR_HOVER_STATES, true)) {
+ getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
+ mLauncher.getLaunchedAppState().hoverScreenBottomEdgeToUnstashTaskbar();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Test
+ @TaskbarModeSwitch(mode = TRANSIENT)
+ public void testHoverBelowHintedTaskbarToUnstash() {
+ try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_CURSOR_HOVER_STATES, true)) {
+ getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
+ mLauncher.getLaunchedAppState().hoverBelowHintedTaskbarToUnstash();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt b/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
index acfd54c..65542cf 100644
--- a/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
@@ -33,14 +33,10 @@
import com.android.launcher3.statemanager.StateManager
import com.android.launcher3.util.ComponentKey
import com.android.launcher3.util.SplitConfigurationOptions
-import com.android.launcher3.util.SplitConfigurationOptions.StagePosition
-import com.android.launcher3.util.mock
import com.android.launcher3.util.withArgCaptor
import com.android.quickstep.RecentsModel
import com.android.quickstep.SystemUiProxy
import com.android.systemui.shared.recents.model.Task
-import java.util.ArrayList
-import java.util.function.Consumer
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNull
@@ -50,7 +46,9 @@
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
+import java.util.function.Consumer
@RunWith(AndroidJUnit4::class)
class SplitSelectStateControllerTest {
@@ -355,6 +353,7 @@
@Test
fun secondPendingIntentSet() {
val itemInfo = ItemInfo()
+ `when`(pendingIntent.creatorUserHandle).thenReturn(primaryUserHandle)
splitSelectStateController.setInitialTaskSelect(null, 0, itemInfo, null, 1)
splitSelectStateController.setSecondTask(pendingIntent)
assertTrue(splitSelectStateController.isBothSplitAppsConfirmed)
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index ce8d901..8136534 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -199,6 +199,9 @@
<attr name="demoModeLayoutId" format="reference" />
<attr name="isScalable" format="boolean" />
<attr name="devicePaddingId" format="reference" />
+ <!-- File that contains the specs for the workspace.
+ Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled -->
+ <attr name="workspaceSpecsId" format="reference" />
<!-- By default all categories are enabled -->
<attr name="deviceCategory" format="integer">
<!-- Enable on phone only -->
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 58a447d..9e73453 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -75,7 +75,6 @@
<color name="text_color_tertiary_dark">#CCFFFFFF</color>
<color name="wallpaper_popup_scrim">?android:attr/colorAccent</color>
- <color name="wallpaper_scrim_color">#0D878787</color>
<color name="workspace_accent_color_light">#ff8df5e3</color>
<color name="workspace_accent_color_dark">#ff3d665f</color>
diff --git a/res/xml/dynamic_resources.xml b/res/xml/dynamic_resources.xml
index 3a3e239..f7a631b 100644
--- a/res/xml/dynamic_resources.xml
+++ b/res/xml/dynamic_resources.xml
@@ -4,6 +4,5 @@
<entry id="@color/delete_target_hover_tint" />
<entry id="@color/delete_target_hover_tint" />
<entry id="@color/delete_target_hover_tint" />
- <entry id="@color/wallpaper_scrim_color" />
</DynamicResources>
diff --git a/res/xml/widget_sections.xml b/res/xml/widget_sections.xml
index 6165bf7..742991f 100644
--- a/res/xml/widget_sections.xml
+++ b/res/xml/widget_sections.xml
@@ -26,6 +26,6 @@
launcher:category="1"
launcher:sectionDrawable="@drawable/ic_note_taking_widget_category"
launcher:sectionTitle="@string/widget_category_note_taking">
- <widget launcher:provider="com.android.settings/com.android.settings.notetask.shortcut.CreateNoteTaskShortcutActivity" />
+ <widget launcher:provider="com.android.systemui/.notetask.shortcut.CreateNoteTaskShortcutActivity" />
</section>
</widget-sections>
\ No newline at end of file
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 8675226..0231090 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -101,6 +101,7 @@
public final float aspectRatio;
public final boolean isScalableGrid;
+ public final boolean isResponsiveGrid;
private final int mTypeIndex;
/**
@@ -293,6 +294,10 @@
this.rotationHint = windowBounds.rotationHint;
mInsets.set(windowBounds.insets);
+ // TODO(b/241386436):
+ // for testing that the flag works only, shouldn't change any launcher behaviour
+ isResponsiveGrid = inv.workspaceSpecsId != INVALID_RESOURCE_HANDLE;
+
isScalableGrid = inv.isScalable && !isVerticalBarLayout() && !isMultiWindowMode;
// Determine device posture.
mInfo = info;
@@ -1577,6 +1582,7 @@
writer.println(prefix + "\taspectRatio:" + aspectRatio);
+ writer.println(prefix + "\tisResponsiveGrid:" + isResponsiveGrid);
writer.println(prefix + "\tisScalableGrid:" + isScalableGrid);
writer.println(prefix + "\tinv.numRows: " + inv.numRows);
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 3aa582d..376f54d 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -48,6 +48,7 @@
import androidx.annotation.XmlRes;
import androidx.core.content.res.ResourcesCompat;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.DotRenderer;
import com.android.launcher3.model.DeviceGridState;
import com.android.launcher3.provider.RestoreDbTask;
@@ -105,7 +106,7 @@
static final int INDEX_TWO_PANEL_PORTRAIT = 2;
static final int INDEX_TWO_PANEL_LANDSCAPE = 3;
- /** These resources are used to override the device profile */
+ /** These resources are used to override the device profile */
private static final String RES_GRID_NUM_ROWS = "grid_num_rows";
private static final String RES_GRID_NUM_COLUMNS = "grid_num_columns";
private static final String RES_GRID_ICON_SIZE_DP = "grid_icon_size_dp";
@@ -177,6 +178,8 @@
protected boolean isScalable;
@XmlRes
public int devicePaddingId = INVALID_RESOURCE_HANDLE;
+ @XmlRes
+ public int workspaceSpecsId = INVALID_RESOURCE_HANDLE;
public String dbFile;
public int defaultLayoutId;
@@ -350,6 +353,7 @@
isScalable = closestProfile.isScalable;
devicePaddingId = closestProfile.devicePaddingId;
+ workspaceSpecsId = closestProfile.mWorkspaceSpecsId;
this.deviceType = deviceType;
inlineNavButtonsEndSpacing = closestProfile.inlineNavButtonsEndSpacing;
@@ -795,6 +799,7 @@
private final boolean isScalable;
private final int devicePaddingId;
+ private final int mWorkspaceSpecsId;
public GridOption(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(
@@ -836,7 +841,7 @@
inlineNavButtonsEndSpacing =
a.getResourceId(R.styleable.GridDisplayOption_inlineNavButtonsEndSpacing,
- R.dimen.taskbar_button_margin_default);
+ R.dimen.taskbar_button_margin_default);
numFolderRows = a.getInt(
R.styleable.GridDisplayOption_numFolderRows, numRows);
@@ -856,6 +861,13 @@
deviceCategory = a.getInt(R.styleable.GridDisplayOption_deviceCategory,
DEVICE_CATEGORY_ALL);
+ if (FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE.get()) {
+ mWorkspaceSpecsId = a.getResourceId(
+ R.styleable.GridDisplayOption_workspaceSpecsId, INVALID_RESOURCE_HANDLE);
+ } else {
+ mWorkspaceSpecsId = INVALID_RESOURCE_HANDLE;
+ }
+
int inlineForRotation = a.getInt(R.styleable.GridDisplayOption_inlineQsb,
DONT_INLINE_QSB);
inlineQsb[INDEX_DEFAULT] =
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 29b0f08..ffd56cc 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -214,6 +214,7 @@
import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.util.ViewOnDrawExecutor;
import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.views.ComposeInitializer;
import com.android.launcher3.views.FloatingIconView;
import com.android.launcher3.views.FloatingSurfaceView;
import com.android.launcher3.views.OptionsPopupView;
@@ -553,6 +554,8 @@
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
setContentView(getRootView());
+ ComposeInitializer.initCompose(this);
+
if (mOnInitialBindListener != null) {
getRootView().getViewTreeObserver().addOnPreDrawListener(mOnInitialBindListener);
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 7f04860..8dc1204 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -372,10 +372,6 @@
"ENABLE_ENFORCED_ROUNDED_CORNERS", ENABLED,
"Enforce rounded corners on all App Widgets");
- public static final BooleanFlag ENABLE_WALLPAPER_SCRIM = getDebugFlag(270393604,
- "ENABLE_WALLPAPER_SCRIM", DISABLED,
- "Enables scrim over wallpaper for text protection.");
-
public static final BooleanFlag ENABLE_ICON_LABEL_AUTO_SCALING = getDebugFlag(270393294,
"ENABLE_ICON_LABEL_AUTO_SCALING", ENABLED,
"Enables scaling/spacing for icon labels to make more characters visible");
@@ -415,11 +411,15 @@
// TODO(Block 31)
public static final BooleanFlag ENABLE_SPLIT_LAUNCH_DATA_REFACTOR = getDebugFlag(279494325,
- "ENABLE_SPLIT_LAUNCH_DATA_REFACTOR", DISABLED,
+ "ENABLE_SPLIT_LAUNCH_DATA_REFACTOR", ENABLED,
"Use refactored split launching code path");
// TODO(Block 32): Empty block
+ public static final BooleanFlag ENABLE_RESPONSIVE_WORKSPACE = getDebugFlag(241386436,
+ "ENABLE_RESPONSIVE_WORKSPACE", DISABLED,
+ "Enables new workspace grid calculations method.");
+
public static class BooleanFlag {
private final boolean mCurrentValue;
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 48239ae..2c1100f 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -74,7 +74,6 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemFactory;
import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.MultiTranslateDelegate;
import com.android.launcher3.util.Thunk;
diff --git a/src/com/android/launcher3/graphics/SysUiScrim.java b/src/com/android/launcher3/graphics/SysUiScrim.java
index be995bc..21ebc98 100644
--- a/src/com/android/launcher3/graphics/SysUiScrim.java
+++ b/src/com/android/launcher3/graphics/SysUiScrim.java
@@ -36,13 +36,10 @@
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.testing.shared.ResourceUtils;
-import com.android.launcher3.util.DynamicResource;
import com.android.launcher3.util.ScreenOnTracker;
import com.android.launcher3.util.ScreenOnTracker.ScreenOnListener;
import com.android.launcher3.util.Themes;
-import com.android.systemui.plugins.ResourceProvider;
/**
* View scrim which draws behind hotseat and workspace
@@ -100,10 +97,8 @@
private static final int ALPHA_MASK_BITMAP_DP = 200;
private static final int ALPHA_MASK_WIDTH_DP = 2;
- private boolean mDrawTopScrim, mDrawBottomScrim, mDrawWallpaperScrim;
+ private boolean mDrawTopScrim, mDrawBottomScrim;
- private final RectF mWallpaperScrimRect = new RectF();
- private final Paint mWallpaperScrimPaint = new Paint();
private final RectF mFinalMaskRect = new RectF();
private final Paint mBottomMaskPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
private final Bitmap mBottomMask;
@@ -118,7 +113,6 @@
private boolean mAnimateScrimOnNextDraw = false;
private float mSysUiAnimMultiplier = 1;
- private int mWallpaperScrimMaxAlpha;
public SysUiScrim(View view) {
mRoot = view;
@@ -135,14 +129,6 @@
mHideSysUiScrim = true;
}
- mDrawWallpaperScrim = FeatureFlags.ENABLE_WALLPAPER_SCRIM.get()
- && !Themes.getAttrBoolean(view.getContext(), R.attr.isMainColorDark)
- && !Themes.getAttrBoolean(view.getContext(), R.attr.isWorkspaceDarkText);
- ResourceProvider rp = DynamicResource.provider(view.getContext());
- int wallpaperScrimColor = rp.getColor(R.color.wallpaper_scrim_color);
- mWallpaperScrimMaxAlpha = Color.alpha(wallpaperScrimColor);
- mWallpaperScrimPaint.setColor(wallpaperScrimColor);
-
view.addOnAttachStateChangeListener(this);
}
@@ -167,9 +153,6 @@
mAnimateScrimOnNextDraw = false;
}
- if (mDrawWallpaperScrim) {
- canvas.drawRect(mWallpaperScrimRect, mWallpaperScrimPaint);
- }
if (mDrawTopScrim) {
mTopScrim.draw(canvas);
}
@@ -228,7 +211,6 @@
mTopScrim.setBounds(0, 0, w, h);
mFinalMaskRect.set(0, h - mMaskHeight, w, h);
}
- mWallpaperScrimRect.set(0, 0, w, h);
}
private void setSysUiProgress(float progress) {
@@ -251,7 +233,6 @@
if (mTopScrim != null) {
mTopScrim.setAlpha(Math.round(255 * factor));
}
- mWallpaperScrimPaint.setAlpha(Math.round(mWallpaperScrimMaxAlpha * factor));
}
private Bitmap createDitheredAlphaMask() {
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 8197b73..15f3538 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -891,6 +891,12 @@
return this;
}
+
+ /** Sets cardinality of the event. */
+ default StatsLatencyLogger withCardinality(int cardinality) {
+ return this;
+ }
+
/**
* Sets packageId of log message.
*/
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index bc492fd..8274789 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -241,8 +241,8 @@
deepShortcutCount,
popupDataProvider.getNotificationKeysForItem(item),
systemShortcuts);
- launcher.tryClearAccessibilityFocus(icon);
}
+ launcher.tryClearAccessibilityFocus(icon);
launcher.refreshAndBindWidgetsForPackageUser(PackageUserKey.fromItemInfo(item));
container.requestFocus();
return container;
diff --git a/src/com/android/launcher3/views/ComposeInitializer.java b/src/com/android/launcher3/views/ComposeInitializer.java
new file mode 100644
index 0000000..0929885
--- /dev/null
+++ b/src/com/android/launcher3/views/ComposeInitializer.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.views;
+
+import android.os.Build;
+import android.view.View;
+import android.view.ViewParent;
+import android.view.ViewTreeObserver;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
+import androidx.lifecycle.ViewTreeLifecycleOwner;
+import androidx.savedstate.SavedStateRegistry;
+import androidx.savedstate.SavedStateRegistryController;
+import androidx.savedstate.SavedStateRegistryOwner;
+import androidx.savedstate.ViewTreeSavedStateRegistryOwner;
+
+import com.android.launcher3.Utilities;
+
+/**
+ * An initializer to use Compose for classes implementing {@code ActivityContext}. This allows
+ * adding ComposeView to ViewTree outside a {@link androidx.activity.ComponentActivity}.
+ */
+public final class ComposeInitializer {
+ /**
+ * Performs the initialization to use Compose in the ViewTree of {@code target}.
+ */
+ public static void initCompose(ActivityContext target) {
+ getContentChild(target).addOnAttachStateChangeListener(
+ new View.OnAttachStateChangeListener() {
+
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ ComposeInitializer.onAttachedToWindow(v);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ ComposeInitializer.onDetachedFromWindow(v);
+ }
+ });
+ }
+
+ /**
+ * Find the "content child" for {@code target}.
+ *
+ * @see "WindowRecomposer.android.kt: [View.contentChild]"
+ */
+ private static View getContentChild(ActivityContext target) {
+ View self = target.getDragLayer();
+ ViewParent parent = self.getParent();
+ while (parent instanceof View parentView) {
+ if (parentView.getId() == android.R.id.content) return self;
+ self = parentView;
+ parent = self.getParent();
+ }
+ return self;
+ }
+
+ /**
+ * Function to be called on your window root view's [View.onAttachedToWindow] function.
+ */
+ private static void onAttachedToWindow(View root) {
+ if (ViewTreeLifecycleOwner.get(root) != null) {
+ throw new IllegalStateException(
+ "View " + root + " already has a LifecycleOwner");
+ }
+
+ ViewParent parent = root.getParent();
+ if (parent instanceof View && ((View) parent).getId() != android.R.id.content) {
+ throw new IllegalStateException(
+ "ComposeInitializer.onContentChildAttachedToWindow(View) must be called on "
+ + "the content child. Outside of activities and dialogs, this is "
+ + "usually the top-most View of a window.");
+ }
+
+ // The lifecycle owner, which is STARTED when [root] is visible and RESUMED when [root]
+ // is both visible and focused.
+ ViewLifecycleOwner lifecycleOwner = new ViewLifecycleOwner(root);
+
+ // We must call [ViewLifecycleOwner.onCreate] after creating the
+ // [SavedStateRegistryOwner] because `onCreate` might move the lifecycle state to STARTED
+ // which will make [SavedStateRegistryController.performRestore] throw.
+ lifecycleOwner.onCreate();
+
+ // Set the owners on the root. They will be reused by any ComposeView inside the root
+ // hierarchy.
+ ViewTreeLifecycleOwner.set(root, lifecycleOwner);
+ ViewTreeSavedStateRegistryOwner.set(root, lifecycleOwner);
+ }
+
+ /**
+ * Function to be called on your window root view's [View.onDetachedFromWindow] function.
+ */
+ private static void onDetachedFromWindow(View root) {
+ final LifecycleOwner lifecycleOwner = ViewTreeLifecycleOwner.get(root);
+ if (lifecycleOwner != null) {
+ ((ViewLifecycleOwner) lifecycleOwner).onDestroy();
+ }
+ ViewTreeLifecycleOwner.set(root, null);
+ ViewTreeSavedStateRegistryOwner.set(root, null);
+ }
+
+ /**
+ * A [LifecycleOwner] for a [View] that updates lifecycle state based on window state.
+ *
+ * Also a trivial implementation of [SavedStateRegistryOwner] that does not do any save or
+ * restore. This works for processes similar to the SystemUI process, which is always running
+ * and top-level windows using this initialization are created once, when the process is
+ * started.
+ *
+ * The implementation requires the caller to call [onCreate] and [onDestroy] when the view is
+ * attached to or detached from a view hierarchy. After [onCreate] and before [onDestroy] is
+ * called, the implementation monitors window state in the following way
+ * * If the window is not visible, we are in the [Lifecycle.State.CREATED] state
+ * * If the window is visible but not focused, we are in the [Lifecycle.State.STARTED] state
+ * * If the window is visible and focused, we are in the [Lifecycle.State.RESUMED] state
+ *
+ * Or in table format:
+ * ```
+ * ┌───────────────┬───────────────────┬──────────────┬─────────────────┐
+ * │ View attached │ Window Visibility │ Window Focus │ Lifecycle State │
+ * ├───────────────┼───────────────────┴──────────────┼─────────────────┤
+ * │ Not attached │ Any │ N/A │
+ * ├───────────────┼───────────────────┬──────────────┼─────────────────┤
+ * │ │ Not visible │ Any │ CREATED │
+ * │ ├───────────────────┼──────────────┼─────────────────┤
+ * │ Attached │ │ No focus │ STARTED │
+ * │ │ Visible ├──────────────┼─────────────────┤
+ * │ │ │ Has focus │ RESUMED │
+ * └───────────────┴───────────────────┴──────────────┴─────────────────┘
+ * ```
+ */
+ private static class ViewLifecycleOwner implements SavedStateRegistryOwner {
+ private final ViewTreeObserver.OnWindowFocusChangeListener mWindowFocusListener =
+ hasFocus -> updateState();
+ private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
+
+ private final SavedStateRegistryController mSavedStateRegistryController =
+ SavedStateRegistryController.create(this);
+
+ private final View mView;
+ private final Api34Impl mApi34Impl;
+
+ ViewLifecycleOwner(View view) {
+ mView = view;
+ if (Utilities.ATLEAST_U) {
+ mApi34Impl = new Api34Impl();
+ } else {
+ mApi34Impl = null;
+ }
+
+ mSavedStateRegistryController.performRestore(null);
+ }
+
+ @NonNull
+ @Override
+ public Lifecycle getLifecycle() {
+ return mLifecycleRegistry;
+ }
+
+ @NonNull
+ @Override
+ public SavedStateRegistry getSavedStateRegistry() {
+ return mSavedStateRegistryController.getSavedStateRegistry();
+ }
+
+ void onCreate() {
+ mLifecycleRegistry.setCurrentState(Lifecycle.State.CREATED);
+ if (Utilities.ATLEAST_U) {
+ mApi34Impl.addOnWindowVisibilityChangeListener();
+ }
+ mView.getViewTreeObserver().addOnWindowFocusChangeListener(
+ mWindowFocusListener);
+ updateState();
+ }
+
+ void onDestroy() {
+ if (Utilities.ATLEAST_U) {
+ mApi34Impl.removeOnWindowVisibilityChangeListener();
+ }
+ mView.getViewTreeObserver().removeOnWindowFocusChangeListener(
+ mWindowFocusListener);
+ mLifecycleRegistry.setCurrentState(Lifecycle.State.DESTROYED);
+ }
+
+ private void updateState() {
+ Lifecycle.State state =
+ mView.getWindowVisibility() != View.VISIBLE ? Lifecycle.State.CREATED
+ : (!mView.hasWindowFocus() ? Lifecycle.State.STARTED
+ : Lifecycle.State.RESUMED);
+ mLifecycleRegistry.setCurrentState(state);
+ }
+
+ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ private class Api34Impl {
+ private final ViewTreeObserver.OnWindowVisibilityChangeListener
+ mWindowVisibilityListener =
+ visibility -> updateState();
+
+ void addOnWindowVisibilityChangeListener() {
+ mView.getViewTreeObserver().addOnWindowVisibilityChangeListener(
+ mWindowVisibilityListener);
+ }
+
+ void removeOnWindowVisibilityChangeListener() {
+ mView.getViewTreeObserver().removeOnWindowVisibilityChangeListener(
+ mWindowVisibilityListener);
+ }
+ }
+ }
+}
diff --git a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
index 0fe8bee..01f494b 100644
--- a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
@@ -50,7 +50,7 @@
private lateinit var originalWindowManagerProxy: WindowManagerProxy
@Before
- fun setUp() {
+ open fun setUp() {
val appContext: Context = ApplicationProvider.getApplicationContext()
originalWindowManagerProxy = WindowManagerProxy.INSTANCE.get(appContext)
originalDisplayController = DisplayController.INSTANCE.get(appContext)
@@ -59,7 +59,7 @@
}
@After
- fun tearDown() {
+ open fun tearDown() {
WindowManagerProxy.INSTANCE.initializeForTesting(originalWindowManagerProxy)
DisplayController.INSTANCE.initializeForTesting(originalDisplayController)
}
diff --git a/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt b/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
index 13db6c7..a81413e 100644
--- a/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
+++ b/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
@@ -58,6 +58,7 @@
"\tmInsets.right: 0.0px (0.0dp)\n" +
"\tmInsets.bottom: 126.0px (48.0dp)\n" +
"\taspectRatio:2.2222223\n" +
+ "\tisResponsiveGrid:false\n" +
"\tisScalableGrid:false\n" +
"\tinv.numRows: 5\n" +
"\tinv.numColumns: 5\n" +
@@ -193,6 +194,7 @@
"\tmInsets.right: 0.0px (0.0dp)\n" +
"\tmInsets.bottom: 63.0px (24.0dp)\n" +
"\taspectRatio:2.2222223\n" +
+ "\tisResponsiveGrid:false\n" +
"\tisScalableGrid:false\n" +
"\tinv.numRows: 5\n" +
"\tinv.numColumns: 5\n" +
@@ -328,6 +330,7 @@
"\tmInsets.right: 126.0px (48.0dp)\n" +
"\tmInsets.bottom: 0.0px (0.0dp)\n" +
"\taspectRatio:2.2222223\n" +
+ "\tisResponsiveGrid:false\n" +
"\tisScalableGrid:false\n" +
"\tinv.numRows: 5\n" +
"\tinv.numColumns: 5\n" +
@@ -463,6 +466,7 @@
"\tmInsets.right: 0.0px (0.0dp)\n" +
"\tmInsets.bottom: 63.0px (24.0dp)\n" +
"\taspectRatio:2.2222223\n" +
+ "\tisResponsiveGrid:false\n" +
"\tisScalableGrid:false\n" +
"\tinv.numRows: 5\n" +
"\tinv.numColumns: 5\n" +
@@ -599,6 +603,7 @@
"\tmInsets.right: 0.0px (0.0dp)\n" +
"\tmInsets.bottom: 0.0px (0.0dp)\n" +
"\taspectRatio:1.6\n" +
+ "\tisResponsiveGrid:false\n" +
"\tisScalableGrid:true\n" +
"\tinv.numRows: 5\n" +
"\tinv.numColumns: 6\n" +
@@ -735,6 +740,7 @@
"\tmInsets.right: 0.0px (0.0dp)\n" +
"\tmInsets.bottom: 0.0px (0.0dp)\n" +
"\taspectRatio:1.6\n" +
+ "\tisResponsiveGrid:false\n" +
"\tisScalableGrid:true\n" +
"\tinv.numRows: 5\n" +
"\tinv.numColumns: 6\n" +
@@ -871,6 +877,7 @@
"\tmInsets.right: 0.0px (0.0dp)\n" +
"\tmInsets.bottom: 0.0px (0.0dp)\n" +
"\taspectRatio:1.6\n" +
+ "\tisResponsiveGrid:false\n" +
"\tisScalableGrid:true\n" +
"\tinv.numRows: 5\n" +
"\tinv.numColumns: 6\n" +
@@ -1007,6 +1014,7 @@
"\tmInsets.right: 0.0px (0.0dp)\n" +
"\tmInsets.bottom: 0.0px (0.0dp)\n" +
"\taspectRatio:1.6\n" +
+ "\tisResponsiveGrid:false\n" +
"\tisScalableGrid:true\n" +
"\tinv.numRows: 5\n" +
"\tinv.numColumns: 6\n" +
@@ -1148,6 +1156,7 @@
"\tmInsets.right: 0.0px (0.0dp)\n" +
"\tmInsets.bottom: 0.0px (0.0dp)\n" +
"\taspectRatio:1.2\n" +
+ "\tisResponsiveGrid:false\n" +
"\tisScalableGrid:false\n" +
"\tinv.numRows: 4\n" +
"\tinv.numColumns: 4\n" +
@@ -1288,6 +1297,7 @@
"\tmInsets.right: 0.0px (0.0dp)\n" +
"\tmInsets.bottom: 0.0px (0.0dp)\n" +
"\taspectRatio:1.2\n" +
+ "\tisResponsiveGrid:false\n" +
"\tisScalableGrid:false\n" +
"\tinv.numRows: 4\n" +
"\tinv.numColumns: 4\n" +
@@ -1428,6 +1438,7 @@
"\tmInsets.right: 0.0px (0.0dp)\n" +
"\tmInsets.bottom: 0.0px (0.0dp)\n" +
"\taspectRatio:1.2\n" +
+ "\tisResponsiveGrid:false\n" +
"\tisScalableGrid:false\n" +
"\tinv.numRows: 4\n" +
"\tinv.numColumns: 4\n" +
@@ -1564,6 +1575,7 @@
"\tmInsets.right: 0.0px (0.0dp)\n" +
"\tmInsets.bottom: 0.0px (0.0dp)\n" +
"\taspectRatio:1.2\n" +
+ "\tisResponsiveGrid:false\n" +
"\tisScalableGrid:false\n" +
"\tinv.numRows: 4\n" +
"\tinv.numColumns: 4\n" +
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index f52b82d..a59eff7 100644
--- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -223,6 +223,9 @@
new Point(taskbarUnstashArea.x, taskbarUnstashArea.y), null);
mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
+
+ mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_EXIT,
+ new Point(taskbarUnstashArea.x, taskbarUnstashArea.y), null);
}
}