Merge "Fix All Apps Icons Count estimation" into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 9221f6b..874f862 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -34,3 +34,10 @@
description: "Enables new workspace grid calculations method."
bug: "241386436"
}
+
+flag {
+ name: "enable_overview_icon_menu"
+ namespace: "launcher"
+ description: "Enable updated overview icon and menu within task."
+ bug: "257950105"
+}
diff --git a/quickstep/res/drawable/ic_chevron_down.xml b/quickstep/res/drawable/ic_chevron_down.xml
new file mode 100644
index 0000000..77a8295
--- /dev/null
+++ b/quickstep/res/drawable/ic_chevron_down.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <target android:name="scaleGroup">
+ <aapt:attr name="android:animation">
+ <objectAnimator
+ android:duration="150"
+ android:propertyName="scaleX"
+ android:valueFrom="1"
+ android:valueTo="-1" />
+ </aapt:attr>
+ </target>
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="48dp"
+ android:height="48dp"
+ android:autoMirrored="true"
+ android:tint="?androidprv:attr/materialColorOnSurface"
+ android:viewportHeight="48"
+ android:viewportWidth="48">
+ <group
+ android:name="scaleGroup"
+ android:pivotX="24"
+ android:pivotY="24"
+ android:rotation="90">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.75,36 L16.6,33.85 26.5,23.95 16.6,14.05 18.75,11.9 30.8,23.95Z" />
+ </group>
+ </vector>
+ </aapt:attr>
+</animated-vector>
diff --git a/quickstep/res/layout/icon_app_chip_view.xml b/quickstep/res/layout/icon_app_chip_view.xml
new file mode 100644
index 0000000..87519a0
--- /dev/null
+++ b/quickstep/res/layout/icon_app_chip_view.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<com.android.quickstep.views.IconAppChipView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:focusable="false"
+ android:importantForAccessibility="no"
+ android:autoMirrored="true"
+ android:elevation="@dimen/task_thumbnail_icon_menu_elevation" >
+
+ <ImageView
+ android:id="@+id/icon_view_background"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@drawable/icon_menu_background"
+ android:importantForAccessibility="no" />
+
+ <com.android.quickstep.views.IconView
+ android:id="@+id/icon_view"
+ android:layout_width="@dimen/task_thumbnail_icon_size"
+ android:layout_height="@dimen/task_thumbnail_icon_size"
+ android:focusable="false"
+ android:importantForAccessibility="no" />
+
+ <TextView
+ android:id="@+id/icon_text"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:maxLines="1"
+ android:textAlignment="viewStart"
+ android:textColor="?androidprv:attr/materialColorOnSurface"
+ android:textSize="16sp"
+ android:importantForAccessibility="no" />
+
+ <ImageView
+ android:id="@+id/icon_arrow"
+ android:layout_width="@dimen/task_thumbnail_icon_menu_arrow_size"
+ android:layout_height="match_parent"
+ android:background="@drawable/icon_menu_arrow_background"
+ android:src="@drawable/ic_chevron_down"
+ android:importantForAccessibility="no" />
+</com.android.quickstep.views.IconAppChipView>
\ No newline at end of file
diff --git a/quickstep/res/layout/icon_view.xml b/quickstep/res/layout/icon_view.xml
new file mode 100644
index 0000000..a33066f
--- /dev/null
+++ b/quickstep/res/layout/icon_view.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<com.android.quickstep.views.IconView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
\ No newline at end of file
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 29c9992..823a86e 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -44,10 +44,9 @@
android:importantForAccessibility="no"
android:src="@drawable/ic_select_windows" />
- <com.android.quickstep.views.IconView
+ <ViewStub
android:id="@+id/icon"
- android:layout_width="@dimen/task_thumbnail_icon_size"
- android:layout_height="@dimen/task_thumbnail_icon_size"
- android:focusable="false"
- android:importantForAccessibility="no"/>
+ android:inflatedId="@id/icon"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
</com.android.quickstep.views.TaskView>
\ No newline at end of file
diff --git a/quickstep/res/layout/task_desktop.xml b/quickstep/res/layout/task_desktop.xml
index 06f4d06..fe12bd3 100644
--- a/quickstep/res/layout/task_desktop.xml
+++ b/quickstep/res/layout/task_desktop.xml
@@ -45,11 +45,10 @@
android:layout_height="wrap_content"
android:visibility="gone" />
- <com.android.quickstep.views.IconView
+ <ViewStub
android:id="@+id/icon"
- android:layout_width="@dimen/task_thumbnail_icon_size"
- android:layout_height="@dimen/task_thumbnail_icon_size"
- android:focusable="false"
- android:importantForAccessibility="no" />
+ android:inflatedId="@id/icon"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
</com.android.quickstep.views.DesktopTaskView>
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index 75ff626..d20afd3 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -66,17 +66,15 @@
android:importantForAccessibility="no"
android:src="@drawable/ic_select_windows" />
- <com.android.quickstep.views.IconView
+ <ViewStub
android:id="@+id/icon"
- android:layout_width="@dimen/task_thumbnail_icon_size"
- android:layout_height="@dimen/task_thumbnail_icon_size"
- android:focusable="false"
- android:importantForAccessibility="no"/>
+ android:inflatedId="@id/icon"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
- <com.android.quickstep.views.IconView
+ <ViewStub
android:id="@+id/bottomRight_icon"
- android:layout_width="@dimen/task_thumbnail_icon_size"
- android:layout_height="@dimen/task_thumbnail_icon_size"
- android:focusable="false"
- android:importantForAccessibility="no"/>
+ android:inflatedId="@id/bottomRight_icon"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
</com.android.quickstep.views.GroupedTaskView>
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index aeb453c..aaa699b 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -44,6 +44,33 @@
<dimen name="overview_task_margin">16dp</dimen>
<!-- The horizontal space between tasks -->
<dimen name="overview_page_spacing">16dp</dimen>
+ <!-- The width of the thumbnail icon menu -->
+ <dimen name="task_thumbnail_icon_menu_min_width">132dp</dimen>
+ <!-- The width of the icon menu text -->
+ <dimen name="task_thumbnail_icon_menu_text_width">62dp</dimen>
+ <!-- The max width of the icon menu text -->
+ <dimen name="task_thumbnail_icon_menu_text_max_width">138dp</dimen>
+ <!-- The max width of the thumbnail icon menu -->
+ <dimen name="task_thumbnail_icon_menu_max_width">216dp</dimen>
+ <!-- The height of the thumbnail icon menu -->
+ <dimen name="task_thumbnail_icon_menu_min_height">36dp</dimen>
+ <!-- The max height of the thumbnail icon menu -->
+ <dimen name="task_thumbnail_icon_menu_max_height">52dp</dimen>
+ <!-- The size of the icon menu arrow -->
+ <dimen name="task_thumbnail_icon_menu_arrow_size">32dp</dimen>
+ <!-- The size of the icon menu arrow drawable -->
+ <dimen name="task_thumbnail_icon_menu_arrow_drawable_size">16dp</dimen>
+ <!-- The margin around the task icon menu -->
+ <dimen name="task_thumbnail_icon_menu_margin">12dp</dimen>
+ <!-- The space around the task icon arrow within the icon menu -->
+ <dimen name="task_thumbnail_icon_menu_arrow_margin">6dp</dimen>
+ <!-- The max space around the task icon within the icon menu -->
+ <dimen name="task_thumbnail_icon_menu_touch_max_margin">8dp</dimen>
+ <!-- The icon size for the icon menu -->
+ <dimen name="task_thumbnail_icon_menu_drawable_size">24dp</dimen>
+ <!-- The size of the icon menu's icon touch target -->
+ <dimen name="task_thumbnail_icon_menu_drawable_touch_size">36dp</dimen>
+ <dimen name="task_thumbnail_icon_menu_elevation">14dp</dimen>
<dimen name="task_icon_cache_default_icon_size">72dp</dimen>
<item name="overview_modal_max_scale" format="float" type="dimen">1.1</item>
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index e6dfe0f..1c7d7e0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -337,7 +337,7 @@
}
public boolean isBubbleBarEnabled() {
- return BubbleBarController.BUBBLE_BAR_ENABLED;
+ return BubbleBarController.isBubbleBarEnabled();
}
/** Whether the bubble bar has any bubbles. */
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index df6626a..4b16019 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -191,6 +191,7 @@
private MultiValueAlpha mBackButtonAlpha;
private MultiValueAlpha mHomeButtonAlpha;
private FloatingRotationButton mFloatingRotationButton;
+ private ImageView mImeSwitcherButton;
// Variables for moving nav buttons to a separate window above IME
private boolean mAreNavButtonsInSeparateWindow = false;
@@ -237,10 +238,10 @@
InputMethodService.canImeRenderGesturalNavButtons() && mContext.imeDrawsImeNavBar();
if (!mIsImeRenderingNavButtons) {
// IME switcher
- View imeSwitcherButton = addButton(R.drawable.ic_ime_switcher, BUTTON_IME_SWITCH,
+ mImeSwitcherButton = addButton(R.drawable.ic_ime_switcher, BUTTON_IME_SWITCH,
isThreeButtonNav ? mStartContextualContainer : mEndContextualContainer,
mControllers.navButtonController, R.id.ime_switcher);
- mPropertyHolders.add(new StatePropertyHolder(imeSwitcherButton,
+ mPropertyHolders.add(new StatePropertyHolder(mImeSwitcherButton,
flags -> ((flags & FLAG_SWITCHER_SHOWING) != 0)
&& ((flags & FLAG_ROTATION_BUTTON_VISIBLE) == 0)));
}
@@ -736,7 +737,9 @@
if (TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW) {
NavButtonLayoutter navButtonLayoutter =
NavButtonLayoutFactory.Companion.getUiLayoutter(
- dp, mNavButtonsView, res, isInKidsMode, isInSetup, isThreeButtonNav,
+ dp, mNavButtonsView, mImeSwitcherButton,
+ mControllers.rotationButtonController.getRotationButton(),
+ mA11yButton, res, isInKidsMode, isInSetup, isThreeButtonNav,
TaskbarManager.isPhoneMode(dp),
mWindowManagerProxy.getRotation(mContext));
navButtonLayoutter.layoutButtons(dp, isContextualButtonShowing());
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 0aa02f2..9f8f82a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -218,7 +218,8 @@
// If Bubble bar is present, TaskbarControllers depends on it so build it first.
Optional<BubbleControllers> bubbleControllersOptional = Optional.empty();
- if (BubbleBarController.BUBBLE_BAR_ENABLED && bubbleBarView != null) {
+ BubbleBarController.onTaskbarRecreated();
+ if (BubbleBarController.isBubbleBarEnabled() && bubbleBarView != null) {
bubbleControllersOptional = Optional.of(new BubbleControllers(
new BubbleBarController(this, bubbleBarView),
new BubbleBarViewController(this, bubbleBarView),
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
index a0ce976..712374d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
@@ -17,7 +17,7 @@
import static android.view.View.VISIBLE;
-import static com.android.launcher3.taskbar.bubbles.BubbleBarController.BUBBLE_BAR_ENABLED;
+import static com.android.launcher3.taskbar.bubbles.BubbleBarController.isBubbleBarEnabled;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED;
import static com.android.wm.shell.common.bubbles.BubbleConstants.BUBBLE_EXPANDED_SCRIM_ALPHA;
@@ -83,7 +83,7 @@
* Updates the scrim state based on the flags.
*/
public void updateStateForSysuiFlags(int stateFlags, boolean skipAnim) {
- if (BUBBLE_BAR_ENABLED && DisplayController.isTransientTaskbar(mActivity)) {
+ if (isBubbleBarEnabled() && DisplayController.isTransientTaskbar(mActivity)) {
// These scrims aren't used if bubble bar & transient taskbar are active.
return;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index bd11efd..3fb7247 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -85,17 +85,31 @@
* information to render each of the bubbles & dispatches changes to
* {@link BubbleBarViewController} which will then update {@link BubbleBarView} as needed.
*
- * For details around the behavior of the bubble bar, see {@link BubbleBarView}.
+ * <p>For details around the behavior of the bubble bar, see {@link BubbleBarView}.
*/
public class BubbleBarController extends IBubblesListener.Stub {
private static final String TAG = BubbleBarController.class.getSimpleName();
private static final boolean DEBUG = false;
- // Whether bubbles are showing in the bubble bar from launcher
- public static final boolean BUBBLE_BAR_ENABLED =
+ /**
+ * Determines whether bubbles can be shown in the bubble bar. This value updates when the
+ * taskbar is recreated.
+ *
+ * @see #onTaskbarRecreated()
+ */
+ private static boolean sBubbleBarEnabled =
SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false);
+ /** Whether showing bubbles in the launcher bubble bar is enabled. */
+ public static boolean isBubbleBarEnabled() {
+ return sBubbleBarEnabled;
+ }
+
+ /** Re-reads the value of the flag from SystemProperties when taskbar is recreated. */
+ public static void onTaskbarRecreated() {
+ sBubbleBarEnabled = SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false);
+ }
private static final int MASK_HIDE_BUBBLE_BAR = SYSUI_STATE_BOUNCER_SHOWING
| SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
| SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED
@@ -167,7 +181,7 @@
mSystemUiProxy = SystemUiProxy.INSTANCE.get(context);
- if (BUBBLE_BAR_ENABLED) {
+ if (sBubbleBarEnabled) {
mSystemUiProxy.setBubblesListener(this);
}
mMainExecutor = MAIN_EXECUTOR;
@@ -191,9 +205,9 @@
bubbleControllers.runAfterInit(() -> {
mBubbleBarViewController.setHiddenForBubbles(
- !BUBBLE_BAR_ENABLED || mBubbles.isEmpty());
+ !sBubbleBarEnabled || mBubbles.isEmpty());
mBubbleStashedHandleViewController.setHiddenForBubbles(
- !BUBBLE_BAR_ENABLED || mBubbles.isEmpty());
+ !sBubbleBarEnabled || mBubbles.isEmpty());
mBubbleBarViewController.setUpdateSelectedBubbleAfterCollapse(
key -> setSelectedBubble(mBubbles.get(key)));
});
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
index b682081..9758d44 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
@@ -18,12 +18,15 @@
import android.content.res.Resources
import android.graphics.drawable.RotateDrawable
+import android.view.Gravity
import android.view.ViewGroup
+import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter
+import com.android.systemui.shared.rotation.RotationButton
/**
* Meant to be a simple container for data subclasses will need
@@ -37,10 +40,13 @@
* @property startContextualContainer ViewGroup that holds the start contextual button (ex, A11y).
*/
abstract class AbstractNavButtonLayoutter(
- val resources: Resources,
- val navButtonContainer: LinearLayout,
- protected val endContextualContainer: ViewGroup,
- protected val startContextualContainer: ViewGroup
+ val resources: Resources,
+ val navButtonContainer: LinearLayout,
+ protected val endContextualContainer: ViewGroup,
+ protected val startContextualContainer: ViewGroup,
+ protected val imeSwitcher: ImageView?,
+ protected val rotationButton: RotationButton?,
+ protected val a11yButton: ImageView
) : NavButtonLayoutter {
protected val homeButton: ImageView? = navButtonContainer.findViewById(R.id.home)
protected val recentsButton: ImageView? = navButtonContainer.findViewById(R.id.recent_apps)
@@ -56,4 +62,11 @@
backButton.setImageDrawable(rotateDrawable)
}
}
+
+ fun getParamsToCenterView(): FrameLayout.LayoutParams {
+ val params = FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+ params.gravity = Gravity.CENTER
+ return params;
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
index 4a53c0c..f254ee8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
@@ -26,18 +26,25 @@
import android.widget.LinearLayout
import com.android.launcher3.DeviceProfile
import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.*
+import com.android.systemui.shared.rotation.RotationButton
class KidsNavLayoutter(
- resources: Resources,
- navBarContainer: LinearLayout,
- endContextualContainer: ViewGroup,
- startContextualContainer: ViewGroup
+ resources: Resources,
+ navBarContainer: LinearLayout,
+ endContextualContainer: ViewGroup,
+ startContextualContainer: ViewGroup,
+ imeSwitcher: ImageView?,
+ rotationButton: RotationButton?,
+ a11yButton: ImageView
) :
AbstractNavButtonLayoutter(
- resources,
- navBarContainer,
- endContextualContainer,
- startContextualContainer
+ resources,
+ navBarContainer,
+ endContextualContainer,
+ startContextualContainer,
+ imeSwitcher,
+ rotationButton,
+ a11yButton
) {
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
@@ -89,5 +96,28 @@
navButtonContainer.requestLayout()
homeButton.onLongClickListener = null
+
+ endContextualContainer.removeAllViews()
+ startContextualContainer.removeAllViews()
+
+ val endContextualContainerParams = FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)
+ endContextualContainerParams.gravity = Gravity.END or Gravity.CENTER_VERTICAL
+ endContextualContainer.layoutParams = endContextualContainerParams
+
+ val startContextualContainerParams = FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)
+ startContextualContainerParams.gravity = Gravity.START or Gravity.CENTER_VERTICAL
+ startContextualContainer.layoutParams = startContextualContainerParams
+
+ if (imeSwitcher != null) {
+ startContextualContainer.addView(imeSwitcher)
+ imeSwitcher.layoutParams = getParamsToCenterView()
+ }
+ endContextualContainer.addView(a11yButton)
+ if (rotationButton != null) {
+ endContextualContainer.addView(rotationButton.currentView)
+ rotationButton.currentView.layoutParams = getParamsToCenterView()
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
index 931f692..7db1a37 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
@@ -21,11 +21,13 @@
import android.view.Surface.Rotation
import android.view.ViewGroup
import android.widget.FrameLayout
+import android.widget.ImageView
import android.widget.LinearLayout
import com.android.launcher3.DeviceProfile
import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.*
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.Companion
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter
+import com.android.systemui.shared.rotation.RotationButton
/**
* Select the correct layout for nav buttons
@@ -52,14 +54,17 @@
* @param isThreeButtonNav are no-ops when taskbar is present/showing
*/
fun getUiLayoutter(
- deviceProfile: DeviceProfile,
- navButtonsView: FrameLayout,
- resources: Resources,
- isKidsMode: Boolean,
- isInSetup: Boolean,
- isThreeButtonNav: Boolean,
- phoneMode: Boolean,
- @Rotation surfaceRotation: Int
+ deviceProfile: DeviceProfile,
+ navButtonsView: FrameLayout,
+ imeSwitcher: ImageView?,
+ rotationButton: RotationButton?,
+ a11yButton: ImageView,
+ resources: Resources,
+ isKidsMode: Boolean,
+ isInSetup: Boolean,
+ isThreeButtonNav: Boolean,
+ phoneMode: Boolean,
+ @Rotation surfaceRotation: Int
): NavButtonLayoutter {
val navButtonContainer =
navButtonsView.requireViewById<LinearLayout>(ID_END_NAV_BUTTONS)
@@ -73,24 +78,33 @@
isPhoneNavMode -> {
if (!deviceProfile.isLandscape) {
PhonePortraitNavLayoutter(
- resources,
- navButtonContainer,
- endContextualContainer,
- startContextualContainer
+ resources,
+ navButtonContainer,
+ endContextualContainer,
+ startContextualContainer,
+ imeSwitcher,
+ rotationButton,
+ a11yButton
)
} else if (surfaceRotation == ROTATION_90) {
PhoneLandscapeNavLayoutter(
- resources,
- navButtonContainer,
- endContextualContainer,
- startContextualContainer
+ resources,
+ navButtonContainer,
+ endContextualContainer,
+ startContextualContainer,
+ imeSwitcher,
+ rotationButton,
+ a11yButton
)
} else {
PhoneSeascapeNavLayoutter(
resources,
navButtonContainer,
endContextualContainer,
- startContextualContainer
+ startContextualContainer,
+ imeSwitcher,
+ rotationButton,
+ a11yButton
)
}
}
@@ -99,33 +113,45 @@
resources,
navButtonContainer,
endContextualContainer,
- startContextualContainer
+ startContextualContainer,
+ imeSwitcher,
+ rotationButton,
+ a11yButton
)
}
deviceProfile.isTaskbarPresent -> {
return when {
isInSetup -> {
SetupNavLayoutter(
- resources,
- navButtonContainer,
- endContextualContainer,
- startContextualContainer
+ resources,
+ navButtonContainer,
+ endContextualContainer,
+ startContextualContainer,
+ imeSwitcher,
+ rotationButton,
+ a11yButton
)
}
isKidsMode -> {
KidsNavLayoutter(
- resources,
- navButtonContainer,
- endContextualContainer,
- startContextualContainer
+ resources,
+ navButtonContainer,
+ endContextualContainer,
+ startContextualContainer,
+ imeSwitcher,
+ rotationButton,
+ a11yButton
)
}
else ->
TaskbarNavLayoutter(
- resources,
- navButtonContainer,
- endContextualContainer,
- startContextualContainer
+ resources,
+ navButtonContainer,
+ endContextualContainer,
+ startContextualContainer,
+ imeSwitcher,
+ rotationButton,
+ a11yButton
)
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneGestureLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneGestureLayoutter.kt
index 8525c6c..c1dae40 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneGestureLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneGestureLayoutter.kt
@@ -18,24 +18,33 @@
import android.content.res.Resources
import android.view.ViewGroup
+import android.widget.ImageView
import android.widget.LinearLayout
import com.android.launcher3.DeviceProfile
+import com.android.systemui.shared.rotation.RotationButton
/** Layoutter for showing gesture navigation on phone screen. No buttons here, no-op container */
class PhoneGestureLayoutter(
resources: Resources,
navBarContainer: LinearLayout,
endContextualContainer: ViewGroup,
- startContextualContainer: ViewGroup
+ startContextualContainer: ViewGroup,
+ imeSwitcher: ImageView?,
+ rotationButton: RotationButton?,
+ a11yButton: ImageView
) :
AbstractNavButtonLayoutter(
resources,
navBarContainer,
endContextualContainer,
- startContextualContainer
+ startContextualContainer,
+ imeSwitcher,
+ rotationButton,
+ a11yButton
) {
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
- // no-op
+ endContextualContainer.removeAllViews()
+ startContextualContainer.removeAllViews()
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
index 13ffe6e..21bbca5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
@@ -20,24 +20,32 @@
import android.view.Gravity
import android.view.ViewGroup
import android.widget.FrameLayout
+import android.widget.ImageView
import android.widget.LinearLayout
import androidx.core.view.children
import com.android.launcher3.DeviceProfile
import com.android.launcher3.R
import com.android.launcher3.taskbar.TaskbarManager
import com.android.launcher3.util.DimensionUtils
+import com.android.systemui.shared.rotation.RotationButton
open class PhoneLandscapeNavLayoutter(
- resources: Resources,
- navBarContainer: LinearLayout,
- endContextualContainer: ViewGroup,
- startContextualContainer: ViewGroup
+ resources: Resources,
+ navBarContainer: LinearLayout,
+ endContextualContainer: ViewGroup,
+ startContextualContainer: ViewGroup,
+ imeSwitcher: ImageView?,
+ rotationButton: RotationButton?,
+ a11yButton: ImageView,
) :
AbstractNavButtonLayoutter(
- resources,
- navBarContainer,
- endContextualContainer,
- startContextualContainer
+ resources,
+ navBarContainer,
+ endContextualContainer,
+ startContextualContainer,
+ imeSwitcher,
+ rotationButton,
+ a11yButton
) {
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
@@ -81,6 +89,24 @@
}
}
}
+
+ endContextualContainer.removeAllViews()
+ startContextualContainer.removeAllViews()
+
+ val startContextualContainerParams = FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+ startContextualContainerParams.gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
+ startContextualContainer.layoutParams = startContextualContainerParams
+
+ if (imeSwitcher != null) {
+ startContextualContainer.addView(imeSwitcher)
+ imeSwitcher.layoutParams = getParamsToCenterView()
+ }
+ startContextualContainer.addView(a11yButton)
+ if (rotationButton != null) {
+ startContextualContainer.addView(rotationButton.currentView)
+ rotationButton.currentView.layoutParams = getParamsToCenterView()
+ }
}
open fun addThreeButtons() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
index c763115..ad03e5b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
@@ -20,23 +20,31 @@
import android.view.Gravity
import android.view.ViewGroup
import android.widget.FrameLayout
+import android.widget.ImageView
import android.widget.LinearLayout
import com.android.launcher3.DeviceProfile
import com.android.launcher3.R
import com.android.launcher3.taskbar.TaskbarManager
import com.android.launcher3.util.DimensionUtils
+import com.android.systemui.shared.rotation.RotationButton
class PhonePortraitNavLayoutter(
- resources: Resources,
- navBarContainer: LinearLayout,
- endContextualContainer: ViewGroup,
- startContextualContainer: ViewGroup
+ resources: Resources,
+ navBarContainer: LinearLayout,
+ endContextualContainer: ViewGroup,
+ startContextualContainer: ViewGroup,
+ imeSwitcher: ImageView?,
+ rotationButton: RotationButton?,
+ a11yButton: ImageView,
) :
AbstractNavButtonLayoutter(
- resources,
- navBarContainer,
- endContextualContainer,
- startContextualContainer
+ resources,
+ navBarContainer,
+ endContextualContainer,
+ startContextualContainer,
+ imeSwitcher,
+ rotationButton,
+ a11yButton
) {
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
@@ -90,5 +98,23 @@
}
}
}
+
+ endContextualContainer.removeAllViews()
+ startContextualContainer.removeAllViews()
+
+ val endContextualContainerParams = FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)
+ endContextualContainerParams.gravity = Gravity.END or Gravity.CENTER_VERTICAL
+ endContextualContainer.layoutParams = endContextualContainerParams
+
+ if (imeSwitcher != null) {
+ endContextualContainer.addView(imeSwitcher)
+ imeSwitcher.layoutParams = getParamsToCenterView()
+ }
+ endContextualContainer.addView(a11yButton)
+ if (rotationButton != null) {
+ endContextualContainer.addView(rotationButton.currentView)
+ rotationButton.currentView.layoutParams = getParamsToCenterView()
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneSeascapeNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneSeascapeNavLayoutter.kt
index 2d62c3f..cde39f3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneSeascapeNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneSeascapeNavLayoutter.kt
@@ -17,20 +17,30 @@
package com.android.launcher3.taskbar.navbutton
import android.content.res.Resources
+import android.view.Gravity
import android.view.ViewGroup
+import android.widget.FrameLayout
+import android.widget.ImageView
import android.widget.LinearLayout
+import com.android.systemui.shared.rotation.RotationButton
class PhoneSeascapeNavLayoutter(
resources: Resources,
navBarContainer: LinearLayout,
endContextualContainer: ViewGroup,
- startContextualContainer: ViewGroup
+ startContextualContainer: ViewGroup,
+ imeSwitcher: ImageView?,
+ rotationButton: RotationButton?,
+ a11yButton: ImageView
) :
PhoneLandscapeNavLayoutter(
resources,
navBarContainer,
endContextualContainer,
- startContextualContainer
+ startContextualContainer,
+ imeSwitcher,
+ rotationButton,
+ a11yButton
) {
override fun addThreeButtons() {
@@ -38,5 +48,23 @@
navButtonContainer.addView(backButton)
navButtonContainer.addView(homeButton)
navButtonContainer.addView(recentsButton)
+
+ endContextualContainer.removeAllViews()
+ startContextualContainer.removeAllViews()
+
+ val endContextualContainerParams = FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+ endContextualContainerParams.gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL
+ endContextualContainer.layoutParams = endContextualContainerParams
+
+ if (imeSwitcher != null) {
+ endContextualContainer.addView(imeSwitcher)
+ imeSwitcher.layoutParams = getParamsToCenterView()
+ }
+ endContextualContainer.addView(a11yButton)
+ if (rotationButton != null) {
+ endContextualContainer.addView(rotationButton.currentView)
+ rotationButton.currentView.layoutParams = getParamsToCenterView()
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt
index a24002c..db245b8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt
@@ -20,20 +20,28 @@
import android.view.Gravity
import android.view.ViewGroup
import android.widget.FrameLayout
+import android.widget.ImageView
import android.widget.LinearLayout
import com.android.launcher3.DeviceProfile
+import com.android.systemui.shared.rotation.RotationButton
class SetupNavLayoutter(
- resources: Resources,
- navButtonContainer: LinearLayout,
- endContextualContainer: ViewGroup,
- startContextualContainer: ViewGroup
+ resources: Resources,
+ navButtonContainer: LinearLayout,
+ endContextualContainer: ViewGroup,
+ startContextualContainer: ViewGroup,
+ imeSwitcher: ImageView?,
+ rotationButton: RotationButton?,
+ a11yButton: ImageView
) :
AbstractNavButtonLayoutter(
- resources,
- navButtonContainer,
- endContextualContainer,
- startContextualContainer
+ resources,
+ navButtonContainer,
+ endContextualContainer,
+ startContextualContainer,
+ imeSwitcher,
+ rotationButton,
+ a11yButton
) {
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
@@ -46,5 +54,28 @@
gravity = Gravity.START
}
navButtonContainer.requestLayout()
+
+ endContextualContainer.removeAllViews()
+ startContextualContainer.removeAllViews()
+
+ val endContextualContainerParams = FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)
+ endContextualContainerParams.gravity = Gravity.END or Gravity.CENTER_VERTICAL
+ endContextualContainer.layoutParams = endContextualContainerParams
+
+ val startContextualContainerParams = FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)
+ startContextualContainerParams.gravity = Gravity.START or Gravity.CENTER_VERTICAL
+ startContextualContainer.layoutParams = startContextualContainerParams
+
+ if (imeSwitcher != null) {
+ startContextualContainer.addView(imeSwitcher)
+ imeSwitcher.layoutParams = getParamsToCenterView()
+ }
+ endContextualContainer.addView(a11yButton)
+ if (rotationButton != null) {
+ endContextualContainer.addView(rotationButton.currentView)
+ rotationButton.currentView.layoutParams = getParamsToCenterView()
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
index 8332b7d..56e55bb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
@@ -20,22 +20,30 @@
import android.view.Gravity
import android.view.ViewGroup
import android.widget.FrameLayout
+import android.widget.ImageView
import android.widget.LinearLayout
import com.android.launcher3.DeviceProfile
import com.android.launcher3.R
+import com.android.systemui.shared.rotation.RotationButton
/** Layoutter for showing 3 button navigation on large screen */
class TaskbarNavLayoutter(
- resources: Resources,
- navBarContainer: LinearLayout,
- endContextualContainer: ViewGroup,
- startContextualContainer: ViewGroup
+ resources: Resources,
+ navBarContainer: LinearLayout,
+ endContextualContainer: ViewGroup,
+ startContextualContainer: ViewGroup,
+ imeSwitcher: ImageView?,
+ rotationButton: RotationButton?,
+ a11yButton: ImageView
) :
AbstractNavButtonLayoutter(
- resources,
- navBarContainer,
- endContextualContainer,
- startContextualContainer
+ resources,
+ navBarContainer,
+ endContextualContainer,
+ startContextualContainer,
+ imeSwitcher,
+ rotationButton,
+ a11yButton
) {
override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
@@ -77,5 +85,28 @@
}
}
}
+
+ endContextualContainer.removeAllViews()
+ startContextualContainer.removeAllViews()
+
+ val endContextualContainerParams = FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)
+ endContextualContainerParams.gravity = Gravity.END or Gravity.CENTER_VERTICAL
+ endContextualContainer.layoutParams = endContextualContainerParams
+
+ val startContextualContainerParams = FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)
+ startContextualContainerParams.gravity = Gravity.START or Gravity.CENTER_VERTICAL
+ startContextualContainer.layoutParams = startContextualContainerParams
+
+ if (imeSwitcher != null) {
+ startContextualContainer.addView(imeSwitcher)
+ imeSwitcher.layoutParams = getParamsToCenterView()
+ }
+ endContextualContainer.addView(a11yButton)
+ if (rotationButton != null) {
+ endContextualContainer.addView(rotationButton.currentView)
+ rotationButton.currentView.layoutParams = getParamsToCenterView()
+ }
}
}
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 9be9294..221ce48 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -161,6 +161,10 @@
response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
SystemUiProxy.INSTANCE.get(mContext).isDragAndDropReady());
return response;
+
+ case TestProtocol.REQUEST_REFRESH_OVERVIEW_TARGET:
+ runOnTISBinder(TouchInteractionService.TISBinder::refreshOverviewTarget);
+ return response;
}
return super.call(method, arg, extras);
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 02d0f39..02fcc68 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -409,18 +409,16 @@
* Sets a proxy to bypass swipe up behavior
*/
public void setSwipeUpProxy(Function<GestureState, AnimatedFloat> proxy) {
- TouchInteractionService tis = mTis.get();
- if (tis == null) return;
- tis.mSwipeUpProxyProvider = proxy != null ? proxy : (i -> null);
+ executeForTouchInteractionService(
+ tis -> tis.mSwipeUpProxyProvider = proxy != null ? proxy : (i -> null));
}
/**
* Sets the task id where gestures should be blocked
*/
public void setGestureBlockedTaskId(int taskId) {
- TouchInteractionService tis = mTis.get();
- if (tis == null) return;
- tis.mDeviceState.setGestureBlockingTaskId(taskId);
+ executeForTouchInteractionService(
+ tis -> tis.mDeviceState.setGestureBlockingTaskId(taskId));
}
/** Sets a listener to be run on Overview Target updates. */
@@ -434,6 +432,12 @@
mOnOverviewTargetChangeListener = null;
}
}
+
+ /** Refreshes the current overview target. */
+ public void refreshOverviewTarget() {
+ executeForTouchInteractionService(tis -> tis.onOverviewTargetChange(
+ tis.mOverviewComponentObserver.isHomeAndOverviewSame()));
+ }
}
private static boolean sConnected = false;
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index c3774eb..689402b 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -34,12 +34,12 @@
import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource
import com.android.launcher3.views.BaseDragLayer
import com.android.quickstep.views.FloatingTaskView
-import com.android.quickstep.views.IconView
import com.android.quickstep.views.RecentsView
import com.android.quickstep.views.SplitInstructionsView
import com.android.quickstep.views.TaskThumbnailView
import com.android.quickstep.views.TaskView
import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
+import com.android.quickstep.views.TaskViewIcon
import java.util.function.Supplier
/**
@@ -82,7 +82,7 @@
return SplitAnimInitProps(container.thumbnailView,
container.thumbnailView.thumbnail, drawable!!,
fadeWithThumbnail = true, isStagedTask = true,
- iconView = container.iconView
+ iconView = container.iconView.asView()
)
}
}
@@ -94,7 +94,7 @@
val drawable = getDrawable(taskView.iconView, splitSelectSource)
return SplitAnimInitProps(taskView.thumbnail, taskView.thumbnail.thumbnail,
drawable!!, fadeWithThumbnail = true, isStagedTask = true,
- taskView.iconView
+ taskView.iconView.asView()
)
}
}
@@ -105,7 +105,7 @@
* TaskView's icon drawable can be null if the TaskView is scrolled far enough off screen
* @return [Drawable]
*/
- fun getDrawable(iconView: IconView, splitSelectSource: SplitSelectSource?) : Drawable? {
+ fun getDrawable(iconView: TaskViewIcon, splitSelectSource: SplitSelectSource?) : Drawable? {
if (iconView.drawable == null && splitSelectSource != null) {
return splitSelectSource.drawable
}
@@ -129,7 +129,7 @@
taskViewWidth: Int, taskViewHeight: Int,
isPrimaryTaskSplitting: Boolean) {
val thumbnail = taskIdAttributeContainer.thumbnailView
- val iconView: View = taskIdAttributeContainer.iconView
+ val iconView: View = taskIdAttributeContainer.iconView.asView()
builder.add(ObjectAnimator.ofFloat(thumbnail, TaskThumbnailView.SPLASH_ALPHA, 1f))
thumbnail.setShowSplashForSplitSelection(true)
if (deviceProfile.isLandscape) {
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index 8a6c197..dc6b5a2 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -330,7 +330,7 @@
}
@Override
- protected boolean showTaskMenuWithContainer(IconView iconView) {
+ protected boolean showTaskMenuWithContainer(TaskViewIcon iconView) {
return false;
}
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 2e347ba..3d33c87 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -2,6 +2,7 @@
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static com.android.launcher3.config.FeatureFlags.enableOverviewIconMenu;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.quickstep.util.SplitScreenUtils.convertLauncherSplitBoundsToShell;
@@ -11,6 +12,7 @@
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewStub;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -25,6 +27,7 @@
import com.android.quickstep.RecentsModel;
import com.android.quickstep.TaskIconCache;
import com.android.quickstep.TaskThumbnailCache;
+import com.android.quickstep.TaskUtils;
import com.android.quickstep.util.CancellableTask;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.SplitSelectStateController;
@@ -54,7 +57,7 @@
@Nullable
private Task mSecondaryTask;
private TaskThumbnailView mSnapshotView2;
- private IconView mIconView2;
+ private TaskViewIcon mIconView2;
@Nullable
private CancellableTask<ThumbnailData> mThumbnailLoadRequest2;
@Nullable
@@ -99,8 +102,14 @@
protected void onFinishInflate() {
super.onFinishInflate();
mSnapshotView2 = findViewById(R.id.bottomright_snapshot);
- mIconView2 = findViewById(R.id.bottomRight_icon);
- mIcon2TouchDelegate = new TransformingTouchDelegate(mIconView2);
+ ViewStub iconViewStub2 = findViewById(R.id.bottomRight_icon);
+ if (enableOverviewIconMenu()) {
+ iconViewStub2.setLayoutResource(R.layout.icon_app_chip_view);
+ } else {
+ iconViewStub2.setLayoutResource(R.layout.icon_view);
+ }
+ mIconView2 = (TaskViewIcon) iconViewStub2.inflate();
+ mIcon2TouchDelegate = new TransformingTouchDelegate(mIconView2.asView());
}
public void bind(Task primary, Task secondary, RecentsOrientedState orientedState,
@@ -160,6 +169,7 @@
mIconLoadRequest2 = iconCache.updateIconInBackground(mSecondaryTask,
(task) -> {
setIcon(mIconView2, task.icon);
+ setText(mIconView2, TaskUtils.getTitle(getContext(), task));
mDigitalWellBeingToast2.initialize(mSecondaryTask);
mDigitalWellBeingToast2.setSplitConfiguration(mSplitBoundsConfig);
mDigitalWellBeingToast.setSplitConfiguration(mSplitBoundsConfig);
@@ -174,6 +184,7 @@
}
if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
setIcon(mIconView2, null);
+ setText(mIconView2, null);
}
}
}
@@ -305,7 +316,7 @@
}
// Check which of the two apps was selected
- if (isCoordInView(mIconView2, mLastTouchDownPosition)
+ if (isCoordInView(mIconView2.asView(), mLastTouchDownPosition)
|| isCoordInView(mSnapshotView2, mLastTouchDownPosition)) {
return 1;
}
@@ -371,10 +382,7 @@
super.setOrientationState(orientationState);
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
boolean isGridTask = deviceProfile.isTablet && !isFocusedTask();
- int iconDrawableSize = isGridTask ? deviceProfile.overviewTaskIconDrawableSizeGridPx
- : deviceProfile.overviewTaskIconDrawableSizePx;
- mIconView2.setDrawableSize(iconDrawableSize, iconDrawableSize);
- mIconView2.setRotation(getPagedOrientationHandler().getDegreesRotated());
+ mIconView2.setIconOrientation(orientationState, isGridTask);
updateIconPlacement();
updateSecondaryDwbPlacement();
}
@@ -388,7 +396,7 @@
int taskIconHeight = deviceProfile.overviewTaskIconSizePx;
boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
- getPagedOrientationHandler().setSplitIconParams(mIconView, mIconView2,
+ getPagedOrientationHandler().setSplitIconParams(mIconView.asView(), mIconView2.asView(),
taskIconHeight, mSnapshotView.getMeasuredWidth(), mSnapshotView.getMeasuredHeight(),
getMeasuredHeight(), getMeasuredWidth(), isRtl, deviceProfile,
mSplitBoundsConfig);
diff --git a/quickstep/src/com/android/quickstep/views/IconAppChipView.java b/quickstep/src/com/android/quickstep/views/IconAppChipView.java
new file mode 100644
index 0000000..960a09e
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/IconAppChipView.java
@@ -0,0 +1,284 @@
+/*
+ * 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.quickstep.views;
+
+import static com.android.app.animation.Interpolators.EMPHASIZED;
+import static com.android.launcher3.config.FeatureFlags.enableOverviewIconMenu;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewAnimationUtils;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.R;
+import com.android.launcher3.touch.LandscapePagedViewHandler;
+import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.launcher3.touch.SeascapePagedViewHandler;
+import com.android.launcher3.views.ActivityContext;
+import com.android.quickstep.util.RecentsOrientedState;
+
+/**
+ * An icon app menu view which can be used in place of an IconView in overview TaskViews.
+ */
+public class IconAppChipView extends FrameLayout implements TaskViewIcon {
+
+ private static final int MENU_BACKGROUND_REVEAL_DURATION = 417;
+ private static final int MENU_BACKGROUND_HIDE_DURATION = 333;
+
+ private IconView mIconView;
+ private TextView mIconTextView;
+ private ImageView mIconArrowView;
+ private ImageView mIconViewBackground;
+
+ private int mMaxIconBackgroundWidth;
+ private int mMinIconBackgroundWidth;
+ private int mMaxIconBackgroundHeight;
+ private int mMinIconBackgroundHeight;
+ private int mIconTextMinWidth;
+ private int mIconTextMaxWidth;
+ private int mInnerMargin;
+ private int mIconArrowSize;
+ private int mIconMenuMarginStart;
+ private int mArrowMaxTranslationX;
+
+ public IconAppChipView(Context context) {
+ this(context, null);
+ }
+
+ public IconAppChipView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public IconAppChipView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public IconAppChipView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ mMaxIconBackgroundWidth = getResources().getDimensionPixelSize(
+ R.dimen.task_thumbnail_icon_menu_max_width);
+ mMinIconBackgroundWidth = getResources().getDimensionPixelSize(
+ R.dimen.task_thumbnail_icon_menu_min_width);
+ mMaxIconBackgroundHeight = getResources().getDimensionPixelSize(
+ R.dimen.task_thumbnail_icon_menu_max_height);
+ mMinIconBackgroundHeight = getResources().getDimensionPixelSize(
+ R.dimen.task_thumbnail_icon_menu_min_height);
+ mIconTextMaxWidth = getResources().getDimensionPixelSize(
+ R.dimen.task_thumbnail_icon_menu_text_max_width);
+ mInnerMargin = (int) getResources().getDimension(
+ R.dimen.task_thumbnail_icon_menu_arrow_margin);
+ mIconTextMinWidth = getResources().getDimensionPixelSize(
+ R.dimen.task_thumbnail_icon_menu_text_width) + (2 * mInnerMargin);
+ int taskIconHeight = getResources().getDimensionPixelSize(
+ R.dimen.task_thumbnail_icon_menu_drawable_touch_size);
+ int arrowWidth = getResources().getDimensionPixelSize(
+ R.dimen.task_thumbnail_icon_menu_arrow_size);
+ mIconArrowSize = getResources().getDimensionPixelSize(
+ R.dimen.task_thumbnail_icon_menu_arrow_drawable_size);
+ mIconMenuMarginStart = getResources().getDimensionPixelSize(
+ R.dimen.task_thumbnail_icon_menu_margin);
+ mArrowMaxTranslationX =
+ mMaxIconBackgroundWidth - taskIconHeight - mIconTextMaxWidth + arrowWidth;
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mIconView = findViewById(R.id.icon_view);
+ mIconTextView = findViewById(R.id.icon_text);
+ mIconArrowView = findViewById(R.id.icon_arrow);
+ mIconViewBackground = findViewById(R.id.icon_view_background);
+ }
+
+ protected IconView getIconView() {
+ return mIconView;
+ }
+
+ @Override
+ public void setText(CharSequence text) {
+ if (mIconTextView != null) {
+ mIconTextView.setText(text);
+ }
+ }
+
+ @Override
+ public Drawable getDrawable() {
+ return mIconView == null ? null : mIconView.getDrawable();
+ }
+
+ @Override
+ public void setDrawable(Drawable icon) {
+ if (mIconView != null) {
+ mIconView.setDrawable(icon);
+ }
+ }
+
+ @Override
+ public void setDrawableSize(int iconWidth, int iconHeight) {
+ if (mIconView != null) {
+ mIconView.setDrawableSize(iconWidth, iconHeight);
+ }
+ }
+
+ @Override
+ public void setIconOrientation(RecentsOrientedState orientationState, boolean isGridTask) {
+
+ PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
+ boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ DeviceProfile deviceProfile =
+ ActivityContext.lookupContext(getContext()).getDeviceProfile();
+
+ int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
+ int taskIconSize = deviceProfile.overviewTaskIconSizePx;
+ int taskMargin = deviceProfile.overviewTaskMarginPx;
+
+ LayoutParams iconMenuParams = (LayoutParams) getLayoutParams();
+ orientationHandler.setTaskIconMenuParams(iconMenuParams, mIconMenuMarginStart,
+ thumbnailTopMargin);
+ iconMenuParams.width = mMinIconBackgroundWidth;
+ iconMenuParams.height = taskIconSize;
+ if (orientationHandler instanceof SeascapePagedViewHandler) {
+ // Use half menu height to place the pivot within the X/Y center of icon in the menu.
+ setPivotX(getHeight() / 2f);
+ setPivotY(getHeight() / 2f - mIconMenuMarginStart);
+ } else if (orientationHandler instanceof LandscapePagedViewHandler) {
+ setPivotX(getWidth());
+ setPivotY(0);
+ }
+ // Pivot not updated for PortraitPagedViewHandler case, as it has 0 rotation.
+
+ setTranslationY(0);
+ setRotation(orientationHandler.getDegreesRotated());
+
+ LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
+ orientationHandler.setTaskIconParams(iconParams, taskMargin, taskIconSize,
+ thumbnailTopMargin, isRtl);
+ iconParams.width = iconParams.height = taskIconSize;
+ iconParams.gravity = Gravity.START | Gravity.CENTER_VERTICAL;
+ mIconView.setLayoutParams(iconParams);
+
+ int iconDrawableSize = enableOverviewIconMenu()
+ ? deviceProfile.overviewTaskIconAppChipMenuDrawableSizePx
+ : isGridTask ? deviceProfile.overviewTaskIconDrawableSizeGridPx
+ : deviceProfile.overviewTaskIconDrawableSizePx;
+ mIconView.setDrawableSize(iconDrawableSize, iconDrawableSize);
+
+ LayoutParams iconTextParams = (LayoutParams) mIconTextView.getLayoutParams();
+ orientationHandler.setTaskIconParams(iconTextParams, 0, taskIconSize,
+ thumbnailTopMargin, isRtl);
+ iconTextParams.width = mIconTextMaxWidth;
+ iconTextParams.height = taskIconSize;
+ iconTextParams.setMarginStart(taskIconSize);
+ iconTextParams.topMargin = (getHeight() - mIconTextView.getHeight()) / 2;
+ iconTextParams.gravity = Gravity.CENTER_VERTICAL | Gravity.START;
+ mIconTextView.setLayoutParams(iconTextParams);
+ mIconTextView.setRevealClip(true, 0, taskIconSize / 2f, mIconTextMinWidth);
+
+ LayoutParams iconArrowParams = (LayoutParams) mIconArrowView.getLayoutParams();
+ iconArrowParams.gravity = Gravity.CENTER_VERTICAL | Gravity.END;
+ iconArrowParams.setMarginStart(taskIconSize + mIconTextMinWidth);
+ iconArrowParams.setMarginEnd(mInnerMargin);
+ mIconArrowView.setLayoutParams(iconArrowParams);
+ mIconArrowView.getDrawable().setBounds(0, 0, mIconArrowSize, mIconArrowSize);
+
+ LayoutParams backgroundParams = (LayoutParams) mIconViewBackground.getLayoutParams();
+ backgroundParams.width = mMinIconBackgroundWidth;
+ backgroundParams.height = taskIconSize;
+ mIconViewBackground.setPivotX(
+ isRtl ? mMinIconBackgroundWidth - (taskIconSize / 2f - mInnerMargin)
+ : taskIconSize / 2f - mInnerMargin);
+ mIconViewBackground.setPivotY(taskIconSize / 2f);
+
+ requestLayout();
+ }
+
+ @Override
+ public void setIconColorTint(int color, float amount) {
+ if (mIconView != null) {
+ mIconView.setIconColorTint(color, amount);
+ }
+ }
+
+ @Override
+ public int getDrawableWidth() {
+ return mIconView == null ? 0 : mIconView.getDrawableWidth();
+ }
+
+ @Override
+ public int getDrawableHeight() {
+ return mIconView == null ? 0 : mIconView.getDrawableHeight();
+ }
+
+ protected void revealAnim(boolean isRevealing) {
+ if (isRevealing) {
+ ((AnimatedVectorDrawable) mIconArrowView.getDrawable()).start();
+ AnimatorSet anim = new AnimatorSet();
+ anim.playTogether(
+ ViewAnimationUtils.createCircularReveal(mIconTextView, 0,
+ mIconTextView.getHeight() / 2, mIconTextMinWidth, mIconTextMaxWidth),
+ ObjectAnimator.ofFloat(mIconViewBackground, SCALE_X,
+ mMaxIconBackgroundWidth / (float) mMinIconBackgroundWidth),
+ ObjectAnimator.ofFloat(mIconViewBackground, SCALE_Y,
+ mMaxIconBackgroundHeight / (float) mMinIconBackgroundHeight),
+ ObjectAnimator.ofFloat(mIconArrowView, TRANSLATION_X,
+ isLayoutRtl() ? -mArrowMaxTranslationX : mArrowMaxTranslationX));
+ anim.setDuration(MENU_BACKGROUND_REVEAL_DURATION);
+ anim.setInterpolator(EMPHASIZED);
+ anim.start();
+ } else {
+ ((AnimatedVectorDrawable) mIconArrowView.getDrawable()).reverse();
+ AnimatorSet anim = new AnimatorSet();
+ Animator textRevealAnim = ViewAnimationUtils.createCircularReveal(mIconTextView, 0,
+ mIconTextView.getHeight() / 2, mIconTextMaxWidth, mIconTextMinWidth);
+ textRevealAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // createCircularReveal removes clip on finish, restore it here to clip text.
+ mIconTextView.setRevealClip(true, 0, mIconTextView.getHeight() / 2f,
+ mIconTextMinWidth);
+ }
+ });
+ anim.playTogether(
+ textRevealAnim,
+ ObjectAnimator.ofFloat(mIconViewBackground, SCALE_X, 1),
+ ObjectAnimator.ofFloat(mIconViewBackground, SCALE_Y, 1),
+ ObjectAnimator.ofFloat(mIconArrowView, TRANSLATION_X, 0));
+ anim.setDuration(MENU_BACKGROUND_HIDE_DURATION);
+ anim.setInterpolator(EMPHASIZED);
+ anim.start();
+ }
+ }
+
+ @Override
+ public View asView() {
+ return this;
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/IconView.java b/quickstep/src/com/android/quickstep/views/IconView.java
index 5895c05..222f9ca 100644
--- a/quickstep/src/com/android/quickstep/views/IconView.java
+++ b/quickstep/src/com/android/quickstep/views/IconView.java
@@ -15,6 +15,8 @@
*/
package com.android.quickstep.views;
+import static com.android.launcher3.config.FeatureFlags.enableOverviewIconMenu;
+
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
@@ -22,16 +24,21 @@
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
+import android.widget.FrameLayout;
import androidx.annotation.Nullable;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
+import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.launcher3.views.ActivityContext;
+import com.android.quickstep.util.RecentsOrientedState;
/**
* A view which draws a drawable stretched to fit its size. Unlike ImageView, it avoids relayout
* when the drawable changes.
*/
-public class IconView extends View {
+public class IconView extends View implements TaskViewIcon {
@Nullable
private Drawable mDrawable;
@@ -52,6 +59,7 @@
/**
* Sets a {@link Drawable} to be displayed.
*/
+ @Override
public void setDrawable(@Nullable Drawable d) {
if (mDrawable != null) {
mDrawable.setCallback(null);
@@ -67,6 +75,7 @@
/**
* Sets the size of the icon drawable.
*/
+ @Override
public void setDrawableSize(int iconWidth, int iconHeight) {
mDrawableWidth = iconWidth;
mDrawableHeight = iconHeight;
@@ -82,15 +91,18 @@
mDrawable.setBounds(drawableRect);
}
+ @Override
@Nullable
public Drawable getDrawable() {
return mDrawable;
}
+ @Override
public int getDrawableWidth() {
return mDrawableWidth;
}
+ @Override
public int getDrawableHeight() {
return mDrawableHeight;
}
@@ -147,9 +159,41 @@
* @param color to blend in.
* @param amount [0,1] 0 no tint, 1 full tint
*/
+ @Override
public void setIconColorTint(int color, float amount) {
if (mDrawable != null) {
mDrawable.setColorFilter(Utilities.makeColorTintingColorFilter(color, amount));
}
}
+
+ @Override
+ public void setIconOrientation(RecentsOrientedState orientationState, boolean isGridTask) {
+ PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
+ boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ DeviceProfile deviceProfile =
+ ActivityContext.lookupContext(getContext()).getDeviceProfile();
+
+ FrameLayout.LayoutParams iconParams = (FrameLayout.LayoutParams) getLayoutParams();
+
+ int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
+ int taskIconHeight = deviceProfile.overviewTaskIconSizePx;
+ int taskMargin = deviceProfile.overviewTaskMarginPx;
+
+ orientationHandler.setTaskIconParams(iconParams, taskMargin, taskIconHeight,
+ thumbnailTopMargin, isRtl);
+ iconParams.width = iconParams.height = taskIconHeight;
+ setLayoutParams(iconParams);
+
+ setRotation(orientationHandler.getDegreesRotated());
+ int iconDrawableSize = enableOverviewIconMenu()
+ ? deviceProfile.overviewTaskIconAppChipMenuDrawableSizePx
+ : isGridTask ? deviceProfile.overviewTaskIconDrawableSizeGridPx
+ : deviceProfile.overviewTaskIconDrawableSizePx;
+ setDrawableSize(iconDrawableSize, iconDrawableSize);
+ }
+
+ @Override
+ public View asView() {
+ return this;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index b4d24e5..62c0bef 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -16,6 +16,8 @@
package com.android.quickstep.views;
+import static com.android.app.animation.Interpolators.EMPHASIZED;
+import static com.android.launcher3.config.FeatureFlags.enableOverviewIconMenu;
import static com.android.quickstep.views.TaskThumbnailView.DIM_ALPHA;
import android.animation.Animator;
@@ -24,6 +26,7 @@
import android.content.Context;
import android.graphics.Outline;
import android.graphics.Rect;
+import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RectShape;
import android.util.AttributeSet;
@@ -58,16 +61,19 @@
private static final Rect sTempRect = new Rect();
- private static final int REVEAL_OPEN_DURATION = 150;
- private static final int REVEAL_CLOSE_DURATION = 100;
+ private static final int REVEAL_OPEN_DURATION = enableOverviewIconMenu() ? 417 : 150;
+ private static final int REVEAL_CLOSE_DURATION = enableOverviewIconMenu() ? 333 : 100;
private BaseDraggingActivity mActivity;
private TextView mTaskName;
@Nullable
private AnimatorSet mOpenCloseAnimator;
+ @Nullable private Runnable mOnClosingStartCallback;
private TaskView mTaskView;
private TaskIdAttributeContainer mTaskContainer;
private LinearLayout mOptionLayout;
+ private float mMenuTranslationYBeforeOpen;
+ private float mIconViewTranslationYBeforeOpen;
public TaskMenuView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -137,14 +143,20 @@
}
}
- public static boolean showForTask(TaskIdAttributeContainer taskContainer) {
+ public static boolean showForTask(TaskIdAttributeContainer taskContainer,
+ @Nullable Runnable onClosingStartCallback) {
BaseDraggingActivity activity = BaseDraggingActivity.fromContext(
taskContainer.getTaskView().getContext());
final TaskMenuView taskMenuView = (TaskMenuView) activity.getLayoutInflater().inflate(
R.layout.task_menu, activity.getDragLayer(), false);
+ taskMenuView.setOnClosingStartCallback(onClosingStartCallback);
return taskMenuView.populateAndShowForTask(taskContainer);
}
+ public static boolean showForTask(TaskIdAttributeContainer taskContainer) {
+ return showForTask(taskContainer, null);
+ }
+
private boolean populateAndShowForTask(TaskIdAttributeContainer taskContainer) {
if (isAttachedToWindow()) {
return false;
@@ -171,8 +183,12 @@
}
private void addMenuOptions(TaskIdAttributeContainer taskContainer) {
- mTaskName.setText(TaskUtils.getTitle(getContext(), taskContainer.getTask()));
- mTaskName.setOnClickListener(v -> close(true));
+ if (enableOverviewIconMenu()) {
+ removeView(mTaskName);
+ } else {
+ mTaskName.setText(TaskUtils.getTitle(getContext(), taskContainer.getTask()));
+ mTaskName.setOnClickListener(v -> close(true));
+ }
TaskOverlayFactory.getEnabledShortcuts(mTaskView, taskContainer)
.forEach(this::addMenuOption);
}
@@ -180,6 +196,9 @@
private void addMenuOption(SystemShortcut menuOption) {
LinearLayout menuOptionView = (LinearLayout) mActivity.getLayoutInflater().inflate(
R.layout.task_view_menu_option, this, false);
+ if (enableOverviewIconMenu()) {
+ ((GradientDrawable) menuOptionView.getBackground()).setCornerRadius(0);
+ }
menuOption.setIconAndLabelFor(
menuOptionView.findViewById(R.id.icon), menuOptionView.findViewById(R.id.text));
LayoutParams lp = (LayoutParams) menuOptionView.getLayoutParams();
@@ -198,8 +217,9 @@
// Get Position
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
- mActivity.getDragLayer().getDescendantRectRelativeToSelf(taskContainer.getThumbnailView(),
- sTempRect);
+ mActivity.getDragLayer().getDescendantRectRelativeToSelf(
+ enableOverviewIconMenu() ? taskContainer.getIconView().asView()
+ : taskContainer.getThumbnailView(), sTempRect);
Rect insets = mActivity.getDragLayer().getInsets();
BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) getLayoutParams();
int padding = getResources()
@@ -217,12 +237,17 @@
ShapeDrawable divider = new ShapeDrawable(new RectShape());
divider.getPaint().setColor(getResources().getColor(android.R.color.transparent));
int dividerSpacing = (int) getResources().getDimension(R.dimen.task_menu_spacing);
- mOptionLayout.setShowDividers(SHOW_DIVIDER_MIDDLE);
+ mOptionLayout.setShowDividers(
+ enableOverviewIconMenu() ? SHOW_DIVIDER_NONE : SHOW_DIVIDER_MIDDLE);
orientationHandler.setTaskOptionsMenuLayoutOrientation(
deviceProfile, mOptionLayout, dividerSpacing, divider);
- float thumbnailAlignedX = sTempRect.left - insets.left;
- float thumbnailAlignedY = sTempRect.top - insets.top;
+ float thumbnailAlignedX = sTempRect.left - insets.left + (enableOverviewIconMenu()
+ ? -getResources().getDimensionPixelSize(
+ R.dimen.task_thumbnail_icon_menu_touch_max_margin) : 0);
+ float thumbnailAlignedY = sTempRect.top - insets.top + (enableOverviewIconMenu()
+ ? getResources().getDimensionPixelSize(R.dimen.task_thumbnail_icon_menu_max_height)
+ - 2 * dividerSpacing : 0);
// Changing pivot to make computations easier
// NOTE: Changing the pivots means the rotated view gets rotated about the new pivots set,
// which would render the X and Y position set here incorrect
@@ -231,15 +256,22 @@
setRotation(orientationHandler.getDegreesRotated());
// Margin that insets the menuView inside the taskView
- float taskInsetMargin = getResources().getDimension(R.dimen.task_card_margin);
+ float taskInsetMargin =
+ enableOverviewIconMenu() ? getResources().getDimension(
+ R.dimen.task_thumbnail_icon_menu_margin) : getResources().getDimension(
+ R.dimen.task_card_margin);
setTranslationX(orientationHandler.getTaskMenuX(thumbnailAlignedX,
- mTaskContainer.getThumbnailView(), deviceProfile, taskInsetMargin));
+ mTaskContainer.getThumbnailView(), deviceProfile, taskInsetMargin,
+ mTaskContainer.getIconView().asView()));
setTranslationY(orientationHandler.getTaskMenuY(
thumbnailAlignedY, mTaskContainer.getThumbnailView(),
- mTaskContainer.getStagePosition(), this, taskInsetMargin));
+ mTaskContainer.getStagePosition(), this, taskInsetMargin,
+ mTaskContainer.getIconView().asView()));
}
private void animateOpen() {
+ mMenuTranslationYBeforeOpen = getTranslationY();
+ mIconViewTranslationYBeforeOpen = mTaskContainer.getIconView().asView().getTranslationY();
animateOpenOrClosed(false);
mIsOpen = true;
}
@@ -256,7 +288,29 @@
final Animator revealAnimator = createOpenCloseOutlineProvider()
.createRevealAnimator(this, closing);
- revealAnimator.setInterpolator(Interpolators.DECELERATE);
+ revealAnimator.setInterpolator(enableOverviewIconMenu() ? Interpolators.EMPHASIZED
+ : Interpolators.DECELERATE);
+
+ if (enableOverviewIconMenu()
+ && ((RecentsView) mActivity.getOverviewPanel()).isOnGridBottomRow(mTaskView)) {
+ float taskBottom = mTaskView.getHeight() + mTaskView.getPersistentTranslationY();
+ float menuBottom = getHeight() + mMenuTranslationYBeforeOpen;
+ float additionalTranslationY = Math.max(menuBottom - taskBottom, 0);
+
+ ObjectAnimator translationYAnim = ObjectAnimator.ofFloat(this, TRANSLATION_Y,
+ closing ? mMenuTranslationYBeforeOpen
+ : mMenuTranslationYBeforeOpen - additionalTranslationY);
+ translationYAnim.setInterpolator(EMPHASIZED);
+
+ ObjectAnimator menuTranslationYAnim = ObjectAnimator.ofFloat(
+ mTaskContainer.getIconView().asView(), TRANSLATION_Y,
+ closing ? mIconViewTranslationYBeforeOpen
+ : mIconViewTranslationYBeforeOpen - additionalTranslationY);
+ menuTranslationYAnim.setInterpolator(EMPHASIZED);
+
+ mOpenCloseAnimator.playTogether(translationYAnim, menuTranslationYAnim);
+ }
+
mOpenCloseAnimator.playTogether(revealAnimator,
ObjectAnimator.ofFloat(
mTaskContainer.getThumbnailView(), DIM_ALPHA,
@@ -266,6 +320,9 @@
@Override
public void onAnimationStart(Animator animation) {
setVisibility(VISIBLE);
+ if (closing && mOnClosingStartCallback != null) {
+ mOnClosingStartCallback.run();
+ }
}
@Override
@@ -286,9 +343,16 @@
private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
float radius = TaskCornerRadius.get(mContext);
- Rect fromRect = new Rect(0, 0, getWidth(), 0);
+ Rect fromRect = new Rect(
+ enableOverviewIconMenu() && isLayoutRtl() ? getWidth() : 0,
+ 0,
+ enableOverviewIconMenu() && !isLayoutRtl() ? 0 : getWidth(),
+ 0);
Rect toRect = new Rect(0, 0, getWidth(), getHeight());
return new RoundedRectRevealOutlineProvider(radius, radius, fromRect, toRect);
}
+ private void setOnClosingStartCallback(Runnable onClosingStartCallback) {
+ mOnClosingStartCallback = onClosingStartCallback;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
index b373911..12b8b6f 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -106,7 +106,7 @@
override fun isOfType(type: Int): Boolean = type and TYPE_TASK_MENU != 0
override fun getTargetObjectLocation(outPos: Rect?) {
- popupContainer.getDescendantRectRelativeToSelf(taskContainer.iconView, outPos)
+ popupContainer.getDescendantRectRelativeToSelf(taskContainer.iconView.asView(), outPos)
}
override fun onControllerInterceptTouchEvent(ev: MotionEvent?): Boolean {
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 50b38ea..6ae1973 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -25,6 +25,7 @@
import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
+import static com.android.launcher3.config.FeatureFlags.enableOverviewIconMenu;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -63,6 +64,7 @@
import android.view.TouchDelegate;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewStub;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
@@ -352,7 +354,7 @@
@Nullable
protected Task mTask;
protected TaskThumbnailView mSnapshotView;
- protected IconView mIconView;
+ protected TaskViewIcon mIconView;
protected final DigitalWellBeingToast mDigitalWellBeingToast;
protected float mFullscreenProgress;
private float mGridProgress;
@@ -519,8 +521,14 @@
protected void onFinishInflate() {
super.onFinishInflate();
mSnapshotView = findViewById(R.id.snapshot);
- mIconView = findViewById(R.id.icon);
- mIconTouchDelegate = new TransformingTouchDelegate(mIconView);
+ ViewStub iconViewStub = findViewById(R.id.icon);
+ if (enableOverviewIconMenu()) {
+ iconViewStub.setLayoutResource(R.layout.icon_app_chip_view);
+ } else {
+ iconViewStub.setLayoutResource(R.layout.icon_view);
+ }
+ mIconView = (TaskViewIcon) iconViewStub.inflate();
+ mIconTouchDelegate = new TransformingTouchDelegate(mIconView.asView());
}
@Override
@@ -563,14 +571,14 @@
@Override
public void draw(Canvas canvas) {
- super.draw(canvas);
+ // Draw border first so any child views outside of the thumbnail bounds are drawn above it.
if (mFocusBorderAnimator != null) {
mFocusBorderAnimator.drawBorder(canvas);
}
-
if (mHoverBorderAnimator != null) {
mHoverBorderAnimator.drawBorder(canvas);
}
+ super.draw(canvas);
}
/**
@@ -587,17 +595,22 @@
return false;
}
- protected void computeAndSetIconTouchDelegate(IconView iconView, float[] tempCenterCoords,
+ protected void computeAndSetIconTouchDelegate(TaskViewIcon view, float[] tempCenterCoords,
TransformingTouchDelegate transformingTouchDelegate) {
- float iconHalfSize = iconView.getWidth() / 2f;
- tempCenterCoords[0] = tempCenterCoords[1] = iconHalfSize;
- getDescendantCoordRelativeToAncestor(iconView, mActivity.getDragLayer(), tempCenterCoords,
- false);
+ if (view == null) {
+ return;
+ }
+ float viewHalfWidth = view.getWidth() / 2f;
+ float viewHalfHeight = view.getHeight() / 2f;
+ tempCenterCoords[0] = viewHalfWidth;
+ tempCenterCoords[1] = viewHalfHeight;
+ getDescendantCoordRelativeToAncestor(view.asView(), mActivity.getDragLayer(),
+ tempCenterCoords, false);
transformingTouchDelegate.setBounds(
- (int) (tempCenterCoords[0] - iconHalfSize),
- (int) (tempCenterCoords[1] - iconHalfSize),
- (int) (tempCenterCoords[0] + iconHalfSize),
- (int) (tempCenterCoords[1] + iconHalfSize));
+ (int) (tempCenterCoords[0] - viewHalfWidth),
+ (int) (tempCenterCoords[1] - viewHalfHeight),
+ (int) (tempCenterCoords[0] + viewHalfWidth),
+ (int) (tempCenterCoords[1] + viewHalfHeight));
}
/**
@@ -629,8 +642,8 @@
cancelPendingLoadTasks();
mTask = task;
mTaskIdContainer[0] = mTask.key.id;
- mTaskIdAttributeContainer[0] = new TaskIdAttributeContainer(task, mSnapshotView,
- mIconView, STAGE_POSITION_UNDEFINED);
+ mTaskIdAttributeContainer[0] = new TaskIdAttributeContainer(task, mSnapshotView, mIconView,
+ STAGE_POSITION_UNDEFINED);
mSnapshotView.bind(task);
setOrientationState(orientedState);
}
@@ -745,7 +758,7 @@
return new TaskThumbnailView[]{mSnapshotView};
}
- public IconView getIconView() {
+ public TaskViewIcon getIconView() {
return mIconView;
}
@@ -1075,6 +1088,7 @@
mIconLoadRequest = iconCache.updateIconInBackground(mTask,
(task) -> {
setIcon(mIconView, task.icon);
+ setText(mIconView, TaskUtils.getTitle(getContext(), task));
mDigitalWellBeingToast.initialize(task);
});
}
@@ -1090,6 +1104,7 @@
}
if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
setIcon(mIconView, null);
+ setText(mIconView, null);
}
}
}
@@ -1109,7 +1124,7 @@
}
}
- private boolean showTaskMenu(IconView iconView) {
+ private boolean showTaskMenu(TaskViewIcon iconView) {
if (!getRecentsView().canLaunchFullscreenTask()) {
// Don't show menu when selecting second split screen app
return true;
@@ -1126,11 +1141,16 @@
}
}
- protected boolean showTaskMenuWithContainer(IconView iconView) {
+ protected boolean showTaskMenuWithContainer(TaskViewIcon iconView) {
TaskIdAttributeContainer menuContainer =
mTaskIdAttributeContainer[iconView == mIconView ? 0 : 1];
DeviceProfile dp = mActivity.getDeviceProfile();
- if (dp.isTablet) {
+ if (enableOverviewIconMenu() && iconView instanceof IconAppChipView) {
+ ((IconAppChipView) iconView).revealAnim(/* isRevealing= */ true);
+ return TaskMenuView.showForTask(menuContainer, () -> {
+ ((IconAppChipView) iconView).revealAnim(/* isRevealing= */ false);
+ });
+ } else if (dp.isTablet) {
int alignedOptionIndex = 0;
if (getRecentsView().isOnGridBottomRow(menuContainer.getTaskView()) && dp.isLandscape) {
if (FeatureFlags.enableGridOnlyOverview()) {
@@ -1142,13 +1162,14 @@
alignedOptionIndex = 1;
}
}
- return TaskMenuViewWithArrow.Companion.showForTask(menuContainer, alignedOptionIndex);
+ return TaskMenuViewWithArrow.Companion.showForTask(menuContainer,
+ alignedOptionIndex);
} else {
return TaskMenuView.showForTask(menuContainer);
}
}
- protected void setIcon(IconView iconView, @Nullable Drawable icon) {
+ protected void setIcon(TaskViewIcon iconView, @Nullable Drawable icon) {
if (icon != null) {
iconView.setDrawable(icon);
iconView.setOnClickListener(v -> {
@@ -1168,32 +1189,13 @@
}
}
- public void setOrientationState(RecentsOrientedState orientationState) {
- setIconOrientation(orientationState);
- setThumbnailOrientation(orientationState);
+ protected void setText(TaskViewIcon iconView, CharSequence text) {
+ iconView.setText(text);
}
- protected void setIconOrientation(RecentsOrientedState orientationState) {
- PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
- boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
- DeviceProfile deviceProfile = mActivity.getDeviceProfile();
-
- boolean isGridTask = isGridTask();
- LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
-
- int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
- int taskIconHeight = deviceProfile.overviewTaskIconSizePx;
- int taskMargin = deviceProfile.overviewTaskMarginPx;
-
- orientationHandler.setTaskIconParams(iconParams, taskMargin, taskIconHeight,
- thumbnailTopMargin, isRtl);
- iconParams.width = iconParams.height = taskIconHeight;
- mIconView.setLayoutParams(iconParams);
-
- mIconView.setRotation(orientationHandler.getDegreesRotated());
- int iconDrawableSize = isGridTask ? deviceProfile.overviewTaskIconDrawableSizeGridPx
- : deviceProfile.overviewTaskIconDrawableSizePx;
- mIconView.setDrawableSize(iconDrawableSize, iconDrawableSize);
+ public void setOrientationState(RecentsOrientedState orientationState) {
+ mIconView.setIconOrientation(orientationState, isGridTask());
+ setThumbnailOrientation(orientationState);
}
protected void setThumbnailOrientation(RecentsOrientedState orientationState) {
@@ -1898,14 +1900,14 @@
public class TaskIdAttributeContainer {
private final TaskThumbnailView mThumbnailView;
private final Task mTask;
- private final IconView mIconView;
+ private final TaskViewIcon mIconView;
/** Defaults to STAGE_POSITION_UNDEFINED if in not a split screen task view */
private @SplitConfigurationOptions.StagePosition int mStagePosition;
@IdRes
private final int mA11yNodeId;
public TaskIdAttributeContainer(Task task, TaskThumbnailView thumbnailView,
- IconView iconView, int stagePosition) {
+ TaskViewIcon iconView, int stagePosition) {
this.mTask = task;
this.mThumbnailView = thumbnailView;
this.mIconView = iconView;
@@ -1930,7 +1932,7 @@
return TaskView.this;
}
- public IconView getIconView() {
+ public TaskViewIcon getIconView() {
return mIconView;
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskViewIcon.java b/quickstep/src/com/android/quickstep/views/TaskViewIcon.java
new file mode 100644
index 0000000..b4f21be
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/TaskViewIcon.java
@@ -0,0 +1,137 @@
+/*
+ * 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.quickstep.views;
+
+import android.annotation.Nullable;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.quickstep.util.RecentsOrientedState;
+
+/**
+ * Interface defining an object which can be used as a TaskView's icon.
+ */
+public interface TaskViewIcon {
+
+ /**
+ * Returns the width of this icon view.
+ */
+ int getWidth();
+
+ /**
+ * Returns the height of this icon view.
+ */
+ int getHeight();
+
+ /**
+ * Sets the opacity of the view.
+ */
+ void setAlpha(float alpha);
+
+ /**
+ * Returns this icon view's drawable.
+ */
+ @Nullable Drawable getDrawable();
+
+ /**
+ * Sets a {@link Drawable} to be displayed.
+ */
+ void setDrawable(@Nullable Drawable icon);
+
+ /**
+ * Register a callback to be invoked when this view is clicked.
+ */
+ void setOnClickListener(@Nullable View.OnClickListener l);
+
+ /**
+ * Register a callback to be invoked when this view is clicked and held.
+ */
+ void setOnLongClickListener(@Nullable View.OnLongClickListener l);
+
+ /**
+ * Returns the LayoutParams associated with this view.
+ */
+ ViewGroup.LayoutParams getLayoutParams();
+
+ /**
+ * Sets the layout parameters associated with this view.
+ */
+ void setLayoutParams(ViewGroup.LayoutParams params);
+
+ /**
+ * Sets the degrees that the view is rotated around the pivot point.
+ */
+ void setRotation(float rotation);
+
+ /**
+ * Sets the size of the icon drawable.
+ */
+ void setDrawableSize(int iconWidth, int iconHeight);
+
+ /**
+ * Sets the orientation of this icon view based on the provided orientationState.
+ */
+ void setIconOrientation(RecentsOrientedState orientationState, boolean isGridTask);
+
+ /**
+ * Sets the visibility state of this view.
+ */
+ void setVisibility(int visibility);
+
+ /**
+ * Sets the tint color of the icon, useful for scrimming or dimming.
+ *
+ * @param color to blend in.
+ * @param amount [0,1] 0 no tint, 1 full tint
+ */
+ void setIconColorTint(int color, float amount);
+
+ /**
+ * Gets the opacity of the view.
+ */
+ float getAlpha();
+
+ /**
+ * Returns the width of this icon view's drawable.
+ */
+ int getDrawableWidth();
+
+ /**
+ * Returns the height of this icon view's drawable.
+ */
+ int getDrawableHeight();
+
+ /**
+ * Directly calls any attached OnClickListener.
+ */
+ boolean callOnClick();
+
+ /**
+ * Calls this view's OnLongClickListener.
+ */
+ boolean performLongClick();
+
+ /**
+ * Sets the text for this icon view if any text view is associated.
+ */
+ default void setText(CharSequence text) {}
+
+ /**
+ * Returns this icon view cast as a View.
+ */
+ View asView();
+}
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
index 3920b08..16bfe70 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
@@ -13,6 +13,7 @@
import com.android.launcher3.DeviceProfile
import com.android.launcher3.R
import com.android.launcher3.taskbar.TaskbarManager
+import com.android.systemui.shared.rotation.RotationButton
import java.lang.IllegalStateException
import org.junit.Assume.assumeTrue
import org.junit.Before
@@ -34,6 +35,9 @@
@Mock lateinit var mockBackButton: ImageView
@Mock lateinit var mockRecentsButton: ImageView
@Mock lateinit var mockHomeButton: ImageView
+ @Mock lateinit var mockImeSwitcher: ImageView
+ @Mock lateinit var mockRotationButton: RotationButton
+ @Mock lateinit var mockA11yButton: ImageView
private var surfaceRotation = Surface.ROTATION_0
@@ -196,7 +200,10 @@
isInSetup = isInSetup,
isThreeButtonNav = isThreeButtonNav,
phoneMode = phoneMode,
- surfaceRotation = surfaceRotation
+ surfaceRotation = surfaceRotation,
+ imeSwitcher = mockImeSwitcher,
+ rotationButton = mockRotationButton,
+ a11yButton = mockA11yButton
)
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 7d82944..99c79b3 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -32,8 +32,6 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.rule.ShellCommandRule.disableHeadsUpNotification;
import static com.android.launcher3.util.rule.ShellCommandRule.getLauncherCommand;
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -61,6 +59,7 @@
import com.android.launcher3.util.rule.FailureWatcher;
import com.android.launcher3.util.rule.SamplerRule;
import com.android.launcher3.util.rule.ScreenRecordRule;
+import com.android.launcher3.util.rule.TestIsolationRule;
import com.android.launcher3.util.rule.TestStabilityRule;
import com.android.launcher3.util.rule.ViewCaptureRule;
import com.android.quickstep.views.RecentsView;
@@ -94,9 +93,6 @@
public final TestRule mDisableHeadsUpNotification = disableHeadsUpNotification();
@Rule
- public final TestRule mSetLauncherCommand;
-
- @Rule
public final TestRule mOrderSensitiveRules;
@Rule
@@ -116,19 +112,7 @@
Utilities.enableRunningInTestHarnessForTests();
}
- final ViewCaptureRule viewCaptureRule = new ViewCaptureRule(
- RecentsActivity.ACTIVITY_TRACKER::getCreatedActivity);
- mOrderSensitiveRules = RuleChain
- .outerRule(new SamplerRule())
- .around(new NavigationModeSwitchRule(mLauncher))
- .around(new FailureWatcher(mLauncher, viewCaptureRule::getViewCaptureData))
- .around(viewCaptureRule);
-
- mOtherLauncherActivity = context.getPackageManager().queryIntentActivities(
- getHomeIntentInPackage(context),
- MATCH_DISABLED_COMPONENTS).get(0).activityInfo;
-
- mSetLauncherCommand = (base, desc) -> new Statement() {
+ final TestRule setLauncherCommand = (base, desc) -> new Statement() {
@Override
public void evaluate() throws Throwable {
TestCommandReceiver.callCommand(TestCommandReceiver.ENABLE_TEST_LAUNCHER);
@@ -152,6 +136,21 @@
}
};
+ final ViewCaptureRule viewCaptureRule = new ViewCaptureRule(
+ RecentsActivity.ACTIVITY_TRACKER::getCreatedActivity);
+ mOrderSensitiveRules = RuleChain
+ .outerRule(new SamplerRule())
+ .around(new TestStabilityRule())
+ .around(new NavigationModeSwitchRule(mLauncher))
+ .around(new FailureWatcher(mLauncher, viewCaptureRule::getViewCaptureData))
+ .around(viewCaptureRule)
+ .around(new TestIsolationRule(mLauncher, false))
+ .around(setLauncherCommand);
+
+ mOtherLauncherActivity = context.getPackageManager().queryIntentActivities(
+ getHomeIntentInPackage(context),
+ MATCH_DISABLED_COMPONENTS).get(0).activityInfo;
+
if (TestHelpers.isInLauncherProcess()) {
mLauncher.setSystemHealthSupplier(startTime -> TestCommandReceiver.callCommand(
TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE, startTime.toString()).
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 211a13c..3039261 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -17,6 +17,7 @@
package com.android.quickstep;
import static com.android.launcher3.config.FeatureFlags.ENABLE_CURSOR_HOVER_STATES;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ICON_MENU;
import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT;
import static com.android.quickstep.TaskbarModeSwitchRule.Mode.TRANSIENT;
@@ -82,6 +83,7 @@
@After
public void tearDown() {
executeOnLauncher(launcher -> {
+ if (launcher == null) return;
RecentsView recentsView = launcher.getOverviewPanel();
recentsView.getPagedViewOrientedState().forceAllowRotationForTesting(false);
});
@@ -196,6 +198,7 @@
}
+ @PlatinumTest(focusArea = "launcher")
@Test
public void testOverviewActionsMenu() throws Exception {
startTestAppsWithCheck();
@@ -208,6 +211,23 @@
isInLaunchedApp(launcher)));
}
+
+ @Test
+ public void testOverviewActionsMenu_iconAppChipMenu() throws Exception {
+ try (AutoCloseable c = TestUtil.overrideFlag(ENABLE_OVERVIEW_ICON_MENU, true)) {
+ startTestAppsWithCheck();
+
+ OverviewTaskMenu menu =
+ mLauncher.goHome().switchToOverview().getCurrentTask().tapMenu();
+
+ assertNotNull("Tapping App info menu item returned null", menu.tapAppInfoMenuItem());
+ executeOnLauncher(launcher -> assertTrue(
+ "Launcher activity is the top activity; expecting another activity to be the "
+ + "top",
+ isInLaunchedApp(launcher)));
+ }
+ }
+
private int getCurrentOverviewPage(Launcher launcher) {
return launcher.<RecentsView>getOverviewPanel().getCurrentPage();
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index cc56faf..ed152f2 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -16,6 +16,7 @@
package com.android.quickstep;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ICON_MENU;
import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
@@ -30,8 +31,10 @@
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.tapl.OverviewTaskMenu;
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
import com.android.launcher3.ui.TaplTestsLauncher3;
+import com.android.launcher3.util.TestUtil;
import com.android.launcher3.util.rule.TestStabilityRule;
import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
@@ -139,6 +142,42 @@
.hasMenuItem("Save app pair"));
}
+ @Test
+ public void testTapBothIconMenus() {
+ createAndLaunchASplitPair();
+
+ OverviewTaskMenu taskMenu =
+ mLauncher.goHome().switchToOverview().getCurrentTask().tapMenu();
+ assertTrue("App info item not appearing in expanded task menu.",
+ taskMenu.hasMenuItem("App info"));
+ taskMenu.touchOutsideTaskMenuToDismiss();
+
+ OverviewTaskMenu splitMenu =
+ mLauncher.getOverview().getCurrentTask().tapSplitTaskMenu();
+ assertTrue("App info item not appearing in expanded split task's menu.",
+ splitMenu.hasMenuItem("App info"));
+ splitMenu.touchOutsideTaskMenuToDismiss();
+ }
+
+ @Test
+ public void testTapBothIconMenus_iconAppChipMenu() throws Exception {
+ try (AutoCloseable c = TestUtil.overrideFlag(ENABLE_OVERVIEW_ICON_MENU, true)) {
+ createAndLaunchASplitPair();
+
+ OverviewTaskMenu taskMenu =
+ mLauncher.goHome().switchToOverview().getCurrentTask().tapMenu();
+ assertTrue("App info item not appearing in expanded task menu.",
+ taskMenu.hasMenuItem("App info"));
+ taskMenu.touchOutsideTaskMenuToDismiss();
+
+ OverviewTaskMenu splitMenu =
+ mLauncher.getOverview().getCurrentTask().tapSplitTaskMenu();
+ assertTrue("App info item not appearing in expanded split task's menu.",
+ splitMenu.hasMenuItem("App info"));
+ splitMenu.touchOutsideTaskMenuToDismiss();
+ }
+ }
+
private void createAndLaunchASplitPair() {
startTestActivity(2);
startTestActivity(3);
diff --git a/res/drawable/icon_menu_arrow_background.xml b/res/drawable/icon_menu_arrow_background.xml
new file mode 100644
index 0000000..f24022e
--- /dev/null
+++ b/res/drawable/icon_menu_arrow_background.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:autoMirrored="true">
+ <gradient
+ android:type="linear"
+ android:angle="0"
+ android:startColor="#00000000"
+ android:centerX="0.25"
+ android:centerColor="?androidprv:attr/materialColorSurfaceContainer"
+ android:endColor="?androidprv:attr/materialColorSurfaceContainer" />
+ <corners android:radius="@dimen/dialogCornerRadius" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/icon_menu_background.xml b/res/drawable/icon_menu_background.xml
new file mode 100644
index 0000000..ec5f011
--- /dev/null
+++ b/res/drawable/icon_menu_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainer" />
+ <corners android:radius="@dimen/dialogCornerRadius" />
+</shape>
\ No newline at end of file
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index b5e4012..aa96397 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -60,7 +60,7 @@
<string name="all_apps_loading_message" msgid="5813968043155271636">"Laai tans programme …"</string>
<string name="all_apps_no_search_results" msgid="3200346862396363786">"Kon geen programme kry wat by \"<xliff:g id="QUERY">%1$s</xliff:g>\" pas nie"</string>
<string name="label_application" msgid="8531721983832654978">"Program"</string>
- <string name="all_apps_label" msgid="5015784846527570951">"Alle programme"</string>
+ <string name="all_apps_label" msgid="5015784846527570951">"Alle apps"</string>
<string name="notifications_header" msgid="1404149926117359025">"Kennisgewings"</string>
<string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Raak en hou om \'n kortpad te skuif."</string>
<string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"Dubbeltik en hou om \'n kortpad te skuif of gebruik gepasmaakte handelinge."</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 10f47cb..7661bd7 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -399,6 +399,10 @@
<dimen name="task_thumbnail_icon_size">0dp</dimen>
<dimen name="task_thumbnail_icon_drawable_size">0dp</dimen>
<dimen name="task_thumbnail_icon_drawable_size_grid">0dp</dimen>
+ <dimen name="task_thumbnail_icon_menu_max_width">0dp</dimen>
+ <dimen name="task_thumbnail_icon_menu_drawable_size">0dp</dimen>
+ <dimen name="task_thumbnail_icon_menu_drawable_touch_size">0dp</dimen>
+ <dimen name="task_menu_vertical_padding">0dp</dimen>
<dimen name="overview_task_margin">0dp</dimen>
<dimen name="overview_actions_height">0dp</dimen>
<dimen name="overview_actions_button_spacing">0dp</dimen>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index ab9836f..879000a 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -17,7 +17,6 @@
package com.android.launcher3;
import static android.text.Layout.Alignment.ALIGN_NORMAL;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_DOWNLOAD_APP_UX_V2;
import static com.android.launcher3.config.FeatureFlags.ENABLE_ICON_LABEL_AUTO_SCALING;
import static com.android.launcher3.config.FeatureFlags.enableCursorHoverStates;
import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
@@ -878,7 +877,7 @@
if ((info.runtimeStatusFlags & FLAG_INCREMENTAL_DOWNLOAD_ACTIVE) != 0
|| info.hasPromiseIconUi()
|| (info.runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) != 0
- || (ENABLE_DOWNLOAD_APP_UX_V2.get() && icon != null)) {
+ || (icon != null)) {
updateProgressBarUi(info.getProgressLevel() == 100 ? icon : null);
}
}
@@ -915,9 +914,7 @@
if (mIcon instanceof PreloadIconDrawable) {
preloadIconDrawable = (PreloadIconDrawable) mIcon;
preloadIconDrawable.setLevel(progressLevel);
- preloadIconDrawable.setIsDisabled(ENABLE_DOWNLOAD_APP_UX_V2.get()
- ? info.getProgressLevel() == 0
- : !info.isAppStartable());
+ preloadIconDrawable.setIsDisabled(info.getProgressLevel() == 0);
} else {
preloadIconDrawable = makePreloadIcon();
setIcon(preloadIconDrawable);
@@ -942,9 +939,7 @@
final PreloadIconDrawable preloadDrawable = newPendingIcon(getContext(), info);
preloadDrawable.setLevel(progressLevel);
- preloadDrawable.setIsDisabled(ENABLE_DOWNLOAD_APP_UX_V2.get()
- ? info.getProgressLevel() == 0
- : !info.isAppStartable());
+ preloadDrawable.setIsDisabled(info.getProgressLevel() == 0);
return preloadDrawable;
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 2b130b8..9a2193f 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -24,6 +24,7 @@
import static com.android.launcher3.Utilities.dpiFromPx;
import static com.android.launcher3.Utilities.pxFromSp;
import static com.android.launcher3.config.FeatureFlags.ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH;
+import static com.android.launcher3.config.FeatureFlags.enableOverviewIconMenu;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR;
import static com.android.launcher3.icons.GraphicsUtils.getShapePath;
import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
@@ -250,6 +251,7 @@
public int overviewTaskIconSizePx;
public int overviewTaskIconDrawableSizePx;
public int overviewTaskIconDrawableSizeGridPx;
+ public int overviewTaskIconAppChipMenuDrawableSizePx;
public int overviewTaskThumbnailTopMarginPx;
public final int overviewActionsHeight;
public final int overviewActionsTopMarginPx;
@@ -614,12 +616,17 @@
desiredWorkspaceHorizontalMarginOriginalPx = desiredWorkspaceHorizontalMarginPx;
overviewTaskMarginPx = res.getDimensionPixelSize(R.dimen.overview_task_margin);
- overviewTaskIconSizePx = res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_size);
+ overviewTaskIconSizePx = enableOverviewIconMenu() ? res.getDimensionPixelSize(
+ R.dimen.task_thumbnail_icon_menu_drawable_touch_size) : res.getDimensionPixelSize(
+ R.dimen.task_thumbnail_icon_size);
overviewTaskIconDrawableSizePx =
res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_drawable_size);
overviewTaskIconDrawableSizeGridPx =
res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_drawable_size_grid);
- overviewTaskThumbnailTopMarginPx = overviewTaskIconSizePx + overviewTaskMarginPx;
+ overviewTaskIconAppChipMenuDrawableSizePx = res.getDimensionPixelSize(
+ R.dimen.task_thumbnail_icon_menu_drawable_size);
+ overviewTaskThumbnailTopMarginPx =
+ enableOverviewIconMenu() ? 0 : overviewTaskIconSizePx + overviewTaskMarginPx;
// Don't add margin with floating search bar to minimize risk of overlapping.
overviewActionsTopMarginPx = FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get() ? 0
: res.getDimensionPixelSize(R.dimen.overview_actions_top_margin);
@@ -2027,6 +2034,8 @@
overviewTaskIconDrawableSizePx));
writer.println(prefix + pxToDpStr("overviewTaskIconDrawableSizeGridPx",
overviewTaskIconDrawableSizeGridPx));
+ writer.println(prefix + pxToDpStr("overviewTaskIconAppChipMenuDrawableSizePx",
+ overviewTaskIconAppChipMenuDrawableSizePx));
writer.println(prefix + pxToDpStr("overviewTaskThumbnailTopMarginPx",
overviewTaskThumbnailTopMarginPx));
writer.println(prefix + pxToDpStr("overviewActionsTopMarginPx",
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 4215e31..2b433f1 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -2988,6 +2988,7 @@
mStateManager.dump(prefix, writer);
mPopupDataProvider.dump(prefix, writer);
mDeviceProfile.dump(this, prefix, writer);
+ mAppsView.getAppsStore().dump(prefix, writer);
try {
FileLog.flushAll(writer);
diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java
index 378dbf3..7867f44 100644
--- a/src/com/android/launcher3/allapps/AllAppsStore.java
+++ b/src/com/android/launcher3/allapps/AllAppsStore.java
@@ -37,6 +37,7 @@
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.views.ActivityContext;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -238,4 +239,13 @@
public interface OnUpdateListener {
void onAppsUpdated();
}
+
+ /** Generate a dumpsys for each app package name and position in the apps list */
+ public void dump(String prefix, PrintWriter writer) {
+ writer.println(prefix + "\tAllAppsStore Apps[] size: " + mApps.length);
+ for (int i = 0; i < mApps.length; i++) {
+ writer.println(String.format("%s\tPackage index and name: %d/%s", prefix, i,
+ mApps[i].componentName.getPackageName()));
+ }
+ }
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 9fb175d..a3e68ba 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -151,21 +151,9 @@
// TODO(Block 8): Clean up flags
// TODO(Block 9): Clean up flags
- public static final BooleanFlag ENABLE_DOWNLOAD_APP_UX_V2 = getReleaseFlag(270395134,
- "ENABLE_DOWNLOAD_APP_UX_V2", ENABLED, "Updates the download app UX"
- + " to have better visuals");
-
- public static final BooleanFlag ENABLE_DOWNLOAD_APP_UX_V3 = getDebugFlag(270395186,
- "ENABLE_DOWNLOAD_APP_UX_V3", ENABLED, "Updates the download app UX"
- + " to have better visuals, improve contrast, and color");
public static final BooleanFlag SHOW_DOT_PAGINATION = getDebugFlag(270395278,
"SHOW_DOT_PAGINATION", ENABLED, "Enable showing dot pagination in workspace");
-
- public static final BooleanFlag LARGE_SCREEN_WIDGET_PICKER = getDebugFlag(270395809,
- "LARGE_SCREEN_WIDGET_PICKER", ENABLED, "Enable new widget picker that takes "
- + "advantage of large screen format");
-
public static final BooleanFlag UNFOLDED_WIDGET_PICKER = getDebugFlag(301918659,
"UNFOLDED_WIDGET_PICKER", DISABLED, "Enable new widget picker that takes "
+ "advantage of the unfolded foldable format");
@@ -327,6 +315,15 @@
return ENABLE_GRID_ONLY_OVERVIEW.get() || Flags.enableGridOnlyOverview();
}
+ // Aconfig migration complete for ENABLE_OVERVIEW_ICON_MENU.
+ @VisibleForTesting
+ public static final BooleanFlag ENABLE_OVERVIEW_ICON_MENU = getDebugFlag(257950105,
+ "ENABLE_OVERVIEW_ICON_MENU", TEAMFOOD,
+ "Enable updated overview icon and menu within task.");
+ public static boolean enableOverviewIconMenu() {
+ return ENABLE_OVERVIEW_ICON_MENU.get() || Flags.enableOverviewIconMenu();
+ }
+
// Aconfig migration complete for ENABLE_CURSOR_HOVER_STATES.
@VisibleForTesting
public static final BooleanFlag ENABLE_CURSOR_HOVER_STATES = getDebugFlag(243191650,
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index 307052a..3e77c78 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -19,8 +19,6 @@
import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.app.animation.Interpolators.LINEAR;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_DOWNLOAD_APP_UX_V2;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_DOWNLOAD_APP_UX_V3;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -76,10 +74,8 @@
// Duration = COMPLETE_ANIM_FRACTION * DURATION_SCALE
private static final float COMPLETE_ANIM_FRACTION = 1f;
- private static final float SMALL_SCALE = ENABLE_DOWNLOAD_APP_UX_V3.get() ? 0.8f : 0.7f;
- private static final float PROGRESS_STROKE_SCALE = ENABLE_DOWNLOAD_APP_UX_V2.get()
- ? 0.055f
- : 0.075f;
+ private static final float SMALL_SCALE = 0.8f;
+ private static final float PROGRESS_STROKE_SCALE = 0.055f;
private static final float PROGRESS_BOUNDS_SCALE = 0.075f;
private static final int PRELOAD_ACCENT_COLOR_INDEX = 0;
private static final int PRELOAD_BACKGROUND_COLOR_INDEX = 1;
@@ -119,8 +115,6 @@
private ObjectAnimator mCurrentAnim;
- private boolean mIsStartable;
-
public PreloadIconDrawable(ItemInfoWithIcon info, Context context) {
this(
info,
@@ -144,9 +138,7 @@
mProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
- if (ENABLE_DOWNLOAD_APP_UX_V3.get()) {
- mProgressPaint.setAlpha(MAX_PAINT_ALPHA);
- }
+ mProgressPaint.setAlpha(MAX_PAINT_ALPHA);
mIndicatorColor = indicatorColor;
// This is the color
@@ -181,9 +173,6 @@
mIconScaleMultiplier.updateValue(info.getProgressLevel() == 0 ? 0 : 1);
setLevel(info.getProgressLevel());
- if (!ENABLE_DOWNLOAD_APP_UX_V2.get()) {
- setIsStartable(info.isAppStartable());
- }
}
@Override
@@ -212,54 +201,31 @@
return;
}
- if (mInternalStateProgress > 0
- && (ENABLE_DOWNLOAD_APP_UX_V3.get() || !ENABLE_DOWNLOAD_APP_UX_V2.get())) {
+ if (mInternalStateProgress > 0) {
// Draw background.
- mProgressPaint.setStyle(ENABLE_DOWNLOAD_APP_UX_V3.get()
- ? Paint.Style.FILL
- : Paint.Style.FILL_AND_STROKE);
- mProgressPaint.setColor(ENABLE_DOWNLOAD_APP_UX_V3.get()
- ? mPlateColor
- : mSystemBackgroundColor);
+ mProgressPaint.setStyle(Paint.Style.FILL);
+ mProgressPaint.setColor(mPlateColor);
canvas.drawPath(mScaledTrackPath, mProgressPaint);
}
- if (!ENABLE_DOWNLOAD_APP_UX_V2.get() || mInternalStateProgress > 0) {
+ if (mInternalStateProgress > 0) {
// Draw track and progress.
mProgressPaint.setStyle(Paint.Style.STROKE);
- mProgressPaint.setColor(ENABLE_DOWNLOAD_APP_UX_V3.get()
- ? mTrackColor
- : mSystemAccentColor);
- if (!ENABLE_DOWNLOAD_APP_UX_V3.get()) {
- mProgressPaint.setAlpha(TRACK_ALPHA);
- }
+ mProgressPaint.setColor(mTrackColor);
canvas.drawPath(mScaledTrackPath, mProgressPaint);
mProgressPaint.setAlpha(MAX_PAINT_ALPHA);
- if (ENABLE_DOWNLOAD_APP_UX_V3.get()) {
- mProgressPaint.setColor(mProgressColor);
- }
+ mProgressPaint.setColor(mProgressColor);
canvas.drawPath(mScaledProgressPath, mProgressPaint);
}
int saveCount = canvas.save();
- float scale = ENABLE_DOWNLOAD_APP_UX_V2.get()
- ? 1 - mIconScaleMultiplier.value * (1 - SMALL_SCALE)
- : SMALL_SCALE;
+ float scale = 1 - mIconScaleMultiplier.value * (1 - SMALL_SCALE);
canvas.scale(scale, scale, bounds.exactCenterX(), bounds.exactCenterY());
super.drawInternal(canvas, bounds);
canvas.restoreToCount(saveCount);
}
- @Override
- protected void updateFilter() {
- if (!ENABLE_DOWNLOAD_APP_UX_V2.get()) {
- setAlpha(mIsDisabled ? DISABLED_ICON_ALPHA : MAX_PAINT_ALPHA);
- } else {
- super.updateFilter();
- }
- }
-
/**
* Updates the install progress based on the level
*/
@@ -296,14 +262,6 @@
return !mRanFinishAnimation;
}
- /** Sets whether this icon should display the startable app UI. */
- public void setIsStartable(boolean isStartable) {
- if (mIsStartable != isStartable) {
- mIsStartable = isStartable;
- setIsDisabled(!isStartable);
- }
- }
-
private void updateInternalState(
float finalProgress, boolean isFinish, Runnable onFinishCallback) {
if (mCurrentAnim != null) {
@@ -355,7 +313,7 @@
*/
private void setInternalProgress(float progress) {
// Animate scale and alpha from pending to downloading state.
- if (ENABLE_DOWNLOAD_APP_UX_V2.get() && progress > 0 && mInternalStateProgress == 0) {
+ if (progress > 0 && mInternalStateProgress == 0) {
// Progress is changing for the first time, animate the icon scale
Animator iconScaleAnimator = mIconScaleMultiplier.animateToValue(1);
iconScaleAnimator.setDuration(SCALE_AND_ALPHA_ANIM_DURATION);
@@ -365,14 +323,11 @@
mInternalStateProgress = progress;
if (progress <= 0) {
- if (!ENABLE_DOWNLOAD_APP_UX_V2.get()) {
- mScaledTrackPath.reset();
- }
mIconScaleMultiplier.updateValue(0);
} else {
mPathMeasure.getSegment(
0, Math.min(progress, 1) * mTrackLength, mScaledProgressPath, true);
- if (progress > 1 && ENABLE_DOWNLOAD_APP_UX_V2.get()) {
+ if (progress > 1) {
// map the scale back to original value
mIconScaleMultiplier.updateValue(Utilities.mapBoundToRange(
progress - 1, 0, COMPLETE_ANIM_FRACTION, 1, 0, EMPHASIZED));
diff --git a/src/com/android/launcher3/logging/StartupLatencyLogger.kt b/src/com/android/launcher3/logging/StartupLatencyLogger.kt
index 93e9de5..7d7564b 100644
--- a/src/com/android/launcher3/logging/StartupLatencyLogger.kt
+++ b/src/com/android/launcher3/logging/StartupLatencyLogger.kt
@@ -30,6 +30,11 @@
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
var workspaceLoadStartTime: Long = UNSET_LONG
+ // StartupLatencyLogger should only send launcher startup logs once in each launcher activity
+ // lifecycle. After launcher activity startup is completed, the logger should be torn down and
+ // reject all logging calls. This flag should be checked at all APIs to prevent logging invalid
+ // startup metrics (such as loading workspace in screen rotation).
+ var isTornDown = false
private var isInTest = false
/** Subclass can override this method to handle collected latency metrics. */
@@ -45,6 +50,9 @@
@MainThread
fun logWorkspaceLoadStartTime(startTimeMs: Long): StartupLatencyLogger {
Preconditions.assertUIThread()
+ if (isTornDown) {
+ return this
+ }
workspaceLoadStartTime = startTimeMs
return this
}
@@ -56,6 +64,9 @@
@MainThread
fun logCardinality(cardinality: Int): StartupLatencyLogger {
Preconditions.assertUIThread()
+ if (isTornDown) {
+ return this
+ }
this.cardinality = cardinality
return this
}
@@ -67,6 +78,9 @@
fun logStart(event: LauncherLatencyEvent, startTimeMs: Long): StartupLatencyLogger {
// In unit test no looper is attached to current thread
Preconditions.assertUIThread()
+ if (isTornDown) {
+ return this
+ }
if (validateLoggingEventAtStart(event)) {
startTimeByEvent.put(event.id, startTimeMs)
}
@@ -80,6 +94,9 @@
fun logEnd(event: LauncherLatencyEvent, endTimeMs: Long): StartupLatencyLogger {
// In unit test no looper is attached to current thread
Preconditions.assertUIThread()
+ if (isTornDown) {
+ return this
+ }
maybeLogStartOfWorkspaceLoadTime(event)
if (validateLoggingEventAtEnd(event)) {
endTimeByEvent.put(event.id, endTimeMs)
@@ -96,6 +113,7 @@
endTimeByEvent.clear()
cardinality = UNSET_INT
workspaceLoadStartTime = UNSET_LONG
+ isTornDown = true
}
@MainThread
@@ -181,6 +199,15 @@
"Cannot end ${event.name} event after ${LauncherLatencyEvent.LAUNCHER_LATENCY_STARTUP_TOTAL_DURATION.name}",
)
return false
+ } else if (
+ latencyType == LatencyType.COLD_DEVICE_REBOOTING &&
+ event == LauncherLatencyEvent.LAUNCHER_LATENCY_STARTUP_WORKSPACE_LOADER_SYNC
+ ) {
+ Log.e(
+ TAG,
+ "Cannot have ${LauncherLatencyEvent.LAUNCHER_LATENCY_STARTUP_WORKSPACE_LOADER_SYNC.name} in ${LatencyType.COLD_DEVICE_REBOOTING.name} startup type"
+ )
+ return false
}
return true
}
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 1917ba2..37a7171 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -44,7 +44,6 @@
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.ShortcutRequest;
-import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ItemInfoMatcher;
@@ -68,7 +67,8 @@
*/
public class PackageUpdatedTask extends BaseModelUpdateTask {
- private static boolean DEBUG = false;
+ // TODO(b/290090023): Set to false after root causing is done.
+ private static final boolean DEBUG = true;
private static final String TAG = "PackageUpdatedTask";
public static final int OP_NONE = 0;
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index c356da9..d434ad2 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -27,6 +27,7 @@
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
+import static com.android.launcher3.config.FeatureFlags.enableOverviewIconMenu;
import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
@@ -267,13 +268,19 @@
@Override
public float getTaskMenuX(float x, View thumbnailView,
- DeviceProfile deviceProfile, float taskInsetMargin) {
+ DeviceProfile deviceProfile, float taskInsetMargin, View taskViewIcon) {
+ if (enableOverviewIconMenu()) {
+ return x - (taskInsetMargin / 2f);
+ }
return thumbnailView.getMeasuredWidth() + x - taskInsetMargin;
}
@Override
public float getTaskMenuY(float y, View thumbnailView, int stagePosition,
- View taskMenuView, float taskInsetMargin) {
+ View taskMenuView, float taskInsetMargin, View taskViewIcon) {
+ if (enableOverviewIconMenu()) {
+ return y - taskMenuView.getMeasuredHeight() - taskInsetMargin;
+ }
BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskMenuView.getLayoutParams();
int taskMenuWidth = lp.width;
if (stagePosition == STAGE_POSITION_UNDEFINED) {
@@ -537,14 +544,25 @@
}
@Override
+ public void setTaskIconMenuParams(FrameLayout.LayoutParams iconMenuParams, int iconMenuMargin,
+ int thumbnailTopMargin) {
+ iconMenuParams.gravity = END | TOP;
+ iconMenuParams.setMarginStart(0);
+ iconMenuParams.topMargin = iconMenuParams.width + iconMenuMargin;
+ iconMenuParams.bottomMargin = 0;
+ iconMenuParams.setMarginEnd(iconMenuMargin);
+ }
+
+ @Override
public void setSplitIconParams(View primaryIconView, View secondaryIconView,
int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
DeviceProfile deviceProfile, SplitBounds splitConfig) {
FrameLayout.LayoutParams primaryIconParams =
(FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
- FrameLayout.LayoutParams secondaryIconParams =
- new FrameLayout.LayoutParams(primaryIconParams);
+ FrameLayout.LayoutParams secondaryIconParams = enableOverviewIconMenu()
+ ? (FrameLayout.LayoutParams) secondaryIconView.getLayoutParams()
+ : new FrameLayout.LayoutParams(primaryIconParams);
// We calculate the "midpoint" of the thumbnail area, and place the icons there.
// This is the place where the thumbnail area splits by default, in a near-50/50 split.
@@ -560,11 +578,17 @@
int bottomToMidpointOffset = (int) (overviewThumbnailAreaThickness * midpointFromBottomPct);
int insetOffset = (int) (overviewThumbnailAreaThickness * insetPct);
- primaryIconParams.gravity = BOTTOM | (isRtl ? START : END);
- secondaryIconParams.gravity = BOTTOM | (isRtl ? START : END);
+ primaryIconParams.gravity = enableOverviewIconMenu() ? TOP | (isRtl ? START : END)
+ : BOTTOM | (isRtl ? START : END);
+ secondaryIconParams.gravity = enableOverviewIconMenu() ? TOP | (isRtl ? START : END)
+ : BOTTOM | (isRtl ? START : END);
primaryIconView.setTranslationX(0);
secondaryIconView.setTranslationX(0);
- if (splitConfig.initiatedFromSeascape) {
+ if (enableOverviewIconMenu()) {
+ int dividerThickness = Math.min(splitConfig.visualDividerBounds.width(),
+ splitConfig.visualDividerBounds.height());
+ secondaryIconView.setTranslationY(primarySnapshotHeight + dividerThickness);
+ } else if (splitConfig.initiatedFromSeascape) {
// if the split was initiated from seascape,
// the task on the right (secondary) is slightly larger
primaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset);
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index 39ef129..0069d9b 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -173,6 +173,8 @@
// Overview TaskMenuView methods
void setTaskIconParams(FrameLayout.LayoutParams iconParams,
int taskIconMargin, int taskIconHeight, int thumbnailTopMargin, boolean isRtl);
+ void setTaskIconMenuParams(FrameLayout.LayoutParams iconMenuParams, int iconMenuMargin,
+ int thumbnailTopMargin);
void setSplitIconParams(View primaryIconView, View secondaryIconView,
int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
@@ -185,9 +187,9 @@
* getTaskMenuWidth()), so we directly use that in the calculations.
*/
float getTaskMenuX(float x, View thumbnailView, DeviceProfile deviceProfile,
- float taskInsetMargin);
+ float taskInsetMargin, View taskViewIcon);
float getTaskMenuY(float y, View thumbnailView, int stagePosition,
- View taskMenuView, float taskInsetMargin);
+ View taskMenuView, float taskInsetMargin, View taskViewIcon);
int getTaskMenuWidth(View thumbnailView, DeviceProfile deviceProfile,
@StagePosition int stagePosition);
/**
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index dc4621e..b3189b7 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -21,11 +21,13 @@
import static android.view.Gravity.END;
import static android.view.Gravity.START;
import static android.view.Gravity.TOP;
+import static android.view.View.LAYOUT_DIRECTION_RTL;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
+import static com.android.launcher3.config.FeatureFlags.enableOverviewIconMenu;
import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
@@ -264,8 +266,11 @@
@Override
public float getTaskMenuX(float x, View thumbnailView,
- DeviceProfile deviceProfile, float taskInsetMargin) {
- if (deviceProfile.isLandscape) {
+ DeviceProfile deviceProfile, float taskInsetMargin, View taskViewIcon) {
+ if (enableOverviewIconMenu()) {
+ return x + (thumbnailView.getLayoutDirection() == LAYOUT_DIRECTION_RTL
+ ? -(taskViewIcon.getWidth() / 2f) : 0);
+ } else if (deviceProfile.isLandscape) {
return x + taskInsetMargin
+ (thumbnailView.getMeasuredWidth() - thumbnailView.getMeasuredHeight()) / 2f;
} else {
@@ -275,13 +280,22 @@
@Override
public float getTaskMenuY(float y, View thumbnailView, int stagePosition,
- View taskMenuView, float taskInsetMargin) {
+ View taskMenuView, float taskInsetMargin, View taskViewIcon) {
+ if (enableOverviewIconMenu()) {
+ return y;
+ }
return y + taskInsetMargin;
}
@Override
public int getTaskMenuWidth(View thumbnailView, DeviceProfile deviceProfile,
@StagePosition int stagePosition) {
+ if (enableOverviewIconMenu()) {
+ int padding = thumbnailView.getResources().getDimensionPixelSize(
+ R.dimen.task_menu_vertical_padding);
+ return thumbnailView.getResources().getDimensionPixelSize(
+ R.dimen.task_thumbnail_icon_menu_max_width) + (2 * padding);
+ }
return deviceProfile.isLandscape && !deviceProfile.isTablet
? thumbnailView.getMeasuredHeight()
: thumbnailView.getMeasuredWidth();
@@ -689,16 +703,53 @@
}
@Override
+ public void setTaskIconMenuParams(FrameLayout.LayoutParams iconMenuParams, int iconMenuMargin,
+ int thumbnailTopMargin) {
+ iconMenuParams.gravity = TOP | START;
+ iconMenuParams.setMarginStart(iconMenuMargin);
+ iconMenuParams.topMargin = iconMenuMargin;
+ iconMenuParams.bottomMargin = 0;
+ iconMenuParams.setMarginEnd(0);
+ }
+
+ @Override
public void setSplitIconParams(View primaryIconView, View secondaryIconView,
int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
DeviceProfile deviceProfile, SplitBounds splitConfig) {
FrameLayout.LayoutParams primaryIconParams =
(FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
- FrameLayout.LayoutParams secondaryIconParams =
- new FrameLayout.LayoutParams(primaryIconParams);
+ FrameLayout.LayoutParams secondaryIconParams = enableOverviewIconMenu()
+ ? (FrameLayout.LayoutParams) secondaryIconView.getLayoutParams()
+ : new FrameLayout.LayoutParams(primaryIconParams);
- if (deviceProfile.isLandscape) {
+ if (enableOverviewIconMenu()) {
+ primaryIconParams.gravity = TOP | START;
+ secondaryIconParams.gravity = TOP | START;
+ secondaryIconParams.topMargin = primaryIconParams.topMargin;
+ secondaryIconParams.setMarginStart(primaryIconParams.getMarginStart());
+ if (deviceProfile.isLandscape) {
+ int fullscreenInsetThickness = deviceProfile.isSeascape()
+ ? deviceProfile.getInsets().right
+ : deviceProfile.getInsets().left;
+ int fullscreenMidpointFromBottom = ((deviceProfile.widthPx
+ - fullscreenInsetThickness) / 2);
+ float midpointFromEndPct = (float) fullscreenMidpointFromBottom
+ / deviceProfile.widthPx;
+ int bottomToMidpointOffset = (int) (groupedTaskViewWidth * midpointFromEndPct);
+ if (isRtl) {
+ primaryIconView.setTranslationX(-bottomToMidpointOffset);
+ } else {
+ secondaryIconView.setTranslationX(bottomToMidpointOffset);
+ }
+ } else {
+ secondaryIconView.setTranslationX(0);
+ int dividerThickness = Math.min(splitConfig.visualDividerBounds.width(),
+ splitConfig.visualDividerBounds.height());
+ secondaryIconView.setTranslationY(
+ primarySnapshotHeight + (deviceProfile.isTablet ? 0 : dividerThickness));
+ }
+ } else if (deviceProfile.isLandscape) {
// We calculate the "midpoint" of the thumbnail area, and place the icons there.
// This is the place where the thumbnail area splits by default, in a near-50/50 split.
// It is usually not exactly 50/50, due to insets/screen cutouts.
@@ -754,8 +805,10 @@
secondaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
secondaryIconView.setTranslationX(taskIconHeight / 2f);
}
- primaryIconView.setTranslationY(0);
- secondaryIconView.setTranslationY(0);
+ if (!enableOverviewIconMenu()) {
+ primaryIconView.setTranslationY(0);
+ secondaryIconView.setTranslationY(0);
+ }
primaryIconView.setLayoutParams(primaryIconParams);
secondaryIconView.setLayoutParams(secondaryIconParams);
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
index ec01231..dac7964 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -22,6 +22,7 @@
import static android.view.Gravity.RIGHT;
import static android.view.Gravity.START;
+import static com.android.launcher3.config.FeatureFlags.enableOverviewIconMenu;
import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
@@ -86,13 +87,19 @@
@Override
public float getTaskMenuX(float x, View thumbnailView,
- DeviceProfile deviceProfile, float taskInsetMargin) {
+ DeviceProfile deviceProfile, float taskInsetMargin, View taskViewIcon) {
+ if (enableOverviewIconMenu()) {
+ return x + taskViewIcon.getHeight() + taskInsetMargin * 2;
+ }
return x + taskInsetMargin;
}
@Override
public float getTaskMenuY(float y, View thumbnailView, int stagePosition,
- View taskMenuView, float taskInsetMargin) {
+ View taskMenuView, float taskInsetMargin, View taskViewIcon) {
+ if (enableOverviewIconMenu()) {
+ return y + taskViewIcon.getWidth() - taskViewIcon.getHeight();
+ }
BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskMenuView.getLayoutParams();
int taskMenuWidth = lp.width;
if (stagePosition == STAGE_POSITION_UNDEFINED) {
@@ -208,13 +215,24 @@
public void setTaskIconParams(FrameLayout.LayoutParams iconParams,
int taskIconMargin, int taskIconHeight, int thumbnailTopMargin, boolean isRtl) {
iconParams.gravity = (isRtl ? END : START) | CENTER_VERTICAL;
- iconParams.leftMargin = -taskIconHeight - taskIconMargin / 2;
+ iconParams.leftMargin =
+ enableOverviewIconMenu() ? 0 : -taskIconHeight - taskIconMargin / 2;
iconParams.rightMargin = 0;
- iconParams.topMargin = thumbnailTopMargin / 2;
+ iconParams.topMargin = enableOverviewIconMenu() ? 0 : thumbnailTopMargin / 2;
iconParams.bottomMargin = 0;
}
@Override
+ public void setTaskIconMenuParams(FrameLayout.LayoutParams iconMenuParams, int iconMenuMargin,
+ int thumbnailTopMargin) {
+ iconMenuParams.gravity = BOTTOM | START;
+ iconMenuParams.setMarginStart(0);
+ iconMenuParams.topMargin = 0;
+ iconMenuParams.bottomMargin = 0;
+ iconMenuParams.setMarginEnd(0);
+ }
+
+ @Override
public void setSplitIconParams(View primaryIconView, View secondaryIconView,
int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
@@ -245,7 +263,11 @@
secondaryIconParams.gravity = BOTTOM | (isRtl ? END : START);
primaryIconView.setTranslationX(0);
secondaryIconView.setTranslationX(0);
- if (splitConfig.initiatedFromSeascape) {
+ if (enableOverviewIconMenu()) {
+ int dividerThickness = Math.min(splitConfig.visualDividerBounds.width(),
+ splitConfig.visualDividerBounds.height());
+ secondaryIconView.setTranslationY(-primarySnapshotHeight - dividerThickness);
+ } else if (splitConfig.initiatedFromSeascape) {
// if the split was initiated from seascape,
// the task on the right (secondary) is slightly larger
primaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index dcc86a1..742d2dc 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -16,7 +16,6 @@
package com.android.launcher3.widget;
import static com.android.app.animation.Interpolators.EMPHASIZED;
-import static com.android.launcher3.config.FeatureFlags.LARGE_SCREEN_WIDGET_PICKER;
import android.content.Context;
import android.graphics.Canvas;
@@ -194,9 +193,7 @@
int widthUsed;
if (deviceProfile.isTablet) {
int margin = deviceProfile.allAppsLeftRightMargin;
- if (deviceProfile.isLandscape
- && LARGE_SCREEN_WIDGET_PICKER.get()
- && !deviceProfile.isTwoPanels) {
+ if (deviceProfile.isLandscape && !deviceProfile.isTwoPanels) {
margin = getResources().getDimensionPixelSize(
R.dimen.widget_picker_landscape_tablet_left_right_margin);
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 4105a9a..2c094f2 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -18,7 +18,6 @@
import static android.view.View.MeasureSpec.makeMeasureSpec;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
-import static com.android.launcher3.config.FeatureFlags.LARGE_SCREEN_WIDGET_PICKER;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_SEARCHED;
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
@@ -679,8 +678,7 @@
/** Shows the {@link WidgetsFullSheet} on the launcher. */
public static WidgetsFullSheet show(Launcher launcher, boolean animate) {
- boolean isTwoPane = LARGE_SCREEN_WIDGET_PICKER.get()
- && launcher.getDeviceProfile().isTablet
+ boolean isTwoPane = launcher.getDeviceProfile().isTablet
&& launcher.getDeviceProfile().isLandscape
&& (!launcher.getDeviceProfile().isTwoPanels
|| FeatureFlags.UNFOLDED_WIDGET_PICKER.get());
@@ -798,8 +796,7 @@
// Checks the orientation of the screen
if (mOrientation != newConfig.orientation) {
mOrientation = newConfig.orientation;
- if (LARGE_SCREEN_WIDGET_PICKER.get()
- && mDeviceProfile.isTablet && !mDeviceProfile.isTwoPanels) {
+ if (mDeviceProfile.isTablet && !mDeviceProfile.isTwoPanels) {
handleClose(false);
show(Launcher.getLauncher(getContext()), false);
} else {
diff --git a/tests/Android.bp b/tests/Android.bp
index 654edad..62d232c 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -49,6 +49,7 @@
"src/com/android/launcher3/ui/AbstractLauncherUiTest.java",
"src/com/android/launcher3/ui/PortraitLandscapeRunner.java",
"src/com/android/launcher3/ui/TaplTestsLauncher3.java",
+ "src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java",
"src/com/android/launcher3/util/LauncherLayoutBuilder.java",
"src/com/android/launcher3/util/TestUtil.java",
"src/com/android/launcher3/util/Wait.java",
@@ -58,6 +59,7 @@
"src/com/android/launcher3/util/rule/SamplerRule.java",
"src/com/android/launcher3/util/rule/ScreenRecordRule.java",
"src/com/android/launcher3/util/rule/ShellCommandRule.java",
+ "src/com/android/launcher3/util/rule/TestIsolationRule.java",
"src/com/android/launcher3/util/rule/TestStabilityRule.java",
"src/com/android/launcher3/util/rule/TISBindRule.java",
"src/com/android/launcher3/util/viewcapture_analysis/*.java",
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
index b8f4c0b..ec32680 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
@@ -108,6 +108,7 @@
overviewTaskIconSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+ overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
overviewActionsTopMarginPx: 0.0px (0.0dp)
overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
index a512277..d69be3f 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
@@ -108,6 +108,7 @@
overviewTaskIconSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+ overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
overviewActionsTopMarginPx: 0.0px (0.0dp)
overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
index a3a8dc5..7e92620 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
@@ -108,6 +108,7 @@
overviewTaskIconSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+ overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
overviewActionsTopMarginPx: 0.0px (0.0dp)
overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
index 55066cb..a9bee2b 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
@@ -108,6 +108,7 @@
overviewTaskIconSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+ overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
overviewActionsTopMarginPx: 0.0px (0.0dp)
overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt
index 6e764c2..42b022b 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt
@@ -108,6 +108,7 @@
overviewTaskIconSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+ overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
overviewActionsTopMarginPx: 0.0px (0.0dp)
overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt
index 7650082..53f8580 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt
@@ -108,6 +108,7 @@
overviewTaskIconSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+ overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
overviewActionsTopMarginPx: 0.0px (0.0dp)
overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt
index 2b241a1..87189fa 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt
@@ -108,6 +108,7 @@
overviewTaskIconSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+ overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
overviewActionsTopMarginPx: 0.0px (0.0dp)
overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt
index 6d38d27..0ade560 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt
@@ -108,6 +108,7 @@
overviewTaskIconSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+ overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
overviewActionsTopMarginPx: 0.0px (0.0dp)
overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt
index 5799de7..d24457d 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt
@@ -108,6 +108,7 @@
overviewTaskIconSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+ overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
overviewActionsTopMarginPx: 0.0px (0.0dp)
overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt
index b4956ff..38dc2c9 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt
@@ -108,6 +108,7 @@
overviewTaskIconSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+ overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
overviewActionsTopMarginPx: 0.0px (0.0dp)
overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt
index 15afb61..5d23147 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt
@@ -108,6 +108,7 @@
overviewTaskIconSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+ overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
overviewActionsTopMarginPx: 0.0px (0.0dp)
overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt
index 6cbed1f..5b53509 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt
@@ -108,6 +108,7 @@
overviewTaskIconSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
+ overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
overviewActionsTopMarginPx: 0.0px (0.0dp)
overviewActionsHeight: 0.0px (0.0dp)
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index f5aa820..54a1c08 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -126,6 +126,7 @@
"taskbar-all-apps-top-padding";
public static final String REQUEST_ALL_APPS_TOP_PADDING = "all-apps-top-padding";
public static final String REQUEST_ALL_APPS_BOTTOM_PADDING = "all-apps-bottom-padding";
+ public static final String REQUEST_REFRESH_OVERVIEW_TARGET = "refresh-overview-target";
public static final String REQUEST_WORKSPACE_CELL_LAYOUT_SIZE = "workspace-cell-layout-size";
public static final String REQUEST_WORKSPACE_CELL_CENTER = "workspace-cell-center";
diff --git a/tests/src/com/android/launcher3/allapps/OopTaplOpenCloseAllApps.java b/tests/src/com/android/launcher3/allapps/OopTaplOpenCloseAllApps.java
index 7d6b7f9..f9dadaa 100644
--- a/tests/src/com/android/launcher3/allapps/OopTaplOpenCloseAllApps.java
+++ b/tests/src/com/android/launcher3/allapps/OopTaplOpenCloseAllApps.java
@@ -17,11 +17,14 @@
import static com.android.launcher3.ui.TaplTestsLauncher3.expectFail;
import static com.android.launcher3.ui.TaplTestsLauncher3.initialize;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
+import android.platform.test.annotations.PlatinumTest;
+
import com.android.launcher3.LauncherState;
import com.android.launcher3.tapl.AllApps;
import com.android.launcher3.ui.AbstractLauncherUiTest;
@@ -88,6 +91,7 @@
/**
* Make sure the swipe up gesture can take us back to the workspace from AllApps
*/
+ @PlatinumTest(focusArea = "launcher")
@Test
@PortraitLandscape
public void testAllAppsSwipeUpToWorkspace() {
diff --git a/tests/src/com/android/launcher3/appiconmenu/TaplAppIconMenuTest.java b/tests/src/com/android/launcher3/appiconmenu/TaplAppIconMenuTest.java
index 66c67f5..85cf52e 100644
--- a/tests/src/com/android/launcher3/appiconmenu/TaplAppIconMenuTest.java
+++ b/tests/src/com/android/launcher3/appiconmenu/TaplAppIconMenuTest.java
@@ -82,6 +82,7 @@
* Drag icon from AllApps to the workspace and then open the AppIconMenu and launch a shortcut
* from it.
*/
+ @PlatinumTest(focusArea = "launcher")
@Test
public void testLaunchHomeScreenMenuItem() {
// Drag the test app icon to home screen and open short cut menu from the icon
diff --git a/tests/src/com/android/launcher3/logging/StartupLatencyLoggerTest.kt b/tests/src/com/android/launcher3/logging/StartupLatencyLoggerTest.kt
index fffa6d7..a29218c 100644
--- a/tests/src/com/android/launcher3/logging/StartupLatencyLoggerTest.kt
+++ b/tests/src/com/android/launcher3/logging/StartupLatencyLoggerTest.kt
@@ -357,6 +357,7 @@
assertThat(underTest.startTimeByEvent.size()).isEqualTo(4)
assertThat(underTest.endTimeByEvent.size()).isEqualTo(4)
assertThat(underTest.cardinality).isEqualTo(235)
+ assertThat(underTest.isTornDown).isFalse()
underTest.reset()
@@ -364,5 +365,26 @@
assertThat(underTest.endTimeByEvent.isEmpty()).isTrue()
assertThat(underTest.cardinality).isEqualTo(StartupLatencyLogger.UNSET_INT)
assertThat(underTest.workspaceLoadStartTime).isEqualTo(StartupLatencyLogger.UNSET_LONG)
+ assertThat(underTest.isTornDown).isTrue()
+ }
+
+ @Test
+ @UiThreadTest
+ fun tornDown_rejectLogs() {
+ underTest.reset()
+
+ underTest
+ .logStart(
+ StatsLogManager.LauncherLatencyEvent.LAUNCHER_LATENCY_STARTUP_TOTAL_DURATION,
+ 100
+ )
+ .logEnd(
+ StatsLogManager.LauncherLatencyEvent.LAUNCHER_LATENCY_STARTUP_TOTAL_DURATION,
+ 200
+ )
+ .logCardinality(123)
+ assertThat(underTest.startTimeByEvent.isEmpty()).isTrue()
+ assertThat(underTest.endTimeByEvent.isEmpty()).isTrue()
+ assertThat(underTest.cardinality).isEqualTo(StartupLatencyLogger.UNSET_INT)
}
}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 3e5d717..e837b8b 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -18,7 +18,6 @@
import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static com.android.launcher3.testing.shared.TestProtocol.ICON_MISSING;
-import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static org.junit.Assert.assertEquals;
@@ -68,6 +67,7 @@
import com.android.launcher3.util.rule.SamplerRule;
import com.android.launcher3.util.rule.ScreenRecordRule;
import com.android.launcher3.util.rule.ShellCommandRule;
+import com.android.launcher3.util.rule.TestIsolationRule;
import com.android.launcher3.util.rule.TestStabilityRule;
import com.android.launcher3.util.rule.ViewCaptureRule;
@@ -111,15 +111,22 @@
protected String mTargetPackage;
private int mLauncherPid;
+ /** Detects activity leaks and throws an exception if a leak is found. */
public static void checkDetectedLeaks(LauncherInstrumentation launcher) {
+ checkDetectedLeaks(launcher, false);
+ }
+
+ /** Detects activity leaks and throws an exception if a leak is found. */
+ public static void checkDetectedLeaks(LauncherInstrumentation launcher,
+ boolean requireOneActiveActivity) {
if (sActivityLeakReported) return;
// Check whether activity leak detector has found leaked activities.
- Wait.atMost(() -> getActivityLeakErrorMessage(launcher),
+ Wait.atMost(() -> getActivityLeakErrorMessage(launcher, requireOneActiveActivity),
() -> {
launcher.forceGc();
return MAIN_EXECUTOR.submit(
- () -> launcher.noLeakedActivities()).get();
+ () -> launcher.noLeakedActivities(requireOneActiveActivity)).get();
}, DEFAULT_UI_TIMEOUT, launcher);
}
@@ -127,13 +134,16 @@
return getInstrumentation().getContext().getPackageName();
}
- private static String getActivityLeakErrorMessage(LauncherInstrumentation launcher) {
+ private static String getActivityLeakErrorMessage(LauncherInstrumentation launcher,
+ boolean requireOneActiveActivity) {
sActivityLeakReported = true;
- return "Activity leak detector has found leaked activities, "
- + dumpHprofData(launcher, false) + ".";
+ return "Activity leak detector has found leaked activities, requirining 1 activity: "
+ + requireOneActiveActivity + "; "
+ + dumpHprofData(launcher, false, requireOneActiveActivity) + ".";
}
- public static String dumpHprofData(LauncherInstrumentation launcher, boolean intentionalLeak) {
+ private static String dumpHprofData(LauncherInstrumentation launcher, boolean intentionalLeak,
+ boolean requireOneActiveActivity) {
if (intentionalLeak) return "intentional leak; not generating dump";
String result;
@@ -152,7 +162,7 @@
"am dumpheap " + device.getLauncherPackageName() + " " + fileName);
}
Log.d(TAG, "Saved leak dump, the leak is still present: "
- + !launcher.noLeakedActivities());
+ + !launcher.noLeakedActivities(requireOneActiveActivity));
sDumpWasGenerated = true;
result = "saved memory dump as an artifact";
} catch (Throwable e) {
@@ -210,7 +220,8 @@
final RuleChain inner = RuleChain
.outerRule(new PortraitLandscapeRunner(this))
.around(new FailureWatcher(mLauncher, viewCaptureRule::getViewCaptureData))
- .around(viewCaptureRule);
+ .around(viewCaptureRule)
+ .around(new TestIsolationRule(mLauncher, true));
return TestHelpers.isInLauncherProcess()
? RuleChain.outerRule(ShellCommandRule.setDefaultLauncher()).around(inner)
diff --git a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java b/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
index f0c4fdb..2cdcf24 100644
--- a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
+++ b/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
@@ -87,6 +87,7 @@
MockitoAnnotations.initMocks(this);
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_CURSOR_HOVER_STATES);
+ mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU);
Utilities.enableRunningInTestHarnessForTests();
mContext = new ActivityContextWrapper(getApplicationContext());
mBubbleTextView = new BubbleTextView(mContext);
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index bc53d6d..9aaca54 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -16,9 +16,6 @@
package com.android.launcher3.ui;
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -40,16 +37,11 @@
import com.android.launcher3.tapl.AppIcon;
import com.android.launcher3.tapl.HomeAllApps;
import com.android.launcher3.tapl.HomeAppIcon;
-import com.android.launcher3.tapl.Widgets;
import com.android.launcher3.tapl.Workspace;
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
import com.android.launcher3.util.LauncherLayoutBuilder;
import com.android.launcher3.util.TestUtil;
-import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import com.android.launcher3.util.rule.TISBindRule;
-import com.android.launcher3.util.rule.TestStabilityRule.Stability;
-import com.android.launcher3.widget.picker.WidgetsFullSheet;
-import com.android.launcher3.widget.picker.WidgetsRecyclerView;
import org.junit.After;
import org.junit.Before;
@@ -93,7 +85,7 @@
test.waitForResumed("Launcher internal state is still Background");
// Check that we switched to home.
test.mLauncher.getWorkspace();
- AbstractLauncherUiTest.checkDetectedLeaks(test.mLauncher);
+ AbstractLauncherUiTest.checkDetectedLeaks(test.mLauncher, true);
}
@After
@@ -122,10 +114,6 @@
return launcher.getWorkspace().getCurrentPage();
}
- private WidgetsRecyclerView getWidgetsView(Launcher launcher) {
- return WidgetsFullSheet.getWidgetsView(launcher);
- }
-
@Test
public void testDevicePressMenu() throws Exception {
mDevice.pressMenu();
@@ -208,42 +196,6 @@
runIconLaunchFromAllAppsTest(this, allApps);
}
- @Test
- @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/293191790
- @ScreenRecord
- @PortraitLandscape
- public void testWidgets() throws Exception {
- // Test opening widgets.
- executeOnLauncher(launcher ->
- assertTrue("Widgets is initially opened", getWidgetsView(launcher) == null));
- Widgets widgets = mLauncher.getWorkspace().openAllWidgets();
- assertNotNull("openAllWidgets() returned null", widgets);
- widgets = mLauncher.getAllWidgets();
- assertNotNull("getAllWidgets() returned null", widgets);
- executeOnLauncher(launcher ->
- assertTrue("Widgets is not shown", getWidgetsView(launcher).isShown()));
- executeOnLauncher(launcher -> assertEquals("Widgets is scrolled upon opening",
- 0, getWidgetsScroll(launcher)));
-
- // Test flinging widgets.
- widgets.flingForward();
- Integer flingForwardY = getFromLauncher(launcher -> getWidgetsScroll(launcher));
- executeOnLauncher(launcher -> assertTrue("Flinging forward didn't scroll widgets",
- flingForwardY > 0));
-
- widgets.flingBackward();
- executeOnLauncher(launcher -> assertTrue("Flinging backward didn't scroll widgets",
- getWidgetsScroll(launcher) < flingForwardY));
-
- mLauncher.goHome();
- waitForLauncherCondition("Widgets were not closed",
- launcher -> getWidgetsView(launcher) == null);
- }
-
- private int getWidgetsScroll(Launcher launcher) {
- return getWidgetsView(launcher).computeVerticalScrollOffset();
- }
-
@FlakyTest(bugId = 256615483)
@Test
@PortraitLandscape
diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
index 64ab206..fd4b7f1 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.ui.widget;
-import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
import static org.junit.Assert.assertNotNull;
import android.platform.test.annotations.PlatinumTest;
@@ -99,6 +98,7 @@
/**
* Test dragging a widget to the workspace and resize it.
*/
+ @PlatinumTest(focusArea = "launcher")
@Test
public void testResizeWidget() throws Throwable {
new FavoriteItemsTransaction(mTargetContext).commitAndLoadHome(mLauncher);
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java b/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java
new file mode 100644
index 0000000..a5e9868
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.ui.widget;
+
+import static com.android.launcher3.ui.TaplTestsLauncher3.initialize;
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.tapl.Widgets;
+import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
+import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
+import com.android.launcher3.util.rule.TestStabilityRule.Stability;
+import com.android.launcher3.widget.picker.WidgetsFullSheet;
+import com.android.launcher3.widget.picker.WidgetsRecyclerView;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * This test run in both Out of process (Oop) and in-process (Ipc).
+ * Make sure the basic interactions with the WidgetPicker works.
+ */
+public class TaplWidgetPickerTest extends AbstractLauncherUiTest {
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ initialize(this);
+ }
+
+ private WidgetsRecyclerView getWidgetsView(Launcher launcher) {
+ return WidgetsFullSheet.getWidgetsView(launcher);
+ }
+
+ private int getWidgetsScroll(Launcher launcher) {
+ return getWidgetsView(launcher).computeVerticalScrollOffset();
+ }
+
+ /**
+ * Open Widget picker, make sure the widget picker can scroll and then go to home screen.
+ */
+ @Test
+ @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/293191790
+ @ScreenRecord
+ @PortraitLandscape
+ public void testWidgets() {
+ // Test opening widgets.
+ executeOnLauncher(launcher ->
+ assertTrue("Widgets is initially opened", getWidgetsView(launcher) == null));
+ Widgets widgets = mLauncher.getWorkspace().openAllWidgets();
+ assertNotNull("openAllWidgets() returned null", widgets);
+ widgets = mLauncher.getAllWidgets();
+ assertNotNull("getAllWidgets() returned null", widgets);
+ executeOnLauncher(launcher ->
+ assertTrue("Widgets is not shown", getWidgetsView(launcher).isShown()));
+ executeOnLauncher(launcher -> assertEquals("Widgets is scrolled upon opening",
+ 0, getWidgetsScroll(launcher)));
+
+ // Test flinging widgets.
+ widgets.flingForward();
+ Integer flingForwardY = getFromLauncher(launcher -> getWidgetsScroll(launcher));
+ executeOnLauncher(launcher -> assertTrue("Flinging forward didn't scroll widgets",
+ flingForwardY > 0));
+
+ widgets.flingBackward();
+ executeOnLauncher(launcher -> assertTrue("Flinging backward didn't scroll widgets",
+ getWidgetsScroll(launcher) < flingForwardY));
+
+ mLauncher.goHome();
+ waitForLauncherCondition("Widgets were not closed",
+ launcher -> getWidgetsView(launcher) == null);
+ }
+}
diff --git a/tests/src/com/android/launcher3/util/rule/TestIsolationRule.java b/tests/src/com/android/launcher3/util/rule/TestIsolationRule.java
new file mode 100644
index 0000000..2b45902
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/rule/TestIsolationRule.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.util.rule;
+
+import androidx.annotation.NonNull;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.uiautomator.UiDevice;
+
+import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.ui.AbstractLauncherUiTest;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * Isolates tests from some of the state created by the previous test.
+ */
+public class TestIsolationRule implements TestRule {
+ private final LauncherInstrumentation mLauncher;
+ private final boolean mRequireOneActiveActivity;
+
+ public TestIsolationRule(LauncherInstrumentation launcher, boolean requireOneActiveActivity) {
+ mLauncher = launcher;
+ mRequireOneActiveActivity = requireOneActiveActivity;
+ }
+
+ @NonNull
+ @Override
+ public Statement apply(@NonNull Statement base, @NonNull Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ base.evaluate();
+ // Make sure that Launcher workspace looks correct.
+
+ UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()).pressHome();
+ AbstractLauncherUiTest.checkDetectedLeaks(mLauncher, mRequireOneActiveActivity);
+ }
+ };
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index b82fa35..dbb3cc3 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -16,6 +16,8 @@
package com.android.launcher3.tapl;
+import static android.view.KeyEvent.KEYCODE_META_RIGHT;
+
import static com.android.launcher3.tapl.LauncherInstrumentation.DEFAULT_POLL_INTERVAL;
import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS;
@@ -370,6 +372,17 @@
}
}
+ /** Presses the meta keyboard shortcut to dismiss AllApps. */
+ public void dismissByKeyboardShortcut() {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+ mLauncher.getDevice().pressKeyCode(KEYCODE_META_RIGHT);
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "pressed meta key")) {
+ verifyVisibleContainerOnDismiss();
+ }
+ }
+ }
+
protected abstract void verifyVisibleContainerOnDismiss();
/**
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 130bd3a..d7f9c78 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -704,6 +704,7 @@
/**
* Set the trackpad gesture type of the interaction.
+ *
* @param trackpadGestureType whether it's not from trackpad, two-finger, three-finger, or
* four-finger gesture.
*/
@@ -1343,6 +1344,16 @@
}
}
+ void waitForObjectFocused(UiObject2 object, String waitReason) {
+ try {
+ assertTrue("Timed out waiting for object to be focused for " + waitReason + " "
+ + object.getResourceName(),
+ object.wait(Until.focused(true), WAIT_TIME_MS));
+ } catch (StaleObjectException e) {
+ fail("The object disappeared from screen");
+ }
+ }
+
@NonNull
UiObject2 waitForObjectInContainer(UiObject2 container, BySelector selector) {
return waitForObjectsInContainer(container, selector).get(0);
@@ -1779,7 +1790,6 @@
private void injectEvent(InputEvent event) {
assertTrue("injectInputEvent failed: event=" + event,
mInstrumentation.getUiAutomation().injectInputEvent(event, true, false));
- event.recycle();
}
public void sendPointer(long downTime, long currentTime, int action, Point point,
@@ -1812,8 +1822,8 @@
final MotionEvent event = isTrackpadGesture
? getTrackpadMotionEvent(
- downTime, currentTime, action, point.x, point.y, pointerCount,
- mTrackpadGestureType)
+ downTime, currentTime, action, point.x, point.y, pointerCount,
+ mTrackpadGestureType)
: getMotionEvent(downTime, currentTime, action, point.x, point.y, source);
if (action == MotionEvent.ACTION_BUTTON_PRESS
|| action == MotionEvent.ACTION_BUTTON_RELEASE) {
@@ -2043,6 +2053,12 @@
getTestInfo(TestProtocol.REQUEST_RECREATE_TASKBAR);
}
+ // TODO(b/270393900): Remove with ENABLE_ALL_APPS_SEARCH_IN_TASKBAR flag cleanup.
+ /** Refreshes the known overview target in TIS. */
+ public void refreshOverviewTarget() {
+ getTestInfo(TestProtocol.REQUEST_REFRESH_OVERVIEW_TARGET);
+ }
+
public List<String> getHotseatIconNames() {
return getTestInfo(TestProtocol.REQUEST_HOTSEAT_ICON_NAMES)
.getStringArrayList(TestProtocol.TEST_INFO_RESPONSE_FIELD);
@@ -2057,14 +2073,16 @@
return String.join(", ", getActivities());
}
- public boolean noLeakedActivities() {
+ /** Returns whether no leaked activities are detected. */
+ public boolean noLeakedActivities(boolean requireOneActiveActivity) {
final String[] activities = getActivities();
+
for (String activity : activities) {
if (activity.contains("(destroyed)")) {
return false;
}
}
- return activities.length <= 2;
+ return activities.length <= (requireOneActiveActivity ? 1 : 2);
}
public int getActivitiesCreated() {
@@ -2202,6 +2220,8 @@
containerBounds.bottom,
getRealDisplaySize().y - getImeInsets().bottom);
int y = (bottomBound - containerBounds.top) / 2;
+ // Do not tap in the status bar.
+ y = Math.max(y, getWindowInsets().top);
final long downTime = SystemClock.uptimeMillis();
final Point tapTarget = new Point(x, y);
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index e4cfc52..95a4802 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -168,7 +168,7 @@
}
}
- /** Taps the task menu. */
+ /** Taps the task menu. Returns the task menu object. */
@NonNull
public OverviewTaskMenu tapMenu() {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
@@ -184,6 +184,22 @@
}
}
+ /** Taps the task menu of the split task. Returns the split task's menu object. */
+ @NonNull
+ public OverviewTaskMenu tapSplitTaskMenu() {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to tap the split task's menu")) {
+ mLauncher.clickLauncherObject(
+ mLauncher.waitForObjectInContainer(mTask.getParent(), "bottomRight_icon"));
+
+ try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+ "tapped the split task's menu")) {
+ return new OverviewTaskMenu(mLauncher);
+ }
+ }
+ }
+
boolean isTaskSplit() {
return mLauncher.findObjectInContainer(mTask.getParent(), "bottomright_snapshot") != null;
}
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
index 859e504..25c73de 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
@@ -91,4 +91,11 @@
return new OverviewTaskMenuItem(mLauncher,
mLauncher.waitForObjectInContainer(mMenu, By.text(menuItemName)));
}
+
+ /**
+ * Taps outside task menu to dismiss it.
+ */
+ public void touchOutsideTaskMenuToDismiss() {
+ mLauncher.touchOutsideContainer(mMenu, false);
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Qsb.java b/tests/tapl/com/android/launcher3/tapl/Qsb.java
index 0f2aff8..5ca80a3 100644
--- a/tests/tapl/com/android/launcher3/tapl/Qsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/Qsb.java
@@ -25,7 +25,7 @@
/**
* Operations on qsb from either Home screen or AllApp screen.
*/
-public abstract class Qsb {
+public abstract class Qsb implements SearchInputSource {
private static final String ASSISTANT_APP_PACKAGE = "com.google.android.googlequicksearchbox";
private static final String ASSISTANT_ICON_RES_ID = "mic_icon";
@@ -125,6 +125,16 @@
}
}
+ @Override
+ public LauncherInstrumentation getLauncher() {
+ return mLauncher;
+ }
+
+ @Override
+ public SearchResultFromQsb getSearchResultForInput() {
+ return createSearchResult();
+ }
+
protected SearchResultFromQsb createSearchResult() {
return new SearchResultFromQsb(mLauncher);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/SearchInputSource.java b/tests/tapl/com/android/launcher3/tapl/SearchInputSource.java
new file mode 100644
index 0000000..032948f
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/SearchInputSource.java
@@ -0,0 +1,52 @@
+/*
+ * 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.tapl;
+
+import androidx.test.uiautomator.UiObject2;
+
+import com.android.launcher3.testing.shared.TestProtocol;
+
+/**
+ * Container that can be used to input a search query and retrieve a {@link SearchResultFromQsb}
+ * instance.
+ */
+interface SearchInputSource {
+ String INPUT_RES = "input";
+
+ /** Set the already focused search input edit text and update search results. */
+ default SearchResultFromQsb searchForInput(String input) {
+ LauncherInstrumentation launcher = getLauncher();
+ try (LauncherInstrumentation.Closable c = launcher.addContextLayer(
+ "want to search for result with an input");
+ LauncherInstrumentation.Closable e = launcher.eventsCheck()) {
+ launcher.executeAndWaitForLauncherEvent(
+ () -> {
+ UiObject2 editText = launcher.waitForLauncherObject(INPUT_RES);
+ launcher.waitForObjectFocused(editText, "search input");
+ editText.setText(input);
+ },
+ event -> TestProtocol.SEARCH_RESULT_COMPLETE.equals(event.getClassName()),
+ () -> "Didn't receive a search result completed message", "searching");
+ return getSearchResultForInput();
+ }
+ }
+
+ /** This method requires public access, however should not be called in tests. */
+ LauncherInstrumentation getLauncher();
+
+ /** This method requires public access, however should not be called in tests. */
+ SearchResultFromQsb getSearchResultForInput();
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
index 513d6bb..f0a8aa2 100644
--- a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
@@ -20,16 +20,12 @@
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.UiObject2;
-import com.android.launcher3.testing.shared.TestProtocol;
-
import java.util.ArrayList;
/**
* Operations on search result page opened from qsb.
*/
-public class SearchResultFromQsb {
- // The input resource id in the search box.
- private static final String INPUT_RES = "input";
+public class SearchResultFromQsb implements SearchInputSource {
private static final String BOTTOM_SHEET_RES_ID = "bottom_sheet_background";
// This particular ID change should happen with caution
@@ -41,18 +37,6 @@
mLauncher.waitForLauncherObject("search_container_all_apps");
}
- /** Set the input to the search input edit text and update search results. */
- public void searchForInput(String input) {
- try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
- "want to search for result with an input");
- LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
- mLauncher.executeAndWaitForLauncherEvent(
- () -> mLauncher.waitForLauncherObject(INPUT_RES).setText(input),
- event -> TestProtocol.SEARCH_RESULT_COMPLETE.equals(event.getClassName()),
- () -> "Didn't receive a search result completed message", "searching");
- }
- }
-
/** Find the app from search results with app name. */
public AppIcon findAppIcon(String appName) {
UiObject2 icon = mLauncher.waitForLauncherObject(By.clazz(TextView.class).text(appName));
@@ -114,4 +98,14 @@
protected void verifyVisibleContainerOnDismiss() {
mLauncher.getWorkspace();
}
+
+ @Override
+ public LauncherInstrumentation getLauncher() {
+ return mLauncher;
+ }
+
+ @Override
+ public SearchResultFromQsb getSearchResultForInput() {
+ return this;
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Taskbar.java b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
index 4293ee8..da26694 100644
--- a/tests/tapl/com/android/launcher3/tapl/Taskbar.java
+++ b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.tapl;
+import static android.view.KeyEvent.KEYCODE_META_RIGHT;
+
import static com.android.launcher3.tapl.LauncherInstrumentation.TASKBAR_RES_ID;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_DISABLE_MANUAL_TASKBAR_STASHING;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_ENABLE_MANUAL_TASKBAR_STASHING;
@@ -105,6 +107,17 @@
}
}
+ /** Opens the Taskbar all apps page with the meta keyboard shortcut. */
+ public TaskbarAllApps openAllAppsFromKeyboardShortcut() {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+ mLauncher.getDevice().pressKeyCode(KEYCODE_META_RIGHT);
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "pressed meta key")) {
+ return getAllApps();
+ }
+ }
+ }
+
/** Returns {@link TaskbarAllApps} if it is open, otherwise fails. */
public TaskbarAllApps getAllApps() {
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index cf48ebc..fc589bd 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -16,6 +16,7 @@
package com.android.launcher3.tapl;
+import static android.view.KeyEvent.KEYCODE_META_RIGHT;
import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_SCROLLED;
import static com.android.launcher3.testing.shared.TestProtocol.ALL_APPS_STATE_ORDINAL;
@@ -115,6 +116,20 @@
}
}
+ /** Opens the Launcher all apps page with the meta keyboard shortcut. */
+ public HomeAllApps openAllAppsFromKeyboardShortcut() {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable c =
+ mLauncher.addContextLayer("want to open all apps search")) {
+ verifyActiveContainer();
+ mLauncher.getDevice().pressKeyCode(KEYCODE_META_RIGHT);
+ try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+ "pressed meta key")) {
+ return new HomeAllApps(mLauncher);
+ }
+ }
+ }
+
/**
* Returns the home qsb.
*