From 5b89b31b127f62ce2936e40ba5ec723c31dcc5b0 Mon Sep 17 00:00:00 2001 From: Brian Isganitis Date: Mon, 11 Apr 2022 12:09:34 -0700 Subject: [PATCH 1/8] Log taskbar all apps entrypoint, launches, and drags Test: wwdebug, wwlogcat, ensure container is formatted as follows: container_info { all_apps_container { taskbar { } } } Bug: 204696617 Change-Id: I2492b133f95fccb059010bc9e5ed6cce73c211f9 --- protos/launcher_atom.proto | 6 ++++++ .../launcher3/taskbar/TaskbarActivityContext.java | 9 +++++++++ .../android/launcher3/taskbar/TaskbarViewController.java | 6 +++++- .../android/quickstep/logging/StatsLogCompatManager.java | 5 +++++ src/com/android/launcher3/logging/StatsLogManager.java | 3 +++ 5 files changed, 28 insertions(+), 1 deletion(-) diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto index cf854ed011..10eedc8578 100644 --- a/protos/launcher_atom.proto +++ b/protos/launcher_atom.proto @@ -76,6 +76,9 @@ message ContainerInfo { // Represents the apps list sorted alphabetically inside the all-apps view. message AllAppsContainer { + oneof ParentContainer { + TaskBarContainer taskbar_container = 1; + } } message WidgetsContainer { @@ -83,6 +86,9 @@ message WidgetsContainer { // Represents the predicted apps row(top row) in the all-apps view. message PredictionContainer { + oneof ParentContainer { + TaskBarContainer taskbar_container = 1; + } } // Represents the apps container within search results. diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 296000b054..7c9bab4d9c 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -374,6 +374,14 @@ public class TaskbarActivityContext extends BaseTaskbarContext { folderBuilder.clearHotseat(); itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder() .setFolder(folderBuilder)); + } else if (oldContainer.hasAllAppsContainer()) { + itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder() + .setAllAppsContainer(oldContainer.getAllAppsContainer().toBuilder() + .setTaskbarContainer(LauncherAtom.TaskBarContainer.newBuilder()))); + } else if (oldContainer.hasPredictionContainer()) { + itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder() + .setPredictionContainer(oldContainer.getPredictionContainer().toBuilder() + .setTaskbarContainer(LauncherAtom.TaskBarContainer.newBuilder()))); } } @@ -691,6 +699,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { } } else if (tag instanceof AppInfo) { startItemInfoActivity((AppInfo) tag); + mControllers.uiController.onTaskbarIconLaunched((AppInfo) tag); } else { Log.e(TAG, "Unknown type clicked: " + tag); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index e1ce89815a..6416720962 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -18,6 +18,7 @@ package com.android.launcher3.taskbar; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import static com.android.launcher3.Utilities.squaredHypot; import static com.android.launcher3.anim.Interpolators.LINEAR; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP; import static com.android.quickstep.AnimatedFloat.VALUE; import android.annotation.NonNull; @@ -341,7 +342,10 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar } public View.OnClickListener getAllAppsButtonClickListener() { - return v -> mControllers.taskbarAllAppsController.show(); + return v -> { + mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP); + mControllers.taskbarAllAppsController.show(); + }; } public View.OnLongClickListener getIconOnLongClickListener() { diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java index 13007ea512..10c56c9e8c 100644 --- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java +++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java @@ -20,6 +20,7 @@ import static androidx.core.util.Preconditions.checkNotNull; import static androidx.core.util.Preconditions.checkState; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_NON_ACTIONABLE; +import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.ALL_APPS_CONTAINER; import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.EXTENDED_CONTAINERS; import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.FOLDER; import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.SEARCH_RESULT_CONTAINER; @@ -92,6 +93,7 @@ public class StatsLogCompatManager extends StatsLogManager { private static final int FOLDER_HIERARCHY_OFFSET = 100; private static final int SEARCH_RESULT_HIERARCHY_OFFSET = 200; private static final int EXTENDED_CONTAINERS_HIERARCHY_OFFSET = 300; + private static final int ALL_APPS_HIERARCHY_OFFSET = 400; /** * Flags for converting SearchAttribute to integer value. @@ -632,6 +634,9 @@ public class StatsLogCompatManager extends StatsLogManager { } else if (info.getContainerInfo().getContainerCase() == EXTENDED_CONTAINERS) { return info.getContainerInfo().getExtendedContainers().getContainerCase().getNumber() + EXTENDED_CONTAINERS_HIERARCHY_OFFSET; + } else if (info.getContainerInfo().getContainerCase() == ALL_APPS_CONTAINER) { + return info.getContainerInfo().getAllAppsContainer().getParentContainerCase() + .getNumber() + ALL_APPS_HIERARCHY_OFFSET; } else { return info.getContainerInfo().getContainerCase().getNumber(); } diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index 9af72c33d4..2b6e426bf7 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -586,6 +586,9 @@ public class StatsLogManager implements ResourceBasedOverride { @UiEvent(doc = "User clicked on IME quicksearch button.") LAUNCHER_ALLAPPS_QUICK_SEARCH_WITH_IME(1047), + + @UiEvent(doc = "User tapped taskbar All Apps button.") + LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP(1057), ; // ADD MORE From 48beebbed5423b0b28275dd9c9886b8b7e624d91 Mon Sep 17 00:00:00 2001 From: Pat Manning Date: Fri, 8 Apr 2022 13:10:09 +0100 Subject: [PATCH 2/8] Update widget edit icon to use material colors. Fix: 216821024 Test: manual Change-Id: I3c3e463e33d7a611010e426eca1378cde027c6d6 --- res/drawable/gm_edit_24.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/drawable/gm_edit_24.xml b/res/drawable/gm_edit_24.xml index 59a0dc2faf..f7413334f9 100644 --- a/res/drawable/gm_edit_24.xml +++ b/res/drawable/gm_edit_24.xml @@ -5,6 +5,6 @@ android:viewportHeight="24" android:tint="?attr/colorControlNormal"> From e28dbba7b4771e3816c73668da7e3c26286ec254 Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Fri, 15 Apr 2022 15:26:32 -0700 Subject: [PATCH 3/8] Check for auto-rotation when initializing RecentsOrientedState * When folding/unfolding we destroy listeners because the view gets torn down but the auto-rotate setting gets updated before launcher has a chance to re-init the listeners * Force update once when initializing (hopefully this doesn't cause test issues by creating an additional binder call..) Fixes: 228765701 Test: Bug no longer repros Change-Id: Ide0e8907f97d6985813257b299104ac7cfdf959a --- .../src/com/android/quickstep/util/RecentsOrientedState.java | 1 + 1 file changed, 1 insertion(+) diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java index 1631be037d..6038a22de8 100644 --- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java +++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java @@ -307,6 +307,7 @@ public class RecentsOrientedState implements private void initMultipleOrientationListeners() { mSharedPrefs.registerOnSharedPreferenceChangeListener(this); mSettingsCache.register(ROTATION_SETTING_URI, mRotationChangeListener); + updateAutoRotateSetting(); } private void destroyMultipleOrientationListeners() { From df307ef14f66555cec7a968e9945856739945844 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Mon, 18 Apr 2022 12:39:05 +0000 Subject: [PATCH 4/8] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: I3c53c19568b209eda0365f8a4169d963cade9098 --- res/values-cs/strings.xml | 4 ++-- res/values-es/strings.xml | 4 ++-- res/values-kk/strings.xml | 2 +- res/values-kn/strings.xml | 2 +- res/values-mr/strings.xml | 2 +- res/values-nb/strings.xml | 2 +- res/values-sw/strings.xml | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index a92e93661f..8cf9c237d6 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -32,7 +32,7 @@ "Rozdělit vlevo" "Rozdělit vpravo" "Informace o aplikaci %1$s" - "Klepnutím a podržením přesunete widget." + "Widget přesunete klepnutím a podržením." "Dvojitým klepnutím a podržením přesunete widget, případně použijte vlastní akce." "%1$d × %2$d" "šířka %1$d, výška %2$d" @@ -156,7 +156,7 @@ "Osobní" "Pracovní" "Pracovní profil" - "Pracovní aplikace jsou označené a viditelné vašemu administrátorovi IT" + "Pracovní aplikace jsou označené a váš administrátor IT je vidí" "Rozumím" "Pracovní aplikace jsou pozastaveny" "Pracovní aplikace vám nemohou zasílat oznámení, používat vaši baterii ani získat přístup k vaší poloze" diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index 8db8fdf4f4..aa01867fcc 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -32,7 +32,7 @@ "Dividir parte izquierda" "Dividir parte derecha" "Información de la aplicación %1$s" - "Mantén pulsado un widget para moverlo." + "Mantén pulsado un widget para moverlo" "Toca dos veces y mantén pulsado un widget para moverlo o usar acciones personalizadas." "%1$d × %2$d" "%1$d de ancho por %2$d de alto" @@ -41,7 +41,7 @@ "Añadir a pantalla de inicio" "Widget %1$s añadido a la pantalla de inicio" "{count,plural, =1{# widget}other{# widgets}}" - "{count,plural, =1{# combinación de teclas}other{# combinaciones de teclas}}" + "{count,plural, =1{# acceso directo}other{# accesos directos}}" "%1$s, %2$s" "Widgets" "Buscar" diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml index 529a00f550..17d21d187d 100644 --- a/res/values-kk/strings.xml +++ b/res/values-kk/strings.xml @@ -51,7 +51,7 @@ "Жеке виджеттер" "Жұмыс виджеттері" "Әңгімелер" - "Саусақпен түртсеңіз болғаны – пайдалы ақпарат көз алдыңызда" + "Саусақпен түртсеңіз болғаны – пайдалы ақпарат көз алдыңызда" "Қолданбаларды ашпай-ақ ақпарат алу үшін негізгі экранға тиісті виджеттерді қосыңыз." "Виджет параметрлерін өзгерту үшін түртіңіз." "Түсінікті" diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml index 9eda419086..d7f8a1691c 100644 --- a/res/values-kn/strings.xml +++ b/res/values-kn/strings.xml @@ -50,7 +50,7 @@ "ಯಾವುದೇ ವಿಜೆಟ್‌ಗಳು ಅಥವಾ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು ಕಂಡುಬಂದಿಲ್ಲ" "ವೈಯಕ್ತಿಕ" "ಕೆಲಸ" - "ಸಂವಾದಗಳು" + "ಸಂಭಾಷಣೆಗಳು" "ನಿಮ್ಮ ಬೆರಳ ತುದಿಯಲ್ಲಿ ಉಪಯುಕ್ತ ಮಾಹಿತಿ" "ಆ್ಯಪ್‌ಗಳನ್ನು ತೆರೆಯದೆಯೇ ಮಾಹಿತಿಯನ್ನು ಪಡೆಯಲು, ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್‌ನಲ್ಲಿ ನೀವು ವಿಜೆಟ್‌ಗಳನ್ನು ಸೇರಿಸಬಹುದು" "ವಿಜೆಟ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ" diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml index 958890749a..e798a3df15 100644 --- a/res/values-mr/strings.xml +++ b/res/values-mr/strings.xml @@ -156,7 +156,7 @@ "वैयक्तिक" "कार्य" "कार्य प्रोफाइल" - "कामाशी संबंधित ॲप्स ही बॅज केलेली असून तुमच्या IT ॲडमिनला दृश्यमान आहेत" + "कामाशी संबंधित ॲप्स ही बॅज केलेली असून तुमच्या आयटी ॲडमिनला दृश्यमान आहेत" "समजले" "कार्य ॲप्स थांबवली आहेत" "तुमची कार्य ॲप्स तुम्हाला सूचना पाठवू शकत नाहीत, तुमची बॅटरी वापरू शकत नाहीत किंवा तुमचे स्थान अ‍ॅक्सेस करू शकत नाहीत" diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index a4bc094856..80939399a0 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -156,7 +156,7 @@ "Personlig" "Jobb" "Jobbprofil" - "Jobbapper er merket og synlige for IT-administratoren din" + "Jobbapper er merket og synlige for IT-administratoren" "Greit" "Jobbapper er satt på pause" "Jobbapper kan ikke sende deg varsler, bruke batteriet eller få tilgang til posisjonen din" diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml index fa58703671..93a37c23d4 100644 --- a/res/values-sw/strings.xml +++ b/res/values-sw/strings.xml @@ -102,7 +102,7 @@ "Folda: %1$s, vipengee %2$d" "Folda: %1$s, vipengee %2$d au zaidi" "Mandhari" - "Mandhari na muundo" + "Mandhari na mtindo" "Mipangilio ya mwanzo" "Imezimwa na msimamizi wako" "Ruhusu kuzungusha skrini ya Kwanza" From 4c5bd537bb0e964b330a80a4a4fecb7465c4ece0 Mon Sep 17 00:00:00 2001 From: Sihua Ma Date: Mon, 11 Apr 2022 03:29:16 -0700 Subject: [PATCH 5/8] Attach work badge to Weather and Battery widgets Moving the part where widget icon is generated from WidgetsListHeader (UI thread) to IconCache (backend) Test: Open widget picker -> switch to work widget picker -> verify that Battery and Weather are badged Fix: 226132413, 209995894 Change-Id: I3d649f2b26d7d8e7b756129b5bae4433ea344d43 --- .../android/launcher3/icons/IconCache.java | 43 ++++++++++++++++--- .../widget/PendingAppWidgetHostView.java | 5 +-- .../widget/picker/WidgetsListHeader.java | 11 +---- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java index 7ba2317868..fe9b633b66 100644 --- a/src/com/android/launcher3/icons/IconCache.java +++ b/src/com/android/launcher3/icons/IconCache.java @@ -42,8 +42,10 @@ import android.os.Trace; import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; +import android.util.SparseArray; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.core.util.Pair; import com.android.launcher3.InvariantDeviceProfile; @@ -94,6 +96,8 @@ public class IconCache extends BaseIconCache { private final InstantAppResolver mInstantAppResolver; private final IconProvider mIconProvider; + private final SparseArray mWidgetCategoryBitmapInfos; + private int mPendingIconRequestCount = 0; public IconCache(Context context, InvariantDeviceProfile idp) { @@ -111,6 +115,7 @@ public class IconCache extends BaseIconCache { mUserManager = UserCache.INSTANCE.get(mContext); mInstantAppResolver = InstantAppResolver.newInstance(mContext); mIconProvider = iconProvider; + mWidgetCategoryBitmapInfos = new SparseArray<>(); } @Override @@ -477,13 +482,39 @@ public class IconCache extends BaseIconCache { CacheEntry entry = getEntryForPackageLocked( infoInOut.packageName, infoInOut.user, useLowResIcon); applyCacheEntry(entry, infoInOut); - if (infoInOut.widgetCategory != NO_CATEGORY) { - WidgetSection widgetSection = WidgetSections.getWidgetSections(mContext) - .get(infoInOut.widgetCategory); - infoInOut.title = mContext.getString(widgetSection.mSectionTitle); - infoInOut.contentDescription = mPackageManager.getUserBadgedLabel( - infoInOut.title, infoInOut.user); + if (infoInOut.widgetCategory == NO_CATEGORY) { + return; } + + WidgetSection widgetSection = WidgetSections.getWidgetSections(mContext) + .get(infoInOut.widgetCategory); + infoInOut.title = mContext.getString(widgetSection.mSectionTitle); + infoInOut.contentDescription = mPackageManager.getUserBadgedLabel( + infoInOut.title, infoInOut.user); + final BitmapInfo cachedBitmap = mWidgetCategoryBitmapInfos.get(infoInOut.widgetCategory); + if (cachedBitmap != null) { + infoInOut.bitmap = getBadgedIcon(cachedBitmap, infoInOut.user); + return; + } + + try (LauncherIcons li = LauncherIcons.obtain(mContext)) { + final BitmapInfo tempBitmap = li.createBadgedIconBitmap( + mContext.getDrawable(widgetSection.mSectionDrawable), + new BaseIconFactory.IconOptions().setShrinkNonAdaptiveIcons(false)); + mWidgetCategoryBitmapInfos.put(infoInOut.widgetCategory, tempBitmap); + infoInOut.bitmap = getBadgedIcon(tempBitmap, infoInOut.user); + } catch (Exception e) { + Log.e(TAG, "Error initializing bitmap for icons with widget category", e); + } + + } + + private synchronized BitmapInfo getBadgedIcon(@Nullable final BitmapInfo bitmap, + @NonNull final UserHandle user) { + if (bitmap == null) { + return getDefaultIcon(user); + } + return bitmap.withFlags(getUserFlagOpLocked(user)); } protected void applyCacheEntry(CacheEntry entry, ItemInfoWithIcon info) { diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java index 1f6551e160..130ee3a70c 100644 --- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java +++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java @@ -18,7 +18,6 @@ package com.android.launcher3.widget; import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon; import static com.android.launcher3.icons.FastBitmapDrawable.getDisabledColorFilter; -import static com.android.launcher3.widget.WidgetSections.getWidgetSections; import android.content.Context; import android.graphics.Canvas; @@ -341,8 +340,6 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView if (mInfo.pendingItemInfo.widgetCategory == WidgetSections.NO_CATEGORY) { return null; } - Context context = getContext(); - return context.getDrawable(getWidgetSections(context).get( - mInfo.pendingItemInfo.widgetCategory).mSectionDrawable); + return mInfo.pendingItemInfo.newIcon(getContext()); } } diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java index 932e06d57b..b0e2ec18b7 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java +++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java @@ -15,7 +15,6 @@ */ package com.android.launcher3.widget.picker; -import static com.android.launcher3.widget.WidgetSections.NO_CATEGORY; import android.content.Context; import android.content.res.Resources; @@ -43,8 +42,6 @@ import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.PackageItemInfo; import com.android.launcher3.util.PluralMessageFormat; import com.android.launcher3.views.ActivityContext; -import com.android.launcher3.widget.WidgetSections; -import com.android.launcher3.widget.WidgetSections.WidgetSection; import com.android.launcher3.widget.model.WidgetsListHeaderEntry; import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry; @@ -177,13 +174,7 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd private void setIcon(PackageItemInfo info) { Drawable icon; - if (info.widgetCategory == NO_CATEGORY) { - icon = info.newIcon(getContext()); - } else { - WidgetSection widgetSection = WidgetSections.getWidgetSections(getContext()) - .get(info.widgetCategory); - icon = getContext().getDrawable(widgetSection.mSectionDrawable); - } + icon = info.newIcon(getContext()); applyDrawables(icon); mIconDrawable = icon; if (mIconDrawable != null) { From 95cad640c74b3c205879ddb445fd458d877c8c2d Mon Sep 17 00:00:00 2001 From: Brian Isganitis Date: Tue, 19 Apr 2022 23:11:12 +0000 Subject: [PATCH 6/8] Decrease overview degree threshold from 45 to 15 degrees. Met with arifhuda@ to confirm the benefit of lowering to 15 degrees. This change also updates AbsSwipeHandler to differentiate between X and Y flings in calculateEndTarget. Test: Manual Fix: 222117127 Change-Id: I416986145a4306d1babe23735e0563e87660c417 --- .../com/android/quickstep/AbsSwipeUpHandler.java | 14 ++++++++++---- .../inputconsumers/OtherActivityInputConsumer.java | 6 +++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 2ae0646ed0..7ca76399a6 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -1006,8 +1006,8 @@ public abstract class AbsSwipeUpHandler, return false; } - private GestureEndTarget calculateEndTarget(PointF velocity, float endVelocity, boolean isFling, - boolean isCancel) { + private GestureEndTarget calculateEndTarget(PointF velocity, float endVelocity, + boolean isFlingY, boolean isCancel) { if (mGestureState.isHandlingAtomicEvent()) { // Button mode, this is only used to go to recents return RECENTS; @@ -1028,11 +1028,17 @@ public abstract class AbsSwipeUpHandler, goingToNewTask = false; } final boolean reachedOverviewThreshold = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW; - if (!isFling) { + final boolean isFlingX = Math.abs(velocity.x) > mContext.getResources() + .getDimension(R.dimen.quickstep_fling_threshold_speed); + if (!isFlingY) { if (isCancel) { endTarget = LAST_TASK; } else if (mDeviceState.isFullyGesturalNavMode()) { - if (mIsMotionPaused) { + if (goingToNewTask && isFlingX) { + // Flinging towards new task takes precedence over mIsMotionPaused (which only + // checks y-velocity). + endTarget = NEW_TASK; + } else if (mIsMotionPaused) { endTarget = RECENTS; } else if (goingToNewTask) { endTarget = NEW_TASK; diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index dd459f5258..11f0ff3259 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -84,6 +84,9 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC public static final float QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON = 9; public static final float QUICKSTEP_TOUCH_SLOP_RATIO_GESTURAL = 2; + // Minimum angle of a gesture's coordinate where a release goes to overview. + public static final int OVERVIEW_MIN_DEGREES = 15; + private final RecentsAnimationDeviceState mDeviceState; private final NavBarPosition mNavBarPosition; private final TaskAnimationManager mTaskAnimationManager; @@ -291,8 +294,9 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC // the gesture (in which case mPassedPilferInputSlop starts as true). boolean haveNotPassedSlopOnContinuedGesture = !mPassedSlopOnThisGesture && mPassedPilferInputSlop; + double degrees = Math.toDegrees(Math.atan(upDist / horizontalDist)); boolean isLikelyToStartNewTask = haveNotPassedSlopOnContinuedGesture - || horizontalDist > upDist; + || degrees <= OVERVIEW_MIN_DEGREES; if (!mPassedPilferInputSlop) { if (passedSlop) { From 25fbd5b0bbb4e1fe0fe33f525235e6bbb6081b30 Mon Sep 17 00:00:00 2001 From: vadimt Date: Tue, 19 Apr 2022 17:31:28 -0700 Subject: [PATCH 7/8] Sampling too long Launcher tests A test that takes > 3 min will generate an artifact file containing stacks of all threads of the test process taken every 3 sec. This artifact will be also generated if the test process is killed, for example, by timeout. This artifact should help EngProd's effort to speed up presubmits. Bug: 225186335 Test: local runs Change-Id: I721779bfbe5bc6289315998ed2660f5f46165611 --- .../quickstep/FallbackRecentsTest.java | 4 +- tests/Android.bp | 1 + .../launcher3/ui/AbstractLauncherUiTest.java | 4 +- .../launcher3/util/rule/SamplerRule.java | 129 ++++++++++++++++++ 4 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 tests/src/com/android/launcher3/util/rule/SamplerRule.java diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java index ca6712f768..f7600ff9bb 100644 --- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java +++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java @@ -57,6 +57,7 @@ import com.android.launcher3.tapl.TestHelpers; import com.android.launcher3.testcomponent.TestCommandReceiver; import com.android.launcher3.util.Wait; import com.android.launcher3.util.rule.FailureWatcher; +import com.android.launcher3.util.rule.SamplerRule; import com.android.launcher3.util.rule.ScreenRecordRule; import com.android.quickstep.views.RecentsView; @@ -111,7 +112,8 @@ public class FallbackRecentsTest { } mOrderSensitiveRules = RuleChain - .outerRule(new NavigationModeSwitchRule(mLauncher)) + .outerRule(new SamplerRule()) + .around(new NavigationModeSwitchRule(mLauncher)) .around(new FailureWatcher(mDevice, mLauncher)); mOtherLauncherActivity = context.getPackageManager().queryIntentActivities( diff --git a/tests/Android.bp b/tests/Android.bp index 7542d04f7b..54cded0fd3 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -37,6 +37,7 @@ filegroup { "src/com/android/launcher3/util/WidgetUtils.java", "src/com/android/launcher3/util/rule/FailureWatcher.java", "src/com/android/launcher3/util/rule/LauncherActivityRule.java", + "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/SimpleActivityRule.java", diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index 136f115650..7080c85690 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -68,6 +68,7 @@ import com.android.launcher3.util.Wait; import com.android.launcher3.util.WidgetUtils; import com.android.launcher3.util.rule.FailureWatcher; import com.android.launcher3.util.rule.LauncherActivityRule; +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.TestStabilityRule; @@ -227,7 +228,8 @@ public abstract class AbstractLauncherUiTest { @Rule public TestRule mOrderSensitiveRules = RuleChain - .outerRule(new TestStabilityRule()) + .outerRule(new SamplerRule()) + .around(new TestStabilityRule()) .around(mActivityMonitor) .around(getRulesInsideActivityMonitor()); diff --git a/tests/src/com/android/launcher3/util/rule/SamplerRule.java b/tests/src/com/android/launcher3/util/rule/SamplerRule.java new file mode 100644 index 0000000000..6125f2a8d2 --- /dev/null +++ b/tests/src/com/android/launcher3/util/rule/SamplerRule.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.util.rule; + +import android.os.SystemClock; + +import androidx.test.InstrumentationRegistry; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * A rule that generates a file that helps diagnosing cases when the test process was terminated + * because the test execution took too long, and tests that ran for too long even without being + * terminated. If the process was terminated or the test was long, the test leaves an artifact with + * stack traces of all threads, every SAMPLE_INTERVAL_MS. This will help understanding where we + * stuck. + */ +public class SamplerRule implements TestRule { + private static final int TOO_LONG_TEST_MS = 180000; + private static final int SAMPLE_INTERVAL_MS = 3000; + + public static Thread startThread(Description description) { + Thread thread = + new Thread() { + @Override + public void run() { + // Write all-threads stack stace every SAMPLE_INTERVAL_MS while the test + // is running. + // After the test finishes, delete that file. If the test process is + // terminated due to timeout, the trace file won't be deleted. + final File file = getFile(); + + final long startTime = SystemClock.elapsedRealtime(); + try (OutputStreamWriter outputStreamWriter = + new OutputStreamWriter( + new BufferedOutputStream( + new FileOutputStream(file)))) { + writeSamples(outputStreamWriter); + } catch (IOException | InterruptedException e) { + // Simply suppressing the exceptions, nothing to do here. + } finally { + // If the process is not killed, then there was no test timeout, and + // we are not interested in the trace file, unless the test ran too + // long. + if (SystemClock.elapsedRealtime() - startTime < TOO_LONG_TEST_MS) { + file.delete(); + } + } + } + + private File getFile() { + final String strDate = new SimpleDateFormat("HH:mm:ss").format(new Date()); + + final String descStr = description.getTestClass().getSimpleName() + "." + + description.getMethodName(); + return artifactFile( + "ThreadStackSamples-" + strDate + "-" + descStr + ".txt"); + } + + private void writeSamples(OutputStreamWriter writer) + throws IOException, InterruptedException { + int count = 0; + while (true) { + writer.write( + "#" + + (count++) + + " =============================================\r\n"); + for (StackTraceElement[] stack : getAllStackTraces().values()) { + writer.write("---------------------\r\n"); + for (StackTraceElement frame : stack) { + writer.write(frame.toString() + "\r\n"); + } + } + writer.flush(); + + sleep(SAMPLE_INTERVAL_MS); + } + } + }; + + thread.start(); + return thread; + } + + @Override + public Statement apply(Statement base, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + final Thread traceThread = startThread(description); + try { + base.evaluate(); + } finally { + traceThread.interrupt(); + traceThread.join(); + } + } + }; + } + + private static File artifactFile(String fileName) { + return new File( + InstrumentationRegistry.getInstrumentation().getTargetContext().getFilesDir(), + fileName); + } +} From ea5c1d29fec66a11b57be5a2f30d4c0744a4ae3a Mon Sep 17 00:00:00 2001 From: Pat Manning Date: Thu, 14 Apr 2022 10:58:16 +0100 Subject: [PATCH 8/8] Prevent edit state workspace scale from hiding next pages. Fix: 228969651 Test: manual Change-Id: I0cceb3bfab19e0721b21fb8c55fe1218b1f25af8 --- src/com/android/launcher3/DeviceProfile.java | 7 +++++++ .../android/launcher3/states/SpringLoadedState.java | 10 +++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 72d0f59fd9..e55daac547 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -928,6 +928,13 @@ public class DeviceProfile { return workspaceSpringLoadShrunkBottom; } + /** + * Gets the minimum visible amount of the next workspace page when in the spring-loaded state. + */ + public float getWorkspaceSpringLoadedMinimumNextPageVisible() { + return getCellSize().x / 2f; + } + public int getWorkspaceWidth() { return getWorkspaceWidth(getTotalWorkspacePadding()); } diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java index 9be3cc5539..13e2b34367 100644 --- a/src/com/android/launcher3/states/SpringLoadedState.java +++ b/src/com/android/launcher3/states/SpringLoadedState.java @@ -53,7 +53,15 @@ public class SpringLoadedState extends LauncherState { float shrunkTop = grid.getWorkspaceSpringLoadShrunkTop(); float shrunkBottom = grid.getWorkspaceSpringLoadShrunkBottom(); - float scale = (shrunkBottom - shrunkTop) / ws.getNormalChildHeight(); + float scale = Math.min((shrunkBottom - shrunkTop) / ws.getNormalChildHeight(), 1f); + + // Reduce scale if next pages would not be visible after scaling the workspace + float scaledWorkspaceWidth = ws.getWidth() * scale; + float maxAvailableWidth = + ws.getWidth() - (2 * grid.getWorkspaceSpringLoadedMinimumNextPageVisible()); + if (scaledWorkspaceWidth > maxAvailableWidth) { + scale *= maxAvailableWidth / scaledWorkspaceWidth; + } float halfHeight = ws.getHeight() / 2; float myCenter = ws.getTop() + halfHeight;