Merge "Add shortcut to install an app to Private space" into main
diff --git a/Android.bp b/Android.bp
index 19d2a58..e2dd48d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -112,9 +112,6 @@
resource_dirs: [],
manifest: "tests/tapl/AndroidManifest.xml",
platform_apis: true,
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
java_library_static {
@@ -132,9 +129,6 @@
],
},
static_libs: ["libprotobuf-java-lite"],
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
java_library_static {
@@ -153,9 +147,6 @@
"libprotobuf-java-lite",
"launcher_log_protos_lite",
],
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
java_library {
@@ -167,9 +158,6 @@
sdk_version: "current",
min_sdk_version: min_launcher3_sdk_version,
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
// Library with all the dependencies for building Launcher3
@@ -196,7 +184,7 @@
sdk_version: "current",
min_sdk_version: min_launcher3_sdk_version,
lint: {
- baseline_filename: "lint-baseline-res-lib.xml",
+ baseline_filename: "lint-baseline2.xml",
},
}
@@ -218,7 +206,7 @@
min_sdk_version: min_launcher3_sdk_version,
manifest: "AndroidManifest-common.xml",
lint: {
- baseline_filename: "lint-baseline-common-deps-lib.xml",
+ baseline_filename: "lint-baseline2.xml",
},
}
@@ -265,7 +253,7 @@
"AndroidManifest-common.xml",
],
lint: {
- baseline_filename: "lint-baseline-launcher3.xml",
+ baseline_filename: "lint-baseline.xml",
},
}
@@ -289,9 +277,6 @@
],
manifest: "quickstep/AndroidManifest.xml",
min_sdk_version: "current",
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
// Library with all the dependencies for building Launcher Go
@@ -323,9 +308,6 @@
"AndroidManifest-common.xml",
],
min_sdk_version: "current",
- lint: {
- baseline_filename: "lint-baseline-go-res-lib.xml",
- },
}
// Build rule for Quickstep library
@@ -354,9 +336,6 @@
manifest: "quickstep/AndroidManifest.xml",
platform_apis: true,
min_sdk_version: "current",
- lint: {
- baseline_filename: "lint-baseline-launcher3.xml",
- },
}
// Build rule for Launcher3 Go app for Android Go devices.
@@ -399,9 +378,6 @@
jacoco: {
include_filter: ["com.android.launcher3.*"],
},
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
@@ -438,9 +414,6 @@
jacoco: {
include_filter: ["com.android.launcher3.*"],
},
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
@@ -491,8 +464,5 @@
jacoco: {
include_filter: ["com.android.launcher3.*"],
},
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 0e11f4b..f5afd88 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -71,13 +71,6 @@
}
flag {
- name: "enable_split_from_fullscreen_with_keyboard_shortcuts"
- namespace: "launcher"
- description: "Enables initiating split from a fullscreen app using keyboard shortcuts"
- bug: "270394122"
-}
-
-flag {
name: "enable_launcher_br_metrics"
namespace: "launcher"
description: "Enables logging of Launcher restore metrics to the Backup & Restore team"
diff --git a/lint-baseline-common-deps-lib.xml b/lint-baseline-common-deps-lib.xml
deleted file mode 100644
index e52f8fb..0000000
--- a/lint-baseline-common-deps-lib.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
- <issue
- id="NewApi"
- message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 26)"
- errorLine1=" android:topLeftRadius="?android:attr/dialogCornerRadius""
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/res/drawable/add_item_dialog_background.xml"
- line="6"
- column="9"/>
- </issue>
-
- <issue
- id="NewApi"
- message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 26)"
- errorLine1=" android:topRightRadius="?android:attr/dialogCornerRadius" />"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/res/drawable/add_item_dialog_background.xml"
- line="7"
- column="9"/>
- </issue>
-
- <issue
- id="NewApi"
- message="`@android:style/Widget.DeviceDefault.Button.Colored` requires API level 28 (current min is 26)"
- errorLine1=" <style name="Widget.DeviceDefault.Button.Rounded.Colored" parent="@android:style/Widget.DeviceDefault.Button.Colored">"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/res/values/styles.xml"
- line="287"
- column="63"/>
- </issue>
-
- <issue
- id="NewApi"
- message="`@android:dimen/system_app_widget_background_radius` requires API level 31 (current min is 26)"
- errorLine1=" <corners android:radius="@android:dimen/system_app_widget_background_radius" />"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/res/drawable/widget_resize_frame.xml"
- line="20"
- column="14"/>
- </issue>
-
-</issues>
diff --git a/lint-baseline-go-res-lib.xml b/lint-baseline-go-res-lib.xml
deleted file mode 100644
index c5669f2..0000000
--- a/lint-baseline-go-res-lib.xml
+++ /dev/null
@@ -1,576 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.view.View#getWindowInsetsController`"
- errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java"
- line="203"
- column="9"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.view.WindowInsets.Type#ime`"
- errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
- errorLine2=" ~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java"
- line="203"
- column="60"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.view.WindowInsetsController#hide`"
- errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
- errorLine2=" ~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java"
- line="203"
- column="37"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.view.View#getWindowInsetsController`"
- errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsRecyclerView.java"
- line="193"
- column="17"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.view.WindowInsets.Type#ime`"
- errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
- errorLine2=" ~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsRecyclerView.java"
- line="193"
- column="68"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.view.WindowInsetsController#hide`"
- errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
- errorLine2=" ~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsRecyclerView.java"
- line="193"
- column="45"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 29): `android.appwidget.AppWidgetHostView#updateAppWidgetSize`"
- errorLine1=" widgetView.updateAppWidgetSize(new Bundle(), sizes);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/AppWidgetResizeFrame.java"
- line="399"
- column="24"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 29): `android.graphics.Rect#inset`"
- errorLine1=" potentialTaskRect.inset(insets.left, insets.top, insets.right, insets.bottom);"
- errorLine2=" ~~~~~">
- <location
- file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/BaseActivityInterface.java"
- line="248"
- column="27"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 29): `android.graphics.Rect#inset`"
- errorLine1=" potentialTaskRect.inset("
- errorLine2=" ~~~~~">
- <location
- file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/BaseActivityInterface.java"
- line="249"
- column="27"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 29): `android.graphics.Rect#inset`"
- errorLine1=" outRect.inset(Math.max(insets.left, sideMargin), Math.max(insets.top, topMargin),"
- errorLine2=" ~~~~~">
- <location
- file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/BaseActivityInterface.java"
- line="291"
- column="17"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 29): `android.graphics.Rect#inset`"
- errorLine1=" gridRect.inset(0, dp.overviewTaskThumbnailTopMarginPx, 0, 0);"
- errorLine2=" ~~~~~">
- <location
- file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/BaseActivityInterface.java"
- line="315"
- column="18"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.view.WindowManager#getCurrentWindowMetrics`"
- errorLine1=" .getCurrentWindowMetrics().getWindowInsets();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/DeviceProfile.java"
- line="236"
- column="22"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.view.WindowMetrics#getWindowInsets`"
- errorLine1=" .getCurrentWindowMetrics().getWindowInsets();"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/DeviceProfile.java"
- line="236"
- column="48"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.content.Context#getDisplay`"
- errorLine1=" if (mContext.getDisplay() != null) {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java"
- line="115"
- column="26"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.content.Context#getDisplay`"
- errorLine1=" mContext.getDisplay().getRealSize(mDisplaySize);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java"
- line="116"
- column="26"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.content.ContextWrapper#getDisplay`"
- errorLine1=" Display display = getDisplay();"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java"
- line="153"
- column="27"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `java.util.List#of`"
- errorLine1=" List.of(new Rect(0, 0, metrics.widthPixels, metrics.heightPixels)));"
- errorLine2=" ~~">
- <location
- file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java"
- line="158"
- column="26"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 29): `android.appwidget.AppWidgetHostView#resetColorResources`"
- errorLine1=" resetColorResources();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
- line="137"
- column="13"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `java.util.List#of`"
- errorLine1=" mColorExtractor.addLocation(List.of(mLastLocationRegistered));"
- errorLine2=" ~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
- line="367"
- column="46"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `java.util.List#of`"
- errorLine1=" mColorExtractor.addLocation(List.of(mLastLocationRegistered));"
- errorLine2=" ~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
- line="390"
- column="50"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#maxResizeWidth`"
- errorLine1=" (ATLEAST_S && maxResizeWidth > 0)"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
- line="91"
- column="31"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#maxResizeWidth`"
- errorLine1=" ? getSpanX(widgetPadding, maxResizeWidth, smallestCellWidth)"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
- line="92"
- column="51"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#maxResizeHeight`"
- errorLine1=" (ATLEAST_S && maxResizeHeight > 0)"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
- line="95"
- column="31"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#maxResizeHeight`"
- errorLine1=" ? getSpanY(widgetPadding, maxResizeHeight, smallestCellHeight)"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
- line="96"
- column="51"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#targetCellWidth`"
- errorLine1=" if (ATLEAST_S && targetCellWidth >= minSpanX && targetCellWidth <= maxSpanX"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
- line="101"
- column="26"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#targetCellWidth`"
- errorLine1=" if (ATLEAST_S && targetCellWidth >= minSpanX && targetCellWidth <= maxSpanX"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
- line="101"
- column="57"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#targetCellHeight`"
- errorLine1=" && targetCellHeight >= minSpanY && targetCellHeight <= maxSpanY) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
- line="102"
- column="20"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#targetCellHeight`"
- errorLine1=" && targetCellHeight >= minSpanY && targetCellHeight <= maxSpanY) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
- line="102"
- column="52"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#targetCellWidth`"
- errorLine1=" spanX = targetCellWidth;"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
- line="103"
- column="21"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#targetCellHeight`"
- errorLine1=" spanY = targetCellHeight;"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
- line="104"
- column="21"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.content.Context#getDisplay`"
- errorLine1=" final Display display = mContext.getDisplay();"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java"
- line="94"
- column="42"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 29): `android.content.pm.LauncherActivityInfo#getLoadingProgress`"
- errorLine1=" return (int) (100 * info.getLoadingProgress());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/util/PackageManagerHelper.java"
- line="338"
- column="38"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `java.util.List#of`"
- errorLine1=" private List<WidgetsListBaseEntry> mAllWidgets = List.of();"
- errorLine2=" ~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/popup/PopupDataProvider.java"
- line="64"
- column="59"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `java.util.List#of`"
- errorLine1=" private List<ItemInfo> mRecommendedWidgets = List.of();"
- errorLine2=" ~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/popup/PopupDataProvider.java"
- line="66"
- column="55"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `new android.view.SurfaceControlViewHost`"
- errorLine1=" .submit(() -> new SurfaceControlViewHost(mContext, mDisplay, mHostToken))"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
- line="91"
- column="35"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.view.SurfaceControlViewHost#getSurfacePackage`"
- errorLine1=" surfacePackage = mSurfaceControlViewHost.getSurfacePackage();"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
- line="93"
- column="54"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.view.SurfaceControlViewHost#setView`"
- errorLine1=" host.setView(view, view.getMeasuredWidth(), view.getMeasuredHeight());"
- errorLine2=" ~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
- line="127"
- column="22"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Cast from `SurfacePackage` to `Parcelable` requires API level 30 (current min is 29)"
- errorLine1=" result.putParcelable(KEY_SURFACE_PACKAGE, surfacePackage);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
- line="132"
- column="51"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.view.SurfaceControlViewHost#release`"
- errorLine1=" mSurfaceControlViewHost.release();"
- errorLine2=" ~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
- line="149"
- column="41"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.graphics.Outline#setPath`"
- errorLine1=" outline.setPath(mPath);"
- errorLine2=" ~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/popup/RoundedArrowDrawable.java"
- line="88"
- column="17"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 29): `new android.widget.EdgeEffect`"
- errorLine1=" ? new EdgeEffect(context, attrs) : new EdgeEffect(context);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/views/SpringRelativeLayout.java"
- line="49"
- column="19"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 29): `new android.widget.EdgeEffect`"
- errorLine1=" ? new EdgeEffect(context, attrs) : new EdgeEffect(context);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/views/SpringRelativeLayout.java"
- line="51"
- column="19"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.view.WindowManager.LayoutParams#setFitInsetsTypes`"
- errorLine1=" mWindowLayoutParams.setFitInsetsTypes(0);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java"
- line="316"
- column="29"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.view.WindowInsets#getInsets`"
- errorLine1=" Insets systemInsets = insets.getInsets(WindowInsets.Type.systemBars());"
- errorLine2=" ~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java"
- line="118"
- column="42"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.view.WindowInsets.Type#systemBars`"
- errorLine1=" Insets systemInsets = insets.getInsets(WindowInsets.Type.systemBars());"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java"
- line="118"
- column="70"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#loadDescription`"
- errorLine1=" CharSequence description = mItem.widgetInfo.loadDescription(getContext());"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetCell.java"
- line="193"
- column="57"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#previewLayout`"
- errorLine1=" && item.widgetInfo.previewLayout != Resources.ID_NULL) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetCell.java"
- line="214"
- column="20"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#previewLayout`"
- errorLine1=" launcherAppWidgetProviderInfo.initialLayout = item.widgetInfo.previewLayout;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetCell.java"
- line="222"
- column="59"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.view.View#getWindowInsetsController`"
- errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
- line="558"
- column="9"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.view.WindowInsets.Type#ime`"
- errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
- errorLine2=" ~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
- line="558"
- column="60"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `android.view.WindowInsetsController#hide`"
- errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
- errorLine2=" ~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
- line="558"
- column="37"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 29): `java.util.List#of`"
- errorLine1=" return new RecommendationTableData(List.of(), previewScale);"
- errorLine2=" ~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java"
- line="139"
- column="53"/>
- </issue>
-
-</issues>
diff --git a/lint-baseline-launcher3.xml b/lint-baseline-launcher3.xml
deleted file mode 100644
index 107a346..0000000
--- a/lint-baseline-launcher3.xml
+++ /dev/null
@@ -1,609 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
- <issue
- id="NewApi"
- message="Call requires API level 28 (current min is 26): `android.os.UserManager#requestQuietModeEnabled`"
- errorLine1=" showConfirm |= !userManager.requestQuietModeEnabled(!toState, userProfile);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/allapps/WorkModeSwitch.java"
- line="110"
- column="41"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `android.view.View#getWindowInsetsController`"
- errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java"
- line="203"
- column="9"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `android.view.WindowInsets.Type#ime`"
- errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
- errorLine2=" ~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java"
- line="203"
- column="60"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `android.view.WindowInsetsController#hide`"
- errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
- errorLine2=" ~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java"
- line="203"
- column="37"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `android.view.View#getWindowInsetsController`"
- errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsRecyclerView.java"
- line="193"
- column="17"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `android.view.WindowInsets.Type#ime`"
- errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
- errorLine2=" ~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsRecyclerView.java"
- line="193"
- column="68"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `android.view.WindowInsetsController#hide`"
- errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
- errorLine2=" ~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsRecyclerView.java"
- line="193"
- column="45"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 26): `android.appwidget.AppWidgetHostView#updateAppWidgetSize`"
- errorLine1=" widgetView.updateAppWidgetSize(new Bundle(), sizes);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/AppWidgetResizeFrame.java"
- line="399"
- column="24"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `android.view.WindowManager#getCurrentWindowMetrics`"
- errorLine1=" .getCurrentWindowMetrics().getWindowInsets();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/DeviceProfile.java"
- line="236"
- column="22"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `android.view.WindowMetrics#getWindowInsets`"
- errorLine1=" .getCurrentWindowMetrics().getWindowInsets();"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/DeviceProfile.java"
- line="236"
- column="48"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.content.res.Resources#getFloat`"
- errorLine1=" folderLabelTextScale = res.getFloat(R.dimen.folder_label_text_scale);"
- errorLine2=" ~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/DeviceProfile.java"
- line="256"
- column="36"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.content.res.Resources#getFloat`"
- errorLine1=" return mContext.getResources().getFloat(resId);"
- errorLine2=" ~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/util/DynamicResource.java"
- line="73"
- column="40"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 26): `android.appwidget.AppWidgetHostView#resetColorResources`"
- errorLine1=" resetColorResources();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
- line="137"
- column="13"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `java.util.List#of`"
- errorLine1=" mColorExtractor.addLocation(List.of(mLastLocationRegistered));"
- errorLine2=" ~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
- line="367"
- column="46"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `java.util.List#of`"
- errorLine1=" mColorExtractor.addLocation(List.of(mLastLocationRegistered));"
- errorLine2=" ~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
- line="390"
- column="50"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#maxResizeWidth`"
- errorLine1=" (ATLEAST_S && maxResizeWidth > 0)"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
- line="91"
- column="31"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#maxResizeWidth`"
- errorLine1=" ? getSpanX(widgetPadding, maxResizeWidth, smallestCellWidth)"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
- line="92"
- column="51"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#maxResizeHeight`"
- errorLine1=" (ATLEAST_S && maxResizeHeight > 0)"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
- line="95"
- column="31"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#maxResizeHeight`"
- errorLine1=" ? getSpanY(widgetPadding, maxResizeHeight, smallestCellHeight)"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
- line="96"
- column="51"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#targetCellWidth`"
- errorLine1=" if (ATLEAST_S && targetCellWidth >= minSpanX && targetCellWidth <= maxSpanX"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
- line="101"
- column="26"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#targetCellWidth`"
- errorLine1=" if (ATLEAST_S && targetCellWidth >= minSpanX && targetCellWidth <= maxSpanX"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
- line="101"
- column="57"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#targetCellHeight`"
- errorLine1=" && targetCellHeight >= minSpanY && targetCellHeight <= maxSpanY) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
- line="102"
- column="20"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#targetCellHeight`"
- errorLine1=" && targetCellHeight >= minSpanY && targetCellHeight <= maxSpanY) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
- line="102"
- column="52"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#targetCellWidth`"
- errorLine1=" spanX = targetCellWidth;"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
- line="103"
- column="21"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#targetCellHeight`"
- errorLine1=" spanY = targetCellHeight;"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
- line="104"
- column="21"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 28 (current min is 26): `android.app.Person#getKey`"
- errorLine1=" return people.stream().filter(person -> person.getKey() != null)"
- errorLine2=" ~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/notification/NotificationKeyData.java"
- line="72"
- column="56"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Method reference requires API level 28 (current min is 26): `Person::getKey`"
- errorLine1=" .map(Person::getKey).sorted().toArray(String[]::new);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/notification/NotificationKeyData.java"
- line="73"
- column="22"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 26): `android.content.pm.LauncherActivityInfo#getLoadingProgress`"
- errorLine1=" return (int) (100 * info.getLoadingProgress());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/util/PackageManagerHelper.java"
- line="338"
- column="38"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_LEFT`"
- errorLine1=" AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
- line="1752"
- column="17"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_RIGHT`"
- errorLine1=" : AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
- line="1753"
- column="19"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_RIGHT`"
- errorLine1=" AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
- line="1760"
- column="17"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_LEFT`"
- errorLine1=" : AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
- line="1761"
- column="19"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `java.util.List#of`"
- errorLine1=" private List<WidgetsListBaseEntry> mAllWidgets = List.of();"
- errorLine2=" ~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/popup/PopupDataProvider.java"
- line="64"
- column="59"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `java.util.List#of`"
- errorLine1=" private List<ItemInfo> mRecommendedWidgets = List.of();"
- errorLine2=" ~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/popup/PopupDataProvider.java"
- line="66"
- column="55"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `new android.view.SurfaceControlViewHost`"
- errorLine1=" .submit(() -> new SurfaceControlViewHost(mContext, mDisplay, mHostToken))"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
- line="91"
- column="35"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `android.view.SurfaceControlViewHost#getSurfacePackage`"
- errorLine1=" surfacePackage = mSurfaceControlViewHost.getSurfacePackage();"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
- line="93"
- column="54"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `android.view.SurfaceControlViewHost#setView`"
- errorLine1=" host.setView(view, view.getMeasuredWidth(), view.getMeasuredHeight());"
- errorLine2=" ~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
- line="127"
- column="22"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Cast from `SurfacePackage` to `Parcelable` requires API level 30 (current min is 26)"
- errorLine1=" result.putParcelable(KEY_SURFACE_PACKAGE, surfacePackage);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
- line="132"
- column="51"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `android.view.SurfaceControlViewHost#release`"
- errorLine1=" mSurfaceControlViewHost.release();"
- errorLine2=" ~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
- line="149"
- column="41"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `android.graphics.Outline#setPath`"
- errorLine1=" outline.setPath(mPath);"
- errorLine2=" ~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/popup/RoundedArrowDrawable.java"
- line="88"
- column="17"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 26): `new android.widget.EdgeEffect`"
- errorLine1=" ? new EdgeEffect(context, attrs) : new EdgeEffect(context);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/views/SpringRelativeLayout.java"
- line="49"
- column="19"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 26): `new android.widget.EdgeEffect`"
- errorLine1=" ? new EdgeEffect(context, attrs) : new EdgeEffect(context);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/views/SpringRelativeLayout.java"
- line="51"
- column="19"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.WindowInsets#getTappableElementInsets`"
- errorLine1=" return windowInsets.getTappableElementInsets().bottom > 0;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/graphics/SysUiScrim.java"
- line="190"
- column="33"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.graphics.Insets#bottom`"
- errorLine1=" return windowInsets.getTappableElementInsets().bottom > 0;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/graphics/SysUiScrim.java"
- line="190"
- column="20"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 28 (current min is 26): `android.appwidget.AppWidgetProviderInfo#widgetFeatures`"
- errorLine1=" int featureFlags = mProviderInfo.widgetFeatures;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetAddFlowHandler.java"
- line="93"
- column="28"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#loadDescription`"
- errorLine1=" CharSequence description = mItem.widgetInfo.loadDescription(getContext());"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetCell.java"
- line="193"
- column="57"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#previewLayout`"
- errorLine1=" && item.widgetInfo.previewLayout != Resources.ID_NULL) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetCell.java"
- line="214"
- column="20"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#previewLayout`"
- errorLine1=" launcherAppWidgetProviderInfo.initialLayout = item.widgetInfo.previewLayout;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetCell.java"
- line="222"
- column="59"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `android.view.View#getWindowInsetsController`"
- errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
- line="558"
- column="9"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `android.view.WindowInsets.Type#ime`"
- errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
- errorLine2=" ~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
- line="558"
- column="60"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `android.view.WindowInsetsController#hide`"
- errorLine1=" getWindowInsetsController().hide(WindowInsets.Type.ime());"
- errorLine2=" ~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
- line="558"
- column="37"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `java.util.List#of`"
- errorLine1=" return new RecommendationTableData(List.of(), previewScale);"
- errorLine2=" ~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java"
- line="139"
- column="53"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Method reference requires API level 28 (current min is 26): `Person::getKey`"
- errorLine1=" : Arrays.stream(persons).map(Person::getKey).sorted().toArray(String[]::new);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/model/data/WorkspaceItemInfo.java"
- line="178"
- column="42"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 26): `android.appwidget.AppWidgetHostView#setColorResources`"
- errorLine1=" setColorResources(mWallpaperColorResources);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java"
- line="528"
- column="17"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 27 (current min is 26): `android.app.WallpaperManager#getWallpaperColors`"
- errorLine1=" : WallpaperManager.getInstance(context).getWallpaperColors(FLAG_SYSTEM);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java"
- line="288"
- column="61"/>
- </issue>
-
-</issues>
diff --git a/lint-baseline-res-lib.xml b/lint-baseline-res-lib.xml
deleted file mode 100644
index e52f8fb..0000000
--- a/lint-baseline-res-lib.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
- <issue
- id="NewApi"
- message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 26)"
- errorLine1=" android:topLeftRadius="?android:attr/dialogCornerRadius""
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/res/drawable/add_item_dialog_background.xml"
- line="6"
- column="9"/>
- </issue>
-
- <issue
- id="NewApi"
- message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 26)"
- errorLine1=" android:topRightRadius="?android:attr/dialogCornerRadius" />"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/res/drawable/add_item_dialog_background.xml"
- line="7"
- column="9"/>
- </issue>
-
- <issue
- id="NewApi"
- message="`@android:style/Widget.DeviceDefault.Button.Colored` requires API level 28 (current min is 26)"
- errorLine1=" <style name="Widget.DeviceDefault.Button.Rounded.Colored" parent="@android:style/Widget.DeviceDefault.Button.Colored">"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/res/values/styles.xml"
- line="287"
- column="63"/>
- </issue>
-
- <issue
- id="NewApi"
- message="`@android:dimen/system_app_widget_background_radius` requires API level 31 (current min is 26)"
- errorLine1=" <corners android:radius="@android:dimen/system_app_widget_background_radius" />"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/apps/Launcher3/res/drawable/widget_resize_frame.xml"
- line="20"
- column="14"/>
- </issue>
-
-</issues>
diff --git a/lint-baseline.xml b/lint-baseline.xml
index 23a22be..fe005ca 100644
--- a/lint-baseline.xml
+++ b/lint-baseline.xml
@@ -1,148 +1,169 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="NewApi"
- message="Call requires API level 28 (current min is 26): `android.app.Person#getKey`">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/notification/NotificationKeyData.java"
- line="72"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.content.res.Resources#getFloat`">
+ message="Call requires API level 29 (current min is 26): `android.content.res.Resources#getFloat`"
+ errorLine1=" return mContext.getResources().getFloat(resId);"
+ errorLine2=" ~~~~~~~~">
<location
file="packages/apps/Launcher3/src/com/android/launcher3/util/DynamicResource.java"
- line="73"/>
+ line="73"
+ column="40"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 30 (current min is 26): `android.graphics.Outline#setPath`">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/popup/RoundedArrowDrawable.java"
- line="114"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 30 (current min is 26): `android.view.View#getWindowInsetsController`">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
- line="902"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 30 (current min is 26): `android.view.WindowInsets.Type#ime`">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
- line="902"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 30 (current min is 26): `android.view.WindowInsetsController#hide`">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
- line="902"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 26): `android.appwidget.AppWidgetHostView#resetColorResources`">
+ message="Call requires API level 31 (current min is 26): `android.appwidget.AppWidgetHostView#resetColorResources`"
+ errorLine1=" resetColorResources();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
- line="114"/>
+ line="117"
+ column="13"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.appwidget.AppWidgetHostView#setColorResources`">
+ message="Call requires API level 31 (current min is 30): `android.appwidget.AppWidgetHostView#setColorResources`"
+ errorLine1=" view.setColorResources(mWallpaperColorResources);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="packages/apps/Launcher3/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java"
- line="415"/>
+ line="433"
+ column="18"/>
</issue>
<issue
id="NewApi"
- message="Field requires API level 28 (current min is 26): `android.appwidget.AppWidgetProviderInfo#widgetFeatures`">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetAddFlowHandler.java"
- line="93"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_LEFT`">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
- line="1814"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_LEFT`">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
- line="1824"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_RIGHT`">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
- line="1815"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_RIGHT`">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
- line="1823"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Method reference requires API level 28 (current min is 26): `Person::getKey`">
- <location
- file="packages/apps/Launcher3/src/com/android/launcher3/model/data/WorkspaceItemInfo.java"
- line="195"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Method reference requires API level 28 (current min is 26): `Person::getKey`">
+ message="Call requires API level 28 (current min is 26): `android.app.Person#getKey`"
+ errorLine1=" return people.stream().filter(person -> person.getKey() != null)"
+ errorLine2=" ~~~~~~">
<location
file="packages/apps/Launcher3/src/com/android/launcher3/notification/NotificationKeyData.java"
- line="73"/>
+ line="72"
+ column="56"/>
</issue>
<issue
id="NewApi"
- message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 26)">
+ message="Method reference requires API level 28 (current min is 26): `Person::getKey`"
+ errorLine1=" .map(Person::getKey).sorted().toArray(String[]::new);"
+ errorLine2=" ~~~~~~~~~~~~~~">
<location
- file="packages/apps/Launcher3/res/drawable/add_item_dialog_background.xml"
- line="6"/>
+ file="packages/apps/Launcher3/src/com/android/launcher3/notification/NotificationKeyData.java"
+ line="73"
+ column="22"/>
</issue>
<issue
id="NewApi"
- message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 26)">
+ message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_LEFT`"
+ errorLine1=" AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/apps/Launcher3/res/drawable/add_item_dialog_background.xml"
- line="7"/>
+ file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
+ line="1814"
+ column="17"/>
</issue>
<issue
id="NewApi"
- message="`@android:dimen/system_app_widget_background_radius` requires API level 31 (current min is 26)">
+ message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_RIGHT`"
+ errorLine1=" : AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="packages/apps/Launcher3/res/drawable/widget_resize_frame.xml"
- line="20"/>
+ file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
+ line="1815"
+ column="19"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_RIGHT`"
+ errorLine1=" AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
+ line="1823"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_LEFT`"
+ errorLine1=" : AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
+ line="1824"
+ column="19"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 30 (current min is 26): `android.graphics.Outline#setPath`"
+ errorLine1=" outline.setPath(mPath);"
+ errorLine2=" ~~~~~~~">
+ <location
+ file="packages/apps/Launcher3/src/com/android/launcher3/popup/RoundedArrowDrawable.java"
+ line="114"
+ column="17"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 28 (current min is 26): `android.appwidget.AppWidgetProviderInfo#widgetFeatures`"
+ errorLine1=" int featureFlags = mProviderInfo.widgetFeatures;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetAddFlowHandler.java"
+ line="93"
+ column="28"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 30 (current min is 26): `android.view.View#getWindowInsetsController`"
+ errorLine1=" WindowInsetsController insetsController = getWindowInsetsController();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
+ line="820"
+ column="51"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 30 (current min is 26): `android.view.WindowInsets.Type#ime`"
+ errorLine1=" insetsController.hide(WindowInsets.Type.ime());"
+ errorLine2=" ~~~">
+ <location
+ file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
+ line="822"
+ column="53"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Call requires API level 30 (current min is 26): `android.view.WindowInsetsController#hide`"
+ errorLine1=" insetsController.hide(WindowInsets.Type.ime());"
+ errorLine2=" ~~~~">
+ <location
+ file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
+ line="822"
+ column="30"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Method reference requires API level 28 (current min is 26): `Person::getKey`"
+ errorLine1=" : Arrays.stream(persons).map(Person::getKey).sorted().toArray(String[]::new);"
+ errorLine2=" ~~~~~~~~~~~~~~">
+ <location
+ file="packages/apps/Launcher3/src/com/android/launcher3/model/data/WorkspaceItemInfo.java"
+ line="194"
+ column="42"/>
</issue>
</issues>
\ No newline at end of file
diff --git a/lint-baseline2.xml b/lint-baseline2.xml
new file mode 100644
index 0000000..84f1b15
--- /dev/null
+++ b/lint-baseline2.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
+
+ <issue
+ id="NewApi"
+ message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 26)"
+ errorLine1=' android:topLeftRadius="?android:attr/dialogCornerRadius"'
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/apps/Launcher3/res/drawable/add_item_dialog_background.xml"
+ line="6"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 26)"
+ errorLine1=' android:topRightRadius="?android:attr/dialogCornerRadius" />'
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/apps/Launcher3/res/drawable/add_item_dialog_background.xml"
+ line="7"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="`@android:dimen/system_app_widget_background_radius` requires API level 31 (current min is 26)"
+ errorLine1=' <corners android:radius="@android:dimen/system_app_widget_background_radius" />'
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/apps/Launcher3/res/drawable/widget_resize_frame.xml"
+ line="20"
+ column="14"/>
+ </issue>
+
+</issues>
\ No newline at end of file
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 2ebbe6f..5890f14 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -1161,6 +1161,7 @@
SystemUiProxy.INSTANCE.get(mLauncher)
.registerRemoteTransition(mLauncherOpenTransition, homeCheck);
if (mBackAnimationController != null) {
+ mBackAnimationController.registerComponentCallbacks();
mBackAnimationController.registerBackCallbacks(mHandler);
}
}
@@ -1168,6 +1169,7 @@
public void onActivityDestroyed() {
unregisterRemoteAnimations();
unregisterRemoteTransitions();
+ mLauncher.removeOnDeviceProfileChangeListener(this);
SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(null);
ORDERED_BG_EXECUTOR.execute(() -> mLauncher.getContentResolver()
.unregisterContentObserver(mAnimationRemovalObserver));
@@ -1200,6 +1202,7 @@
mWallpaperOpenTransitionRunner = null;
if (mBackAnimationController != null) {
mBackAnimationController.unregisterBackCallbacks();
+ mBackAnimationController.unregisterComponentCallbacks();
mBackAnimationController = null;
}
}
@@ -1607,7 +1610,7 @@
|| mLauncher.getWorkspace().isOverlayShown()
|| shouldPlayFallbackClosingAnimation(appTargets);
- boolean playWorkspaceReveal = true;
+ boolean playWorkspaceReveal = !fromPredictiveBack;
boolean skipAllAppsScale = false;
if (fromUnlock) {
anim.play(getUnlockWindowAnimator(appTargets, wallpaperTargets));
@@ -1649,7 +1652,7 @@
// targets list because it is already visible). In that case, we force
// invisibility on touch down, and only reset it after the animation to home
// is initialized.
- if (launcherIsForceInvisibleOrOpening) {
+ if (launcherIsForceInvisibleOrOpening || fromPredictiveBack) {
addCujInstrumentation(anim, playFallBackAnimation
? Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK
: Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME);
@@ -1666,7 +1669,7 @@
// Only register the content animation for cancellation when state changes
mLauncher.getStateManager().setCurrentAnimation(anim);
- if (mLauncher.isInState(LauncherState.ALL_APPS)) {
+ if (mLauncher.isInState(LauncherState.ALL_APPS) && !fromPredictiveBack) {
Pair<AnimatorSet, Runnable> contentAnimator =
getLauncherContentAnimator(false, LAUNCHER_RESUME_START_DELAY,
skipAllAppsScale);
@@ -1677,10 +1680,8 @@
contentAnimator.second.run();
}
});
- } else {
- if (playWorkspaceReveal) {
+ } else if (playWorkspaceReveal) {
anim.play(new WorkspaceRevealAnim(mLauncher, false).getAnimators());
- }
}
}
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index ea1d286..f012197 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -56,6 +56,11 @@
private final T mActivityContext;
private int mNumPredictedAppsPerRow;
+ // Vertical padding of the icon that contributes to the expected cell height.
+ private final int mVerticalPadding;
+ // Extra padding that is used in the top app rows (prediction and search) that is not used in
+ // the regular A-Z list. This only applies to single line label.
+ private final int mTopRowExtraHeight;
// Helper to drawing the focus indicator.
private final FocusIndicatorHelper mFocusHelper;
@@ -78,6 +83,10 @@
mFocusHelper = new SimpleFocusIndicatorHelper(this);
mActivityContext = ActivityContext.lookupContext(context);
mNumPredictedAppsPerRow = mActivityContext.getDeviceProfile().numShownAllAppsColumns;
+ mTopRowExtraHeight = getResources().getDimensionPixelSize(
+ R.dimen.all_apps_search_top_row_extra_height);
+ mVerticalPadding = getResources().getDimensionPixelSize(
+ R.dimen.all_apps_predicted_icon_vertical_padding);
updateVisibility();
}
@@ -126,13 +135,11 @@
int iconHeight = deviceProfile.allAppsIconSizePx;
int iconPadding = deviceProfile.allAppsIconDrawablePaddingPx;
int textHeight = Utilities.calculateTextHeight(deviceProfile.allAppsIconTextSizePx);
- int verticalPadding = getResources().getDimensionPixelSize(
- R.dimen.all_apps_predicted_icon_vertical_padding);
- int totalHeight = iconHeight + iconPadding + textHeight + verticalPadding * 2;
- if (FeatureFlags.enableTwolineAllapps()) {
- // Add extra textHeight to the existing total height.
- totalHeight += textHeight;
- }
+ int totalHeight = iconHeight + iconPadding + textHeight + mVerticalPadding * 2;
+ // Prediction row height will be 4dp bigger than the regular apps in A-Z list when two line
+ // is not enabled. Otherwise, the extra height will increase by just the textHeight.
+ int extraHeight = FeatureFlags.enableTwolineAllapps() ? textHeight : mTopRowExtraHeight;
+ totalHeight += extraHeight;
return getVisibility() == GONE ? 0 : totalHeight + getPaddingTop() + getPaddingBottom();
}
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index a7e8118..b7e1092 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.statehandlers;
+import static android.view.View.VISIBLE;
+
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
@@ -269,6 +271,9 @@
if (dragLayer != null) {
dragLayer.setVisibility(visibility);
}
+ if (mLauncher instanceof QuickstepLauncher ql && ql.getTaskbarUIController() != null) {
+ ql.getTaskbarUIController().onLauncherVisibilityChanged(visibility == VISIBLE);
+ }
}
private void markLauncherPaused() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
index 6e88780..9dac89d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -15,20 +15,26 @@
*/
package com.android.launcher3.taskbar;
+import static android.window.SplashScreen.SPLASH_SCREEN_STYLE_UNDEFINED;
+
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.animation.Animator;
+import android.app.ActivityOptions;
import android.view.KeyEvent;
import android.view.View;
+import android.window.RemoteTransition;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayDragLayer;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.GroupTask;
+import com.android.quickstep.util.SlideInRemoteTransition;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -142,19 +148,23 @@
return -1;
}
+ RemoteTransition remoteTransition = new RemoteTransition(new SlideInRemoteTransition(
+ Utilities.isRtl(mControllers.taskbarActivityContext.getResources())));
if (mOnDesktop) {
UI_HELPER_EXECUTOR.execute(() ->
SystemUiProxy.INSTANCE.get(mKeyboardQuickSwitchView.getContext())
.showDesktopApp(task.task1.key.id));
} else if (task.task2 == null) {
- UI_HELPER_EXECUTOR.execute(() ->
- ActivityManagerWrapper.getInstance().startActivityFromRecents(
- task.task1.key,
- mControllers.taskbarActivityContext.getActivityLaunchOptions(
- taskView == null ? mKeyboardQuickSwitchView : taskView, null)
- .options));
+ UI_HELPER_EXECUTOR.execute(() -> {
+ ActivityOptions activityOptions = mControllers.taskbarActivityContext
+ .makeDefaultActivityOptions(SPLASH_SCREEN_STYLE_UNDEFINED).options;
+ activityOptions.setRemoteTransition(remoteTransition);
+
+ ActivityManagerWrapper.getInstance().startActivityFromRecents(
+ task.task1.key, activityOptions);
+ });
} else {
- mControllers.uiController.launchSplitTasks(task);
+ mControllers.uiController.launchSplitTasks(task, remoteTransition);
}
return -1;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 159a6ef..20e977b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.taskbar.TaskbarEduTooltipControllerKt.TOOLTIP_STEP_FEATURES;
import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_VISIBLE;
import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
import android.animation.Animator;
import android.animation.AnimatorSet;
@@ -27,6 +28,7 @@
import android.util.Log;
import android.view.TaskTransitionSpec;
import android.view.WindowManagerGlobal;
+import android.window.RemoteTransition;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -40,11 +42,13 @@
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.taskbar.bubbles.BubbleBarController;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.OnboardingPrefs;
+import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.RecentsAnimationCallbacks;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.views.RecentsView;
@@ -199,6 +203,16 @@
return null;
}
+ DesktopVisibilityController desktopController =
+ LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
+ final boolean onDesktop =
+ isDesktopModeSupported()
+ && desktopController != null
+ && desktopController.areFreeformTasksVisible();
+ if (onDesktop) {
+ isVisible = false;
+ }
+
mTaskbarLauncherStateController.updateStateForFlag(FLAG_VISIBLE, isVisible);
return mTaskbarLauncherStateController.applyState(fromInit ? 0 : duration, startAnimation);
}
@@ -390,8 +404,9 @@
}
@Override
- public void launchSplitTasks(@NonNull GroupTask groupTask) {
- mLauncher.launchSplitTasks(groupTask);
+ public void launchSplitTasks(
+ @NonNull GroupTask groupTask, @Nullable RemoteTransition remoteTransition) {
+ mLauncher.launchSplitTasks(groupTask, remoteTransition);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 709d3ba..6d4fc18 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -61,6 +61,7 @@
import android.graphics.Region;
import android.graphics.Region.Op;
import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.PaintDrawable;
import android.graphics.drawable.RotateDrawable;
import android.inputmethodservice.InputMethodService;
@@ -96,6 +97,7 @@
import com.android.launcher3.util.TouchController;
import com.android.launcher3.util.window.WindowManagerProxy;
import com.android.launcher3.views.BaseDragLayer;
+import com.android.systemui.shared.navigationbar.KeyButtonRipple;
import com.android.systemui.shared.rotation.FloatingRotationButton;
import com.android.systemui.shared.rotation.RotationButton;
import com.android.systemui.shared.rotation.RotationButtonController;
@@ -665,6 +667,11 @@
for (ImageView button : mAllButtons) {
button.setImageTintList(ColorStateList.valueOf(iconColor));
+ Drawable background = button.getBackground();
+ if (background instanceof KeyButtonRipple) {
+ ((KeyButtonRipple) background).setDarkIntensity(
+ mTaskbarNavButtonDarkIntensity.value);
+ }
}
}
@@ -751,6 +758,7 @@
mA11yButton, res, isInKidsMode, isInSetup, isThreeButtonNav,
mContext.isPhoneMode(), mWindowManagerProxy.getRotation(mContext));
navButtonLayoutter.layoutButtons(mContext, isA11yButtonPersistent());
+ updateButtonsBackground();
updateNavButtonColor();
return;
}
@@ -870,7 +878,27 @@
}
}
}
+ }
+ private void updateButtonsBackground() {
+ boolean clipped = !mContext.isPhoneButtonNavMode();
+ mNavButtonContainer.setClipToPadding(clipped);
+ mNavButtonContainer.setClipChildren(clipped);
+ mNavButtonsView.setClipToPadding(clipped);
+ mNavButtonsView.setClipChildren(clipped);
+
+ for (ImageView button : mAllButtons) {
+ updateButtonBackground(button, mContext.isPhoneButtonNavMode());
+ }
+ }
+
+ private static void updateButtonBackground(View view, boolean isPhoneButtonNavMode) {
+ if (isPhoneButtonNavMode) {
+ view.setBackground(new KeyButtonRipple(view.getContext(), view,
+ R.dimen.key_button_ripple_max_width));
+ } else {
+ view.setBackgroundResource(R.drawable.taskbar_icon_click_feedback_roundrect);
+ }
}
public void onDestroy() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index ad2dc23..382276a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.taskbar;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
import android.animation.Animator;
@@ -83,6 +85,7 @@
// States that affect whether region sampling is enabled or not
private boolean mIsStashed;
+ private boolean mIsLumaSamplingEnabled;
private boolean mTaskbarHidden;
private float mTranslationYForSwipe;
@@ -149,7 +152,7 @@
});
initRegionSampler();
if (mActivity.isPhoneGestureNavMode()) {
- onIsStashedChanged(true);
+ onIsStashedChanged();
}
}
@@ -232,10 +235,23 @@
}
/** Called when taskbar is stashed or unstashed. */
- public void onIsStashedChanged(boolean isStashed) {
- mIsStashed = isStashed;
+ public void onIsStashedChanged() {
+ mIsStashed = isStashedHandleVisible();
+ updateSamplingState();
+ }
+
+ public void onNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
+ if (DEFAULT_DISPLAY != displayId) {
+ return;
+ }
+
+ mIsLumaSamplingEnabled = enable;
+ updateSamplingState();
+ }
+
+ private void updateSamplingState() {
updateRegionSamplingWindowVisibility();
- if (isStashed) {
+ if (shouldSample()) {
mStashedHandleView.updateSampledRegion(mStashedHandleBounds);
mRegionSamplingHelper.start(mStashedHandleView.getSampledRegion());
} else {
@@ -243,6 +259,10 @@
}
}
+ private boolean shouldSample() {
+ return mIsStashed && mIsLumaSamplingEnabled;
+ }
+
protected void updateStashedHandleHintScale() {
mStashedHandleView.setScaleX(mTaskbarStashedHandleHintScale.value);
mStashedHandleView.setScaleY(mTaskbarStashedHandleHintScale.value);
@@ -282,7 +302,7 @@
}
private void updateRegionSamplingWindowVisibility() {
- mRegionSamplingHelper.setWindowVisible(mIsStashed && !mTaskbarHidden);
+ mRegionSamplingHelper.setWindowVisible(shouldSample() && !mTaskbarHidden);
}
public boolean isStashedHandleVisible() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index eff6e27..7ad2c68 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -377,6 +377,8 @@
onSystemBarAttributesChanged(sharedState.systemBarAttrsDisplayId,
sharedState.systemBarAttrsBehavior);
onNavButtonsDarkIntensityChanged(sharedState.navButtonsDarkIntensity);
+ onNavigationBarLumaSamplingEnabled(sharedState.mLumaSamplingDisplayId,
+ sharedState.mIsLumaSamplingEnabled);
if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
// W/ the flag not set this entire class gets re-created, which resets the value of
@@ -456,6 +458,10 @@
return mTransientTaskbarBounds;
}
+ protected float getCurrentTaskbarWidth() {
+ return mControllers.taskbarViewController.getCurrentVisualTaskbarWidth();
+ }
+
@Override
public StatsLogManager getStatsLogManager() {
// Used to mock, can't mock a default interface method directly
@@ -841,6 +847,11 @@
.updateValue(darkIntensity);
}
+ public void onNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
+ mControllers.stashedHandleViewController.onNavigationBarLumaSamplingEnabled(displayId,
+ enable);
+ }
+
/**
* Called to update a {@link AutohideSuspendFlag} with a new value.
*/
@@ -1341,6 +1352,16 @@
}
}
+ /** Unstashes the Bubble Bar if it is stashed. */
+ @VisibleForTesting
+ public void unstashBubbleBarIfStashed() {
+ mControllers.bubbleControllers.ifPresent(bubbleControllers -> {
+ if (bubbleControllers.bubbleStashController.isStashed()) {
+ bubbleControllers.bubbleStashController.showBubbleBar(false);
+ }
+ });
+ }
+
protected boolean isUserSetupComplete() {
return mIsUserSetupComplete;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index 30f8d56..e290c3f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -203,12 +203,7 @@
val newBackgroundHeight =
mapRange(progress, backgroundHeightWhileAnimating, maxTransientTaskbarHeight)
val fullWidth = transientBackgroundBounds.width()
-
- // .9f is here to restrict min width of the background while animating, so transient
- // background keeps it pill shape until animation end.
- val animationWidth =
- if (DisplayController.isTransientTaskbar(context)) fullWidth.toFloat() * .9f
- else fullWidth.toFloat()
+ val animationWidth = context.currentTaskbarWidth
val backgroundWidthWhileAnimating =
if (isAnimatingPinning) animationWidth else stashedHandleWidth.toFloat()
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 1a34b7a..7ebc18d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -101,8 +101,10 @@
windowLayoutParams.providedInsets =
if (enableTaskbarNoRecreate()) {
- getProvidedInsets(controllers.sharedState!!.insetsFrameProviders!!,
- insetsRoundedCornerFlag)
+ getProvidedInsets(
+ controllers.sharedState!!.insetsFrameProviders!!,
+ insetsRoundedCornerFlag
+ )
} else {
getProvidedInsets(insetsRoundedCornerFlag)
}
@@ -164,19 +166,18 @@
/**
* This is for when ENABLE_TASKBAR_NO_RECREATION is enabled. We generate one instance of
- * providedInsets and use it across the entire lifecycle of TaskbarManager. The only thing
- * we need to reset is nav bar flags based on insetsRoundedCornerFlag.
+ * providedInsets and use it across the entire lifecycle of TaskbarManager. The only thing we
+ * need to reset is nav bar flags based on insetsRoundedCornerFlag.
*/
- private fun getProvidedInsets(providedInsets: Array<InsetsFrameProvider>,
- insetsRoundedCornerFlag: Int): Array<InsetsFrameProvider> {
+ private fun getProvidedInsets(
+ providedInsets: Array<InsetsFrameProvider>,
+ insetsRoundedCornerFlag: Int
+ ): Array<InsetsFrameProvider> {
val navBarsFlag =
- (if (context.isGestureNav) FLAG_SUPPRESS_SCRIM else 0) or insetsRoundedCornerFlag
+ (if (context.isGestureNav) FLAG_SUPPRESS_SCRIM else 0) or insetsRoundedCornerFlag
for (provider in providedInsets) {
if (provider.type == navigationBars()) {
- provider.setFlags(
- navBarsFlag,
- FLAG_SUPPRESS_SCRIM or FLAG_INSETS_ROUNDED_CORNER
- )
+ provider.setFlags(navBarsFlag, FLAG_SUPPRESS_SCRIM or FLAG_INSETS_ROUNDED_CORNER)
}
}
return providedInsets
@@ -184,25 +185,22 @@
/**
* The inset types and number of insets provided have to match for both gesture nav and button
- * nav. The values and the order of the elements in array are allowed to differ.
- * Reason being WM does not allow types and number of insets changing for a given window once it
- * is added into the hierarchy for performance reasons.
+ * nav. The values and the order of the elements in array are allowed to differ. Reason being WM
+ * does not allow types and number of insets changing for a given window once it is added into
+ * the hierarchy for performance reasons.
*/
private fun getProvidedInsets(insetsRoundedCornerFlag: Int): Array<InsetsFrameProvider> {
val navBarsFlag =
- (if (context.isGestureNav) FLAG_SUPPRESS_SCRIM else 0) or insetsRoundedCornerFlag
+ (if (context.isGestureNav) FLAG_SUPPRESS_SCRIM else 0) or insetsRoundedCornerFlag
return arrayOf(
- InsetsFrameProvider(insetsOwner, 0, navigationBars())
- .setFlags(
- navBarsFlag,
- FLAG_SUPPRESS_SCRIM or FLAG_INSETS_ROUNDED_CORNER
- ),
- InsetsFrameProvider(insetsOwner, 0, tappableElement()),
- InsetsFrameProvider(insetsOwner, 0, mandatorySystemGestures()),
- InsetsFrameProvider(insetsOwner, INDEX_LEFT, systemGestures())
- .setSource(SOURCE_DISPLAY),
- InsetsFrameProvider(insetsOwner, INDEX_RIGHT, systemGestures())
- .setSource(SOURCE_DISPLAY)
+ InsetsFrameProvider(insetsOwner, 0, navigationBars())
+ .setFlags(navBarsFlag, FLAG_SUPPRESS_SCRIM or FLAG_INSETS_ROUNDED_CORNER),
+ InsetsFrameProvider(insetsOwner, 0, tappableElement()),
+ InsetsFrameProvider(insetsOwner, 0, mandatorySystemGestures()),
+ InsetsFrameProvider(insetsOwner, INDEX_LEFT, systemGestures())
+ .setSource(SOURCE_DISPLAY),
+ InsetsFrameProvider(insetsOwner, INDEX_RIGHT, systemGestures())
+ .setSource(SOURCE_DISPLAY)
)
}
@@ -216,46 +214,52 @@
provider.insetsSize = getInsetsForGravity(tappableHeight, gravity)
} else if (provider.type == systemGestures() && provider.index == INDEX_LEFT) {
val leftIndexInset =
- if (context.isThreeButtonNav) 0
- else gestureNavSettingsObserver.getLeftSensitivityForCallingUser(res)
+ if (context.isThreeButtonNav) 0
+ else gestureNavSettingsObserver.getLeftSensitivityForCallingUser(res)
provider.insetsSize = Insets.of(leftIndexInset, 0, 0, 0)
} else if (provider.type == systemGestures() && provider.index == INDEX_RIGHT) {
val rightIndexInset =
- if (context.isThreeButtonNav) 0
- else gestureNavSettingsObserver.getRightSensitivityForCallingUser(res)
+ if (context.isThreeButtonNav) 0
+ else gestureNavSettingsObserver.getRightSensitivityForCallingUser(res)
provider.insetsSize = Insets.of(0, 0, rightIndexInset, 0)
}
// When in gesture nav, report the stashed height to the IME, to allow hiding the
// IME navigation bar.
- val imeInsetsSize = if (ENABLE_HIDE_IME_CAPTION_BAR && context.isGestureNav) {
- getInsetsForGravity(controllers.taskbarStashController.stashedHeight, gravity);
- } else {
- getInsetsForGravity(taskbarHeightForIme, gravity)
- }
+ val imeInsetsSize =
+ if (ENABLE_HIDE_IME_CAPTION_BAR && context.isGestureNav) {
+ getInsetsForGravity(controllers.taskbarStashController.stashedHeight, gravity)
+ } else {
+ getInsetsForGravity(taskbarHeightForIme, gravity)
+ }
val imeInsetsSizeOverride =
- arrayOf(
- InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
- InsetsFrameProvider.InsetsSizeOverride(TYPE_VOICE_INTERACTION,
- // No-op override to keep the size and types in sync with the
- // override below (insetsSizeOverrides must have the same length and
- // types after the window is added according to
- // WindowManagerService#relayoutWindow)
- provider.insetsSize)
+ arrayOf(
+ InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
+ InsetsFrameProvider.InsetsSizeOverride(
+ TYPE_VOICE_INTERACTION,
+ // No-op override to keep the size and types in sync with the
+ // override below (insetsSizeOverrides must have the same length and
+ // types after the window is added according to
+ // WindowManagerService#relayoutWindow)
+ provider.insetsSize
)
+ )
// Use 0 tappableElement insets for the VoiceInteractionWindow when gesture nav is enabled.
val visInsetsSizeForTappableElement =
- if (context.isGestureNav) getInsetsForGravity(0, gravity)
- else getInsetsForGravity(tappableHeight, gravity)
+ if (context.isGestureNav) getInsetsForGravity(0, gravity)
+ else getInsetsForGravity(tappableHeight, gravity)
val insetsSizeOverrideForTappableElement =
- arrayOf(
- InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
- InsetsFrameProvider.InsetsSizeOverride(TYPE_VOICE_INTERACTION,
- visInsetsSizeForTappableElement
- ),
- )
- if ((context.isGestureNav || ENABLE_TASKBAR_NAVBAR_UNIFICATION)
- && provider.type == tappableElement()) {
+ arrayOf(
+ InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
+ InsetsFrameProvider.InsetsSizeOverride(
+ TYPE_VOICE_INTERACTION,
+ visInsetsSizeForTappableElement
+ ),
+ )
+ if (
+ (context.isGestureNav || ENABLE_TASKBAR_NAVBAR_UNIFICATION) &&
+ provider.type == tappableElement()
+ ) {
provider.insetsSizeOverrides = insetsSizeOverrideForTappableElement
} else if (provider.type != systemGestures()) {
// We only override insets at the bottom of the screen
@@ -264,8 +268,8 @@
}
/**
- * @return [Insets] where the [inset] is either used as a bottom inset or
- * right/left inset if using 3 button nav
+ * @return [Insets] where the [inset] is either used as a bottom inset or right/left inset if
+ * using 3 button nav
*/
private fun getInsetsForGravity(inset: Int, gravity: Int): Insets {
if ((gravity and Gravity.BOTTOM) == Gravity.BOTTOM) {
@@ -277,7 +281,7 @@
val isSeascape = (gravity and Gravity.START) == Gravity.START
val leftInset = if (isSeascape) inset else 0
val rightInset = if (isSeascape) 0 else inset
- return Insets.of(leftInset , 0, rightInset, 0)
+ return Insets.of(leftInset, 0, rightInset, 0)
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index a2e5e81..33641a4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -540,6 +540,14 @@
}
}
+ public void onNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
+ mSharedState.mLumaSamplingDisplayId = displayId;
+ mSharedState.mIsLumaSamplingEnabled = enable;
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.onNavigationBarLumaSamplingEnabled(displayId, enable);
+ }
+ }
+
private void removeActivityCallbacksAndListeners() {
if (mActivity != null) {
mActivity.removeOnDeviceProfileChangeListener(mDebugActivityDeviceProfileChanged);
@@ -564,6 +572,7 @@
UI_HELPER_EXECUTOR.execute(
() -> mTaskbarBroadcastReceiver.unregisterReceiverSafely(mContext));
destroyExistingTaskbar();
+ removeTaskbarRootViewFromWindow();
if (mUserUnlocked) {
DisplayController.INSTANCE.get(mContext).removeChangeListener(mRecreationListener);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
index 6cb28ee..5b117fc 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
@@ -20,6 +20,7 @@
import android.view.View
import androidx.annotation.VisibleForTesting
import androidx.core.animation.doOnEnd
+import com.android.app.animation.Interpolators
import com.android.launcher3.LauncherPrefs
import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE
@@ -106,6 +107,7 @@
taskbarViewController.taskbarIconTranslationXForPinning.animateToValue(animateToValue)
)
+ animatorSet.interpolator = Interpolators.EMPHASIZED
return animatorSet
}
@@ -129,6 +131,6 @@
companion object {
const val PINNING_PERSISTENT = 1f
const val PINNING_TRANSIENT = 0f
- const val PINNING_ANIMATION_DURATION = 500L
+ const val PINNING_ANIMATION_DURATION = 600L
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
index d09f74c..41b777b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
@@ -52,6 +52,10 @@
// TaskbarManager#onNavButtonsDarkIntensityChanged()
public float navButtonsDarkIntensity;
+ // TaskbarManager#onNavigationBarLumaSamplingEnabled()
+ public int mLumaSamplingDisplayId;
+ public boolean mIsLumaSamplingEnabled;
+
public boolean setupUIVisible = false;
public boolean allAppsVisible = false;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 48c83da..eced202 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -590,6 +590,7 @@
mAnimator.addListener(AnimatorListeners.forEndCallback(() -> {
mAnimator = null;
mIsStashed = isStashed;
+ onIsStashedChanged();
}));
return;
}
@@ -604,7 +605,7 @@
@Override
public void onAnimationStart(Animator animation) {
mIsStashed = isStashed;
- onIsStashedChanged(mIsStashed);
+ onIsStashedChanged();
cancelTimeoutIfExists();
}
@@ -829,9 +830,9 @@
.setDuration(TASKBAR_HINT_STASH_DURATION).start();
}
- private void onIsStashedChanged(boolean isStashed) {
+ private void onIsStashedChanged() {
mControllers.runAfterInit(() -> {
- mControllers.stashedHandleViewController.onIsStashedChanged(isStashed);
+ mControllers.stashedHandleViewController.onIsStashedChanged();
mControllers.taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
});
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 7edf0d3..ecedf8a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -25,6 +25,7 @@
import android.graphics.drawable.BitmapDrawable;
import android.view.MotionEvent;
import android.view.View;
+import android.window.RemoteTransition;
import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
@@ -302,7 +303,8 @@
/**
* Launches the given task in split-screen.
*/
- public void launchSplitTasks(@NonNull GroupTask groupTask) { }
+ public void launchSplitTasks(
+ @NonNull GroupTask groupTask, @Nullable RemoteTransition remoteTransition) { }
/**
* Returns the matching view (if any) in the taskbar.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 33fb395..1f03f24 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -159,6 +159,8 @@
private final int mTransientIconSize;
private final int mPersistentIconSize;
+ private final float mTaskbarLeftRightMargin;
+
public TaskbarViewController(TaskbarActivityContext activity, TaskbarView taskbarView) {
mActivity = activity;
mTransientTaskbarDp = mActivity.getTransientTaskbarDeviceProfile();
@@ -184,6 +186,9 @@
mTaskbarThemedIconsBackgroundColor = ColorUtils.HSLToColor(colorHSL);
}
mIsRtl = Utilities.isRtl(mTaskbarView.getResources());
+ mTaskbarLeftRightMargin = mActivity.getResources().getDimensionPixelSize(
+ R.dimen.transient_taskbar_padding);
+
}
public void init(TaskbarControllers controllers) {
@@ -391,6 +396,26 @@
}
}
+ /**
+ * Calculates visual taskbar view width.
+ */
+ public float getCurrentVisualTaskbarWidth() {
+ if (mTaskbarView.getIconViews().length == 0) {
+ return 0;
+ }
+
+ View[] iconViews = mTaskbarView.getIconViews();
+
+ int leftIndex = mActivity.getDeviceProfile().isQsbInline && !mIsRtl ? 1 : 0;
+ int rightIndex = mActivity.getDeviceProfile().isQsbInline && mIsRtl
+ ? iconViews.length - 2
+ : iconViews.length - 1;
+
+ float left = iconViews[leftIndex].getX();
+ float right = iconViews[rightIndex].getRight() + iconViews[rightIndex].getTranslationX();
+
+ return right - left + (2 * mTaskbarLeftRightMargin);
+ }
/**
* Sets the translation of the TaskbarView during the swipe up gesture.
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepAppWidgetHost.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepAppWidgetHost.java
index 6659fa0..45813ce 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepAppWidgetHost.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepAppWidgetHost.java
@@ -25,6 +25,7 @@
import androidx.annotation.NonNull;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.util.Executors;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.LauncherWidgetHolder;
@@ -55,7 +56,10 @@
@Override
public void onAppWidgetRemoved(int appWidgetId) {
- mAppWidgetRemovedCallback.accept(appWidgetId);
+ // Route the call via model thread, in case it comes while a loader-bind is in progress
+ Executors.MODEL_EXECUTOR.execute(
+ () -> Executors.MAIN_EXECUTOR.execute(
+ () -> mAppWidgetRemovedCallback.accept(appWidgetId)));
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 806c26b..0d4a7f0 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -85,6 +85,7 @@
import android.window.BackEvent;
import android.window.OnBackAnimationCallback;
import android.window.OnBackInvokedDispatcher;
+import android.window.RemoteTransition;
import android.window.SplashScreen;
import androidx.annotation.BinderThread;
@@ -1277,7 +1278,8 @@
/**
* Launches the given {@link GroupTask} in splitscreen.
*/
- public void launchSplitTasks(@NonNull GroupTask groupTask) {
+ public void launchSplitTasks(
+ @NonNull GroupTask groupTask, @Nullable RemoteTransition remoteTransition) {
// Top/left and bottom/right tasks respectively.
Task task1 = groupTask.task1;
// task2 should never be null when calling this method. Allow a crash to catch invalid calls
@@ -1291,7 +1293,8 @@
/* freezeTaskList= */ false,
groupTask.mSplitBounds == null
? SNAP_TO_50_50
- : groupTask.mSplitBounds.snapPosition);
+ : groupTask.mSplitBounds.snapPosition,
+ remoteTransition);
}
/**
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
index 1a75535..0fb2b17 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
@@ -34,10 +34,10 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.util.IntSet;
+import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.LauncherWidgetHolder;
-import com.android.launcher3.widget.custom.CustomWidgetManager;
import java.util.ArrayList;
import java.util.Collections;
@@ -67,11 +67,11 @@
private static AppWidgetHost sWidgetHost = null;
+ private final UpdateHandler mUpdateHandler = this::onWidgetUpdate;
private final @Nullable RemoteViews.InteractionHandler mInteractionHandler;
private final @NonNull IntConsumer mAppWidgetRemovedCallback;
- private final ArrayList<ProviderChangedListener> mProviderChangedListeners = new ArrayList<>();
// Map to all pending updated keyed with appWidgetId;
private final SparseArray<PendingUpdate> mPendingUpdateMap = new SparseArray<>();
@@ -175,7 +175,10 @@
@Override
public void destroy() {
try {
- MAIN_EXECUTOR.submit(() -> sHolders.remove(this)).get();
+ MAIN_EXECUTOR.submit(() -> {
+ clearViews();
+ sHolders.remove(this);
+ }).get();
} catch (Exception e) {
Log.e(TAG, "Failed to remove self from holder list", e);
}
@@ -188,26 +191,6 @@
}
/**
- * Add a listener that is triggered when the providers of the widgets are changed
- * @param listener The listener that notifies when the providers changed
- */
- @Override
- public void addProviderChangeListener(
- @NonNull LauncherWidgetHolder.ProviderChangedListener listener) {
- MAIN_EXECUTOR.execute(() -> mProviderChangedListeners.add(listener));
- }
-
- /**
- * Remove the specified listener from the host
- * @param listener The listener that is to be removed from the host
- */
- @Override
- public void removeProviderChangeListener(
- LauncherWidgetHolder.ProviderChangedListener listener) {
- MAIN_EXECUTOR.execute(() -> mProviderChangedListeners.remove(listener));
- }
-
- /**
* Stop the host from updating the widget views
*/
@Override
@@ -220,44 +203,41 @@
setListeningFlag(false);
}
- /**
- * Create a view for the specified app widget
- * @param context The activity context for which the view is created
- * @param appWidgetId The ID of the widget
- * @param appWidget The {@link LauncherAppWidgetProviderInfo} of the widget
- * @return A view for the widget
- */
+ @Override
+ public SafeCloseable addOnUpdateListener(int appWidgetId,
+ LauncherAppWidgetProviderInfo appWidget, Runnable callback) {
+ UpdateHandler handler = new UpdateHandler() {
+ @Override
+ public <T> void onWidgetUpdate(int widgetId, UpdateKey<T> key, T data) {
+ if (KEY_VIEWS_UPDATE == key) {
+ callback.run();
+ }
+ }
+ };
+ QuickstepWidgetHolderListener holderListener = getHolderListener(appWidgetId);
+ holderListener.addHolder(handler);
+ return () -> holderListener.mListeningHolders.remove(handler);
+ }
+
@NonNull
@Override
- public LauncherAppWidgetHostView createView(@NonNull Context context, int appWidgetId,
- @NonNull LauncherAppWidgetProviderInfo appWidget) {
- if (appWidget.isCustomWidget()) {
- LauncherAppWidgetHostView lahv = new LauncherAppWidgetHostView(context);
- lahv.setAppWidget(appWidgetId, appWidget);
- CustomWidgetManager.INSTANCE.get(context).onViewCreated(lahv);
- return lahv;
- }
-
- LauncherAppWidgetHostView widgetView = getPendingView(appWidgetId);
- if (widgetView != null) {
- removePendingView(appWidgetId);
- } else {
- widgetView = new LauncherAppWidgetHostView(context);
- }
+ protected LauncherAppWidgetHostView createViewInternal(
+ int appWidgetId, @NonNull LauncherAppWidgetProviderInfo appWidget) {
+ LauncherAppWidgetHostView widgetView = new LauncherAppWidgetHostView(mContext);
widgetView.setInteractionHandler(mInteractionHandler);
widgetView.setAppWidget(appWidgetId, appWidget);
- mViews.put(appWidgetId, widgetView);
+ widgetView.updateAppWidget(getHolderListener(appWidgetId).addHolder(mUpdateHandler));
+ return widgetView;
+ }
+ private static QuickstepWidgetHolderListener getHolderListener(int appWidgetId) {
QuickstepWidgetHolderListener listener = sListeners.get(appWidgetId);
if (listener == null) {
listener = new QuickstepWidgetHolderListener(appWidgetId);
sWidgetHost.setListener(appWidgetId, listener);
sListeners.put(appWidgetId, listener);
}
- RemoteViews remoteViews = listener.addHolder(this);
- widgetView.updateAppWidget(remoteViews);
-
- return widgetView;
+ return listener;
}
/**
@@ -267,7 +247,7 @@
public void clearViews() {
mViews.clear();
for (int i = sListeners.size() - 1; i >= 0; i--) {
- sListeners.valueAt(i).mListeningHolders.remove(this);
+ sListeners.valueAt(i).mListeningHolders.remove(mUpdateHandler);
}
}
@@ -275,7 +255,7 @@
implements AppWidgetHost.AppWidgetHostListener {
// Static listeners should use a set that is backed by WeakHashMap to avoid memory leak
- private final Set<QuickstepWidgetHolder> mListeningHolders = Collections.newSetFromMap(
+ private final Set<UpdateHandler> mListeningHolders = Collections.newSetFromMap(
new WeakHashMap<>());
private final int mWidgetId;
@@ -288,7 +268,7 @@
@UiThread
@Nullable
- public RemoteViews addHolder(@NonNull QuickstepWidgetHolder holder) {
+ public RemoteViews addHolder(@NonNull UpdateHandler holder) {
mListeningHolders.add(holder);
return mRemoteViews;
}
@@ -359,11 +339,15 @@
}
}
+ private interface UpdateKey<T> extends BiConsumer<AppWidgetHostView, T> { }
+
+ private interface UpdateHandler {
+ <T> void onWidgetUpdate(int widgetId, UpdateKey<T> key, T data);
+ }
+
private static class PendingUpdate {
public final IntSet changedViews = new IntSet();
public AppWidgetProviderInfo providerInfo;
public RemoteViews remoteViews;
}
-
- private interface UpdateKey<T> extends BiConsumer<AppWidgetHostView, T> { }
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index d94cd89..5db5d17 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -106,7 +106,7 @@
protected StateAnimationConfig getConfigForStates(
LauncherState fromState, LauncherState toState) {
final StateAnimationConfig config = new StateAnimationConfig();
- config.userControlled = true;
+ config.animProps |= StateAnimationConfig.USER_CONTROLLED;
if (fromState == NORMAL && toState == ALL_APPS) {
AllAppsSwipeController.applyNormalToAllAppsAnimConfig(mLauncher, config);
} else if (fromState == ALL_APPS && toState == NORMAL) {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 42b18bd..cbf6ad6 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1572,7 +1572,8 @@
mSwipePipToHomeAnimator.getTaskId(),
mSwipePipToHomeAnimator.getComponentName(),
mSwipePipToHomeAnimator.getDestinationBounds(),
- mSwipePipToHomeAnimator.getContentOverlay());
+ mSwipePipToHomeAnimator.getContentOverlay(),
+ mSwipePipToHomeAnimator.getAppBounds());
windowAnim = mSwipePipToHomeAnimators;
} else {
diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
index b9029ea..877bdf8 100644
--- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
+++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
@@ -23,13 +23,13 @@
import static com.android.launcher3.BaseActivity.INVISIBLE_ALL;
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_PENDING_FLAGS;
import static com.android.launcher3.BaseActivity.PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION;
-import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING;
-import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
+import android.content.ComponentCallbacks;
+import android.content.res.Configuration;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -101,44 +101,45 @@
private final RectF mCurrentRect = new RectF();
private final QuickstepLauncher mLauncher;
private final int mWindowScaleMarginX;
- /** Max window translation in the Y axis. */
- private final int mWindowMaxDeltaY;
- private final float mWindowScaleEndCornerRadius;
- private final float mWindowScaleStartCornerRadius;
+ private float mWindowScaleEndCornerRadius;
+ private float mWindowScaleStartCornerRadius;
private final Interpolator mCancelInterpolator;
private final Interpolator mProgressInterpolator = new DecelerateInterpolator();
private final PointF mInitialTouchPos = new PointF();
private RemoteAnimationTarget mBackTarget;
private View mLauncherTargetView;
- private SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+ private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
private boolean mSpringAnimationInProgress = false;
private boolean mAnimatorSetInProgress = false;
private float mBackProgress = 0;
private boolean mBackInProgress = false;
private OnBackInvokedCallbackStub mBackCallback;
private IRemoteAnimationFinishedCallback mAnimationFinishedCallback;
- private BackProgressAnimator mProgressAnimator = new BackProgressAnimator();
+ private final BackProgressAnimator mProgressAnimator = new BackProgressAnimator();
private SurfaceControl mScrimLayer;
private ValueAnimator mScrimAlphaAnimator;
private float mScrimAlpha;
private boolean mOverridingStatusBarFlags;
+ private final ComponentCallbacks mComponentCallbacks = new ComponentCallbacks() {
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ loadCornerRadius();
+ }
+
+ @Override
+ public void onLowMemory() {}
+ };
+
public LauncherBackAnimationController(
QuickstepLauncher launcher,
QuickstepTransitionManager quickstepTransitionManager) {
mLauncher = launcher;
mQuickstepTransitionManager = quickstepTransitionManager;
- mWindowScaleEndCornerRadius = QuickStepContract.supportsRoundedCornersOnWindows(
- mLauncher.getResources())
- ? mLauncher.getResources().getDimensionPixelSize(
- R.dimen.swipe_back_window_corner_radius)
- : 0;
- mWindowScaleStartCornerRadius = QuickStepContract.getWindowCornerRadius(mLauncher);
+ loadCornerRadius();
mWindowScaleMarginX = mLauncher.getResources().getDimensionPixelSize(
R.dimen.swipe_back_window_scale_x_margin);
- mWindowMaxDeltaY = mLauncher.getResources().getDimensionPixelSize(
- R.dimen.swipe_back_window_max_delta_y);
mCancelInterpolator =
AnimationUtils.loadInterpolator(mLauncher, R.interpolator.standard_interpolator);
}
@@ -301,11 +302,10 @@
mInitialTouchPos.set(backEvent.getTouchX(), backEvent.getTouchY());
mStartRect.set(appTarget.windowConfiguration.getMaxBounds());
- if (mLauncher.getDeviceProfile().isTaskbarPresent && enableTaskbarPinning()
- && LauncherPrefs.get(mLauncher).get(TASKBAR_PINNING)) {
- int insetBottom = mStartRect.bottom - appTarget.contentInsets.bottom;
- mStartRect.set(mStartRect.left, mStartRect.top, mStartRect.right, insetBottom);
- }
+
+ // inset bottom in case of pinned taskbar being present
+ mStartRect.inset(0, 0, 0, appTarget.contentInsets.bottom);
+
mLauncherTargetView = mQuickstepTransitionManager.findLauncherView(
new RemoteAnimationTarget[]{ mBackTarget });
setLauncherTargetViewVisible(false);
@@ -551,6 +551,30 @@
anim.start();
}
+ private void loadCornerRadius() {
+ mWindowScaleEndCornerRadius = QuickStepContract.supportsRoundedCornersOnWindows(
+ mLauncher.getResources())
+ ? mLauncher.getResources().getDimensionPixelSize(
+ R.dimen.swipe_back_window_corner_radius)
+ : 0;
+ mWindowScaleStartCornerRadius = QuickStepContract.getWindowCornerRadius(mLauncher);
+ }
+
+ /**
+ * Called when launcher is destroyed. Unregisters component callbacks to avoid memory leaks.
+ */
+ public void unregisterComponentCallbacks() {
+ mLauncher.unregisterComponentCallbacks(mComponentCallbacks);
+ }
+
+ /**
+ * Registers component callbacks with the launcher to receive configuration change events.
+ */
+ public void registerComponentCallbacks() {
+ mLauncher.registerComponentCallbacks(mComponentCallbacks);
+ }
+
+
private void resetScrim() {
removeScrimLayer();
mScrimAlpha = 0;
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 9d942c5..65c8662 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -1,5 +1,6 @@
package com.android.quickstep;
+import static com.android.launcher3.taskbar.TaskbarThresholdUtils.getFromNavThreshold;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.app.Activity;
@@ -10,7 +11,6 @@
import androidx.annotation.Nullable;
-import com.android.launcher3.R;
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.testing.TestInformationHandler;
import com.android.launcher3.testing.shared.TestProtocol;
@@ -18,6 +18,7 @@
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.TISBindHelper;
+import com.android.quickstep.views.RecentsView;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
@@ -77,6 +78,11 @@
return response;
}
+ case TestProtocol.REQUEST_GET_OVERVIEW_CURRENT_PAGE_INDEX: {
+ return getLauncherUIProperty(Bundle::putInt,
+ launcher -> launcher.<RecentsView>getOverviewPanel().getCurrentPage());
+ }
+
case TestProtocol.REQUEST_HAS_TIS: {
response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, true);
return response;
@@ -93,7 +99,7 @@
case TestProtocol.REQUEST_TASKBAR_FROM_NAV_THRESHOLD: {
final Resources resources = mContext.getResources();
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
- resources.getDimensionPixelSize(R.dimen.taskbar_from_nav_threshold));
+ getFromNavThreshold(resources, mDeviceProfile));
return response;
}
@@ -154,6 +160,14 @@
// Allow null-pointer to catch illegal states.
runOnTISBinder(tisBinder -> tisBinder.getTaskbarManager().recreateTaskbar());
return response;
+
+ case TestProtocol.REQUEST_UNSTASH_BUBBLE_BAR_IF_STASHED:
+ runOnTISBinder(tisBinder -> {
+ // Allow null-pointer to catch illegal states.
+ tisBinder.getTaskbarManager().getCurrentActivityContext()
+ .unstashBubbleBarIfStashed();
+ });
+ return response;
}
return super.call(method, arg, extras);
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 94ed5b9..a8c6809 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -630,10 +630,11 @@
* should be responsible for cleaning up the overlay.
*/
public void stopSwipePipToHome(int taskId, ComponentName componentName, Rect destinationBounds,
- SurfaceControl overlay) {
+ SurfaceControl overlay, Rect appBounds) {
if (mPip != null) {
try {
- mPip.stopSwipePipToHome(taskId, componentName, destinationBounds, overlay);
+ mPip.stopSwipePipToHome(taskId, componentName, destinationBounds, overlay,
+ appBounds);
} catch (RemoteException e) {
Log.w(TAG, "Failed call stopSwipePipToHome");
}
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 69db91b..4f885af 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -38,6 +38,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
+import com.android.internal.util.ArrayUtils;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.DisplayController;
@@ -185,6 +186,16 @@
cleanUpRecentsAnimation(newCallbacks);
}
+ private boolean isNonRecentsStartedTasksAppeared(
+ RemoteAnimationTarget[] appearedTaskTargets) {
+ // For example, right after swiping from task X to task Y (e.g. from
+ // AbsSwipeUpHandler#startNewTask), and then task Y starts X immediately
+ // (e.g. in Y's onResume). The case will be: lastStartedTask=Y and appearedTask=X.
+ return mLastGestureState.getEndTarget() == GestureState.GestureEndTarget.NEW_TASK
+ && ArrayUtils.find(appearedTaskTargets,
+ mLastGestureState.mLastStartedTaskIdPredicate) == null;
+ }
+
@Override
public void onTasksAppeared(RemoteAnimationTarget[] appearedTaskTargets) {
RemoteAnimationTarget appearedTaskTarget = appearedTaskTargets[0];
@@ -213,7 +224,8 @@
nonAppTargets = new RemoteAnimationTarget[0];
}
if ((activityInterface.isInLiveTileMode()
- || mLastGestureState.getEndTarget() == RECENTS)
+ || mLastGestureState.getEndTarget() == RECENTS
+ || isNonRecentsStartedTasksAppeared(appearedTaskTargets))
&& activityInterface.getCreatedActivity() != null) {
RecentsView recentsView =
activityInterface.getCreatedActivity().getOverviewPanel();
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 6f45caf..9972e59 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -372,6 +372,12 @@
taskbarManager.onNavButtonsDarkIntensityChanged(darkIntensity));
}
+ @Override
+ public void onNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
+ executeForTaskbarManager(taskbarManager ->
+ taskbarManager.onNavigationBarLumaSamplingEnabled(displayId, enable));
+ }
+
private void executeForTouchInteractionService(
@NonNull Consumer<TouchInteractionService> tisConsumer) {
TouchInteractionService tis = mTis.get();
diff --git a/quickstep/src/com/android/quickstep/util/SlideInRemoteTransition.kt b/quickstep/src/com/android/quickstep/util/SlideInRemoteTransition.kt
new file mode 100644
index 0000000..c1fa2f3
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/SlideInRemoteTransition.kt
@@ -0,0 +1,115 @@
+/*
+ * 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.util
+
+import android.animation.ValueAnimator
+import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
+import android.graphics.Rect
+import android.os.IBinder
+import android.os.RemoteException
+import android.view.SurfaceControl
+import android.view.SurfaceControl.Transaction
+import android.window.IRemoteTransition
+import android.window.IRemoteTransitionFinishedCallback
+import android.window.TransitionInfo
+import com.android.launcher3.anim.AnimatorListeners.forEndCallback
+import com.android.launcher3.util.Executors
+import com.android.wm.shell.util.TransitionUtil
+
+/** Remote animation which slides the opening targets in and the closing targets out */
+class SlideInRemoteTransition(val isRtl: Boolean) : IRemoteTransition.Stub() {
+
+ override fun mergeAnimation(
+ iBinder: IBinder,
+ transitionInfo: TransitionInfo,
+ transaction: Transaction,
+ mergeTarget: IBinder,
+ finishCB: IRemoteTransitionFinishedCallback
+ ) {
+
+ try {
+ finishCB.onTransitionFinished(null, Transaction())
+ } catch (e: RemoteException) {
+ // Ignore
+ }
+ }
+
+ override fun startAnimation(
+ transition: IBinder,
+ info: TransitionInfo,
+ startT: Transaction,
+ finishCB: IRemoteTransitionFinishedCallback
+ ) {
+ val anim = ValueAnimator.ofFloat(0f, 1f)
+
+ val closingStartBounds: HashMap<SurfaceControl, Rect> = HashMap()
+ val openingEndBounds: HashMap<SurfaceControl, Rect> = HashMap()
+ for (chg in info.changes) {
+ val leash = chg.leash
+ startT.show(leash)
+
+ val taskInfo = chg.taskInfo
+ if (taskInfo?.activityType == ACTIVITY_TYPE_HOME || taskInfo?.parentTaskId != -1) {
+ continue
+ }
+ if (TransitionUtil.isClosingType(chg.mode)) {
+ closingStartBounds[leash] = chg.startAbsBounds
+ }
+ if (TransitionUtil.isOpeningType(chg.mode)) {
+ openingEndBounds[leash] = chg.endAbsBounds
+ }
+ }
+ startT.apply()
+
+ anim.addUpdateListener {
+ val t = Transaction()
+ closingStartBounds.keys.forEach {
+ // Translate the surface from its original position on-screen to off-screen on the
+ // right (or left in RTL)
+ val startBounds = closingStartBounds[it]
+ val targetX = (if (isRtl) -1 else 1) * startBounds!!.right
+ t.setPosition(it, anim.animatedValue as Float * targetX, 0f)
+ }
+ openingEndBounds.keys.forEach {
+ // Set the alpha in the update listener to prevent one visible frame at the
+ // beginning
+ t.setAlpha(it, 1f)
+ // Translate the surface from off-screen on the left (or left in RTL) to its final
+ // position on-screen
+ val endBounds = openingEndBounds[it]
+ val targetX = (if (isRtl) -1 else 1) * endBounds!!.right
+ t.setPosition(it, (1f - anim.animatedValue as Float) * -targetX, 0f)
+ }
+ t.apply()
+ }
+ anim.addListener(
+ forEndCallback(
+ Runnable {
+ val t = Transaction()
+ try {
+ finishCB.onTransitionFinished(null, t)
+ } catch (e: RemoteException) {
+ // Ignore
+ }
+ }
+ )
+ )
+
+ Executors.MAIN_EXECUTOR.execute { anim.start() }
+ }
+
+ override fun onTransitionConsumed(transition: IBinder?, aborted: Boolean) {}
+}
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 193cc2b..3c90e0c 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -498,6 +498,29 @@
}
/**
+ * Used to launch split screen from a split pair that already exists, optionally with a custom
+ * remote transition.
+ * <p>
+ * See {@link SplitSelectStateController#launchExistingSplitPair(
+ * GroupedTaskView, int, int, int, Consumer, boolean, int, RemoteTransition)}
+ */
+ public void launchExistingSplitPair(@Nullable GroupedTaskView groupedTaskView,
+ int firstTaskId, int secondTaskId, @StagePosition int stagePosition,
+ Consumer<Boolean> callback, boolean freezeTaskList,
+ @PersistentSnapPosition int snapPosition) {
+ launchExistingSplitPair(
+ groupedTaskView,
+ firstTaskId,
+ secondTaskId,
+ stagePosition,
+ callback,
+ freezeTaskList,
+ snapPosition,
+ /* remoteTransition= */ null);
+ }
+
+
+ /**
* Used to launch split screen from a split pair that already exists (usually accessible through
* Overview). This is different than {@link #launchTasks(Consumer, boolean, int, InstanceId)}
* in that this only launches split screen that are existing tasks. This doesn't determine which
@@ -509,7 +532,7 @@
public void launchExistingSplitPair(@Nullable GroupedTaskView groupedTaskView,
int firstTaskId, int secondTaskId, @StagePosition int stagePosition,
Consumer<Boolean> callback, boolean freezeTaskList,
- @PersistentSnapPosition int snapPosition) {
+ @PersistentSnapPosition int snapPosition, @Nullable RemoteTransition remoteTransition) {
mLaunchingTaskView = groupedTaskView;
final ActivityOptions options1 = ActivityOptions.makeBasic();
if (freezeTaskList) {
@@ -518,10 +541,12 @@
Bundle optionsBundle = options1.toBundle();
if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
- final RemoteTransition remoteTransition = getShellRemoteTransition(firstTaskId,
- secondTaskId, callback, "LaunchExistingPair");
+ final RemoteTransition transition = remoteTransition == null
+ ? getShellRemoteTransition(
+ firstTaskId, secondTaskId, callback, "LaunchExistingPair")
+ : remoteTransition;
mSystemUiProxy.startTasks(firstTaskId, optionsBundle, secondTaskId, null /* options2 */,
- stagePosition, snapPosition, remoteTransition, null /*shellInstanceId*/);
+ stagePosition, snapPosition, transition, null /*shellInstanceId*/);
} else {
final RemoteAnimationAdapter adapter = getLegacyRemoteAdapter(firstTaskId,
secondTaskId, callback);
diff --git a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
index cb32c6c..b663970 100644
--- a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
@@ -53,6 +53,7 @@
private final QuickstepLauncher mLauncher;
private final SplitSelectStateController mController;
+ private final RecentsAnimationDeviceState mDeviceState;
private final OverviewComponentObserver mOverviewComponentObserver;
private final int mSplitPlaceholderSize;
@@ -62,10 +63,9 @@
SplitSelectStateController controller) {
mLauncher = launcher;
mController = controller;
- RecentsAnimationDeviceState deviceState = new RecentsAnimationDeviceState(
- launcher.getApplicationContext());
+ mDeviceState = new RecentsAnimationDeviceState(launcher.getApplicationContext());
mOverviewComponentObserver = new OverviewComponentObserver(launcher.getApplicationContext(),
- deviceState);
+ mDeviceState);
mSplitPlaceholderSize = mLauncher.getResources().getDimensionPixelSize(
R.dimen.split_placeholder_size);
@@ -97,6 +97,7 @@
public void onDestroy() {
mOverviewComponentObserver.onDestroy();
+ mDeviceState.destroy();
}
private class SplitWithKeyboardShortcutRecentsAnimationListener implements
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index a36b32c..6c89be1 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -264,6 +264,10 @@
return mDestinationBounds;
}
+ public Rect getAppBounds() {
+ return mAppBounds;
+ }
+
@Nullable
public SurfaceControl getContentOverlay() {
return mPipContentOverlay == null ? null : mPipContentOverlay.getLeash();
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index baaa062..065a9c5 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -74,6 +74,7 @@
private final boolean mIsRecentsRtl;
private final Rect mTaskRect = new Rect();
+ private final Rect mFullTaskSize = new Rect();
private final PointF mPivot = new PointF();
private DeviceProfile mDp;
@StagePosition
@@ -131,6 +132,47 @@
mDp = dp;
mLayoutValid = false;
mOrientationState.setDeviceProfile(dp);
+ calculateTaskSize();
+ }
+
+ private void calculateTaskSize() {
+ if (mDp == null) {
+ return;
+ }
+
+ if (mIsGridTask) {
+ mSizeStrategy.calculateGridTaskSize(mContext, mDp, mFullTaskSize,
+ mOrientationState.getOrientationHandler());
+ } else {
+ mSizeStrategy.calculateTaskSize(mContext, mDp, mFullTaskSize,
+ mOrientationState.getOrientationHandler());
+ }
+
+ if (mSplitBounds != null) {
+ // The task rect changes according to the staged split task sizes, but recents
+ // fullscreen scale and pivot remains the same since the task fits into the existing
+ // sized task space bounds
+ mTaskRect.set(mFullTaskSize);
+ mOrientationState.getOrientationHandler()
+ .setSplitTaskSwipeRect(mDp, mTaskRect, mSplitBounds, mStagePosition);
+ mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
+ } else if (mIsDesktopTask) {
+ // For desktop, tasks can take up only part of the screen size.
+ // Full task size represents the whole screen size, but scaled down to fit in recents.
+ // Task rect will represent the scaled down thumbnail position and is placed inside
+ // full task size as it is on the home screen.
+ PointF fullscreenTaskDimension = new PointF();
+ BaseActivityInterface.getTaskDimension(mContext, mDp, fullscreenTaskDimension);
+ // Calculate the scale down factor used in recents
+ float scale = mFullTaskSize.width() / fullscreenTaskDimension.x;
+ mTaskRect.set(mThumbnailPosition);
+ mTaskRect.scale(scale);
+ // Ensure the task rect is inside the full task rect
+ mTaskRect.offset(mFullTaskSize.left, mFullTaskSize.top);
+ } else {
+ mTaskRect.set(mFullTaskSize);
+ mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
+ }
}
/**
@@ -148,44 +190,11 @@
if (mDp == null) {
return 1;
}
-
- if (mIsGridTask) {
- mSizeStrategy.calculateGridTaskSize(mContext, mDp, mTaskRect,
- mOrientationState.getOrientationHandler());
- } else {
- mSizeStrategy.calculateTaskSize(mContext, mDp, mTaskRect,
- mOrientationState.getOrientationHandler());
- }
-
- Rect fullTaskSize;
- if (mSplitBounds != null) {
- // The task rect changes according to the staged split task sizes, but recents
- // fullscreen scale and pivot remains the same since the task fits into the existing
- // sized task space bounds
- fullTaskSize = new Rect(mTaskRect);
- mOrientationState.getOrientationHandler()
- .setSplitTaskSwipeRect(mDp, mTaskRect, mSplitBounds, mStagePosition);
- mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
- } else if (mIsDesktopTask) {
- // For desktop, tasks can take up only part of the screen size.
- // Full task size represents the whole screen size, but scaled down to fit in recents.
- // Task rect will represent the scaled down thumbnail position and is placed inside
- // full task size as it is on the home screen.
- fullTaskSize = new Rect(mTaskRect);
- PointF fullscreenTaskDimension = new PointF();
- BaseActivityInterface.getTaskDimension(mContext, mDp, fullscreenTaskDimension);
- // Calculate the scale down factor used in recents
- float scale = fullTaskSize.width() / fullscreenTaskDimension.x;
- mTaskRect.set(mThumbnailPosition);
- mTaskRect.scale(scale);
- // Ensure the task rect is inside the full task rect
- mTaskRect.offset(fullTaskSize.left, fullTaskSize.top);
- } else {
- fullTaskSize = new Rect(mTaskRect);
- mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
- }
- fullTaskSize.offset(mTaskRectTranslationX + mPivotOffsetX, mTaskRectTranslationY);
- return mOrientationState.getFullScreenScaleAndPivot(fullTaskSize, mDp, mPivot);
+ // Copy mFullTaskSize instead of updating it directly so it could be reused next time
+ // without recalculating
+ Rect scaleRect = new Rect(mFullTaskSize);
+ scaleRect.offset(mTaskRectTranslationX + mPivotOffsetX, mTaskRectTranslationY);
+ return mOrientationState.getFullScreenScaleAndPivot(scaleRect, mDp, mPivot);
}
/**
@@ -209,13 +218,13 @@
mSplitBounds = splitInfo;
if (mSplitBounds == null) {
mStagePosition = STAGE_POSITION_UNDEFINED;
- return;
+ } else {
+ mStagePosition = mThumbnailPosition.equals(splitInfo.leftTopBounds)
+ ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT;
+ mPositionHelper.setSplitBounds(convertLauncherSplitBoundsToShell(mSplitBounds),
+ mStagePosition);
}
- mStagePosition = mThumbnailPosition.equals(splitInfo.leftTopBounds) ?
- STAGE_POSITION_TOP_OR_LEFT :
- STAGE_POSITION_BOTTOM_OR_RIGHT;
- mPositionHelper.setSplitBounds(convertLauncherSplitBoundsToShell(mSplitBounds),
- mStagePosition);
+ calculateTaskSize();
}
/**
@@ -261,6 +270,8 @@
public void setTaskRectTranslation(int taskRectTranslationX, int taskRectTranslationY) {
mTaskRectTranslationX = taskRectTranslationX;
mTaskRectTranslationY = taskRectTranslationY;
+ // Re-calculate task size after changing translation
+ calculateTaskSize();
}
/**
@@ -269,7 +280,7 @@
public void addAppToOverviewAnim(PendingAnimation pa, TimeInterpolator interpolator) {
pa.addFloat(fullScreenProgress, AnimatedFloat.VALUE, 1, 0, interpolator);
if (enableGridOnlyOverview() && mDp.isTablet) {
- int translationXToMiddle = mDp.widthPx / 2 - mTaskRect.centerX();
+ int translationXToMiddle = mDp.widthPx / 2 - mFullTaskSize.centerX();
taskPrimaryTranslation.value = translationXToMiddle;
mPivotOffsetX = translationXToMiddle;
}
@@ -324,8 +335,8 @@
public void applyWindowToHomeRotation(Matrix matrix) {
matrix.postTranslate(mDp.windowX, mDp.windowY);
postDisplayRotation(deltaRotation(
- mOrientationState.getRecentsActivityRotation(),
- mOrientationState.getDisplayRotation()),
+ mOrientationState.getRecentsActivityRotation(),
+ mOrientationState.getDisplayRotation()),
mDp.widthPx, mDp.heightPx, matrix);
}
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index a10d2ed..6b00473 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -17,6 +17,7 @@
package com.android.quickstep.views;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
import android.content.Context;
@@ -53,6 +54,8 @@
import com.android.systemui.shared.system.QuickStepContract;
import com.android.wm.shell.Flags;
+import kotlin.Unit;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -60,7 +63,6 @@
import java.util.List;
import java.util.function.Consumer;
-import kotlin.Unit;
/**
* TaskView that contains all tasks that are part of the desktop.
@@ -91,6 +93,8 @@
private View mBackgroundView;
+ private int mChildCountAtInflation;
+
/** Check whether desktop windowing is enabled */
public static boolean isDesktopModeSupported() {
// Check for aconfig flag first
@@ -151,6 +155,8 @@
Drawable iconBackground = getResources().getDrawable(R.drawable.bg_circle,
getContext().getTheme());
mIconView.setDrawable(new LayerDrawable(new Drawable[]{iconBackground, icon}));
+
+ mChildCountAtInflation = getChildCount();
}
@Override
@@ -196,7 +202,9 @@
for (int i = 0; i < diff; i++) {
TaskThumbnailView snapshotView = new TaskThumbnailView(getContext());
mSnapshotViews.add(snapshotView);
- addView(snapshotView, new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
+ // Add snapshots from to position after the initial child views.
+ addView(snapshotView, mChildCountAtInflation,
+ new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
}
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index cf89d2e..77033b2 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -115,9 +115,6 @@
animateClose();
} else {
closeComplete();
- if (enableOverviewIconMenu()) {
- ((IconAppChipView) mTaskContainer.getIconView()).reset();
- }
}
}
@@ -378,9 +375,18 @@
private void closeComplete() {
mIsOpen = false;
+ resetOverviewIconMenu();
mActivity.getDragLayer().removeView(this);
}
+ private void resetOverviewIconMenu() {
+ if (enableOverviewIconMenu()) {
+ ((IconAppChipView) mTaskContainer.getIconView()).reset();
+ setTranslationY(mMenuTranslationYBeforeOpen);
+ mTaskContainer.getIconView().asView().setTranslationY(mIconViewTranslationYBeforeOpen);
+ }
+ }
+
private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
float radius = TaskCornerRadius.get(mContext);
Rect fromRect = new Rect(
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 0a325ac..39d6f03 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -77,6 +77,7 @@
import org.junit.runners.model.Statement;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -193,6 +194,7 @@
@Test
public void goToOverviewFromApp() {
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
+ waitForRecentsActivityStop();
mLauncher.getLaunchedAppState().switchToOverview();
}
@@ -229,6 +231,19 @@
}
private void waitForRecentsActivityStop() {
+ try {
+ final boolean recentsActivityIsNull = MAIN_EXECUTOR.submit(
+ () -> RecentsActivity.ACTIVITY_TRACKER.getCreatedActivity() == null).get();
+ if (recentsActivityIsNull) {
+ // Null activity counts as a "stopped" one.
+ return;
+ }
+ } catch (ExecutionException e) {
+ throw new RuntimeException(e);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+
Wait.atMost("Recents activity didn't stop",
() -> getFromRecents(recents -> !recents.isStarted()),
DEFAULT_UI_TIMEOUT, mLauncher);
@@ -241,6 +256,7 @@
startAppFast(getAppPackageName());
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
startTestActivity(2);
+ waitForRecentsActivityStop();
Wait.atMost("Expected three apps in the task list",
() -> mLauncher.getRecentTasks().size() >= 3, DEFAULT_ACTIVITY_TIMEOUT, mLauncher);
@@ -282,7 +298,6 @@
// Test dismissing all tasks.
pressHomeAndGoToOverview().dismissAllTasks();
- waitForRecentsActivityStop(); // dismissAllTasks() will close Recents
assertTrue("Fallback Launcher not visible", TestHelpers.wait(Until.hasObject(By.pkg(
mOtherLauncherActivity.packageName).text(FALLBACK_LAUNCHER_TITLE)), WAIT_TIME_MS));
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index ebe3365..1b8866a 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -28,7 +28,6 @@
import android.content.Intent;
import android.content.res.Configuration;
-import android.platform.test.annotations.PlatinumTest;
import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -113,7 +112,6 @@
@Test
@PortraitLandscape
- @PlatinumTest(focusArea = "launcher")
public void testOverview() throws Exception {
startTestAppsWithCheck();
// mLauncher.pressHome() also tests an important case of pressing home while in background.
@@ -412,7 +410,6 @@
@Test
@PortraitLandscape
@TaskbarModeSwitch()
- @PlatinumTest(focusArea = "launcher")
@TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/309820115
@ScreenRecord // b/309820115
public void testOverviewForTablet() throws Exception {
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java
index 7109bbf..38d6046 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java
@@ -25,6 +25,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
+import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
import org.junit.Test;
@@ -69,6 +70,7 @@
@Test
@TaskbarModeSwitch(mode = TRANSIENT)
@PortraitLandscape
+ @ScreenRecord // b/317798731
public void testSwipeToStashAndUnstash() {
getTaskbar().swipeDownToStash();
mLauncher.getLaunchedAppState().swipeUpToUnstashTaskbar();
diff --git a/res/drawable/private_space_install_app_icon.xml b/res/drawable/private_space_install_app_icon.xml
new file mode 100644
index 0000000..4c167ba
--- /dev/null
+++ b/res/drawable/private_space_install_app_icon.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="60dp"
+ android:height="60dp"
+ android:viewportWidth="60"
+ android:viewportHeight="60">
+ <group>
+ <clip-path
+ android:pathData="M30 0H30A30 30 0 0 1 60 30V30A30 30 0 0 1 30 60H30A30 30 0 0 1 0 30V30A30 30 0 0 1 30 0Z" />
+ <path
+ android:pathData="M30 0H30A30 30 0 0 1 60 30V30A30 30 0 0 1 30 60H30A30 30 0 0 1 0 30V30A30 30 0 0 1 30 0Z"
+ android:fillColor="@color/material_color_surface_bright" />
+ <path
+ android:pathData="M29 31h-6v-2h6v-6h2v6h6v2h-6v6h-2v-6Z"
+ android:fillColor="@color/material_color_on_surface_variant" />
+ </group>
+</vector>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 8d84c90..e54539f 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -189,6 +189,10 @@
defaults to 2 * numAllAppsColumns -->
<attr name="numExtendedAllAppsColumns" format="integer" />
+ <!-- Number of rows to calculate the cell height for all apps when it's necessary.
+ Defaults to numRows. Requires FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE to be enabled. -->
+ <attr name="numAllAppsRowsForCellHeightCalculation" format="integer" />
+
<!-- numHotseatIcons defaults to numColumns, if not specified -->
<attr name="numHotseatIcons" format="integer" />
<!-- Number of icons to use when extending the hotseat size,
@@ -219,26 +223,32 @@
<!-- File that contains the specs for the workspace.
Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled -->
<attr name="workspaceSpecsId" format="reference" />
+ <!-- defaults to workspaceSpecsId, if not specified -->
<attr name="workspaceSpecsTwoPanelId" format="reference" />
<!-- File that contains the specs for all apps.
Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled -->
<attr name="allAppsSpecsId" format="reference" />
+ <!-- defaults to allAppsSpecsId, if not specified -->
<attr name="allAppsSpecsTwoPanelId" format="reference" />
<!-- File that contains the specs for the workspace.
Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled -->
<attr name="folderSpecsId" format="reference" />
+ <!-- defaults to folderSpecsId, if not specified -->
<attr name="folderSpecsTwoPanelId" format="reference" />
<!-- File that contains the specs for hotseat bar.
Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled -->
<attr name="hotseatSpecsId" format="reference" />
+ <!-- defaults to hotseatSpecsId, if not specified -->
<attr name="hotseatSpecsTwoPanelId" format="reference" />
<!-- File that contains the specs for workspace icon and text size.
Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled -->
<attr name="workspaceCellSpecsId" format="reference" />
+ <!-- defaults to workspaceCellSpecsId, if not specified -->
<attr name="workspaceCellSpecsTwoPanelId" format="reference" />
<!-- File that contains the specs for all apps icon and text size.
Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled -->
<attr name="allAppsCellSpecsId" format="reference" />
+ <!-- defaults to allAppsCellSpecsId, if not specified -->
<attr name="allAppsCellSpecsTwoPanelId" format="reference" />
<!-- By default all categories are enabled -->
diff --git a/res/values/config.xml b/res/values/config.xml
index 2980635..33eb4c7 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -201,7 +201,6 @@
<!-- Swipe back to home related -->
<dimen name="swipe_back_window_scale_x_margin">10dp</dimen>
- <dimen name="swipe_back_window_max_delta_y">160dp</dimen>
<dimen name="swipe_back_window_corner_radius">40dp</dimen>
<!-- The duration of the bottom sheet opening and closing animation -->
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 6d115b2..603e697 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -103,6 +103,7 @@
<dimen name="all_apps_search_bar_content_overlap">24dp</dimen>
<dimen name="all_apps_search_bar_bottom_padding">30dp</dimen>
<dimen name="all_apps_empty_search_message_top_offset">40dp</dimen>
+ <dimen name="all_apps_search_top_row_extra_height">4dp</dimen>
<dimen name="all_apps_header_pill_height">48dp</dimen>
<dimen name="all_apps_header_pill_corner_radius">12dp</dimen>
<dimen name="all_apps_header_tab_height">48dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b043662..34677f6 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -463,6 +463,10 @@
<string name="ps_container_lock_unlock_button">Lock/Unlock Private Space</string>
<!-- Description for Private Space Transition button -->
<string name="ps_container_transition">Private Space Transitioning</string>
+ <!-- Title for Private Space install app icon -->
+ <string name="ps_add_button_label">Install apps</string>
+ <!-- Content description for install app icon -->
+ <string name="ps_add_button_content_description">Install apps to Private Space</string>
<!-- Strings for bubble bar -->
<!-- content description for the overflow bubble [CHAR_LIMIT=none] -->
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index f8ed4df..b6f6615 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -39,7 +39,6 @@
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.OnColorHintListener;
import com.android.launcher3.util.Themes;
-import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.util.WallpaperColorHints;
import com.android.launcher3.util.WindowBounds;
@@ -55,16 +54,12 @@
public static final Object AUTO_CANCEL_ACTION_MODE = new Object();
private ActionMode mCurrentActionMode;
- protected boolean mIsSafeModeEnabled;
private int mThemeRes = R.style.AppTheme;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
- mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
- () -> getPackageManager().isSafeMode());
DisplayController.INSTANCE.get(this).addChangeListener(this);
// Update theme
@@ -183,6 +178,6 @@
@Override
public boolean isAppBlockedForSafeMode() {
- return mIsSafeModeEnabled;
+ return LauncherAppState.getInstance(this).isSafeModeEnabled();
}
}
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index a57eaa3..5b497f2 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -22,6 +22,7 @@
import static com.android.launcher3.config.FeatureFlags.ENABLE_ICON_LABEL_AUTO_SCALING;
import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
import static com.android.launcher3.icons.BitmapInfo.FLAG_NO_BADGE;
+import static com.android.launcher3.icons.BitmapInfo.FLAG_SKIP_USER_BADGE;
import static com.android.launcher3.icons.BitmapInfo.FLAG_THEMED;
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_INCREMENTAL_DOWNLOAD_ACTIVE;
@@ -164,6 +165,8 @@
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mHideBadge = false;
@ViewDebug.ExportedProperty(category = "launcher")
+ private boolean mSkipUserBadge = false;
+ @ViewDebug.ExportedProperty(category = "launcher")
private boolean mIsIconVisible = true;
@ViewDebug.ExportedProperty(category = "launcher")
private int mTextColor;
@@ -268,6 +271,10 @@
mHideBadge = hideBadge;
}
+ public void setSkipUserBadge(boolean skipUserBadge) {
+ mSkipUserBadge = skipUserBadge;
+ }
+
/**
* Resets the view so it can be recycled.
*/
@@ -397,6 +404,9 @@
if (mHideBadge || mDisplay == DISPLAY_SEARCH_RESULT_SMALL) {
flags |= FLAG_NO_BADGE;
}
+ if (mSkipUserBadge) {
+ flags |= FLAG_SKIP_USER_BADGE;
+ }
FastBitmapDrawable iconDrawable = info.newIcon(getContext(), flags);
mDotParams.appColor = iconDrawable.getIconColor();
mDotParams.dotColor = Themes.getAttrColor(getContext(), R.attr.notificationDotColor);
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 72d2213..834ba04 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -640,8 +640,8 @@
DimensionType.WIDTH, numShownAllAppsColumns, availableWidthPx,
mResponsiveWorkspaceWidthSpec);
mResponsiveAllAppsHeightSpec = allAppsSpecs.getCalculatedSpec(responsiveAspectRatio,
- DimensionType.HEIGHT, inv.numRows, heightPx - mInsets.top,
- mResponsiveWorkspaceHeightSpec);
+ DimensionType.HEIGHT, inv.numAllAppsRowsForCellHeightCalculation,
+ heightPx - mInsets.top, mResponsiveWorkspaceHeightSpec);
ResponsiveSpecsProvider folderSpecs = ResponsiveSpecsProvider.create(
new ResourceHelper(context,
@@ -988,16 +988,6 @@
float workspaceCellPaddingY = getCellSize().y - iconSizePx - iconDrawablePaddingPx
- iconTextHeight;
- if (mIsResponsiveGrid) {
- iconTextSizePx = 0;
- iconDrawablePaddingPx = 0;
- int iconSizeWithOverlap = getIconSizeWithOverlap(iconSizePx);
- cellYPaddingPx = Math.max(0, getCellSize().y - iconSizeWithOverlap) / 2;
- autoResizeAllAppsCells();
-
- return;
- }
-
// We want enough space so that the text is closer to its corresponding icon.
if (workspaceCellPaddingY < iconTextHeight) {
iconTextSizePx = 0;
@@ -1115,25 +1105,28 @@
iconSizePx = mIconSizeSteps.getIconSmallerThan(cellWidthPx);
}
- iconDrawablePaddingPx = getNormalizedIconDrawablePadding();
+ if (isVerticalLayout) {
+ iconDrawablePaddingPx = 0;
+ iconTextSizePx = 0;
+ } else {
+ iconDrawablePaddingPx = getNormalizedIconDrawablePadding();
+ }
CellContentDimensions cellContentDimensions = new CellContentDimensions(iconSizePx,
iconDrawablePaddingPx,
iconTextSizePx);
- if (isVerticalLayout) {
- if (cellHeightPx < iconSizePx) {
- cellContentDimensions.setIconSizePx(
- mIconSizeSteps.getIconSmallerThan(cellHeightPx));
- }
- } else {
- cellContentDimensions.resizeToFitCellHeight(cellHeightPx, mIconSizeSteps);
- }
+ int cellContentHeight = cellContentDimensions.resizeToFitCellHeight(cellHeightPx,
+ mIconSizeSteps);
iconSizePx = cellContentDimensions.getIconSizePx();
iconDrawablePaddingPx = cellContentDimensions.getIconDrawablePaddingPx();
iconTextSizePx = cellContentDimensions.getIconTextSizePx();
- int cellContentHeight = cellContentDimensions.getCellContentHeight();
- cellYPaddingPx = Math.max(0, cellHeightPx - cellContentHeight) / 2;
+ if (isVerticalLayout) {
+ cellYPaddingPx = Math.max(0, getCellSize().y - getIconSizeWithOverlap(iconSizePx))
+ / 2;
+ } else {
+ cellYPaddingPx = Math.max(0, cellHeightPx - cellContentHeight) / 2;
+ }
} else if (mIsScalableGrid) {
iconDrawablePaddingPx = (int) (getNormalizedIconDrawablePadding() * iconScale);
cellWidthPx = pxFromDp(inv.minCellSize[mTypeIndex].x, mMetrics, scale);
@@ -1217,7 +1210,7 @@
updateAllAppsIconSize(scale, res);
}
updateAllAppsContainerWidth();
- if (isVerticalBarLayout()) {
+ if (isVerticalLayout && !mIsResponsiveGrid) {
hideWorkspaceLabelsIfNotEnoughSpace();
}
if (FeatureFlags.enableTwolineAllapps()) {
@@ -1341,7 +1334,7 @@
if (allAppsCellHeightPx < cellContentDimensions.getCellContentHeight()) {
if (isVerticalBarLayout()) {
- if (allAppsCellHeightPx < iconSizePx) {
+ if (allAppsCellHeightPx < allAppsIconSizePx) {
cellContentDimensions.setIconSizePx(
mIconSizeSteps.getIconSmallerThan(allAppsCellHeightPx));
}
@@ -1355,6 +1348,10 @@
}
allAppsCellHeightPx += mResponsiveAllAppsHeightSpec.getGutterPx();
+
+ if (isVerticalBarLayout()) {
+ autoResizeAllAppsCells();
+ }
}
/**
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 1cbc5b6..42d4d50 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -170,6 +170,7 @@
* Number of columns in the all apps list.
*/
public int numAllAppsColumns;
+ public int numAllAppsRowsForCellHeightCalculation;
public int numDatabaseAllAppsColumns;
public @StyleRes int allAppsStyle;
@@ -393,6 +394,8 @@
workspaceCellSpecsTwoPanelId = closestProfile.mWorkspaceCellSpecsTwoPanelId;
allAppsCellSpecsId = closestProfile.mAllAppsCellSpecsId;
allAppsCellSpecsTwoPanelId = closestProfile.mAllAppsCellSpecsTwoPanelId;
+ numAllAppsRowsForCellHeightCalculation =
+ closestProfile.mNumAllAppsRowsForCellHeightCalculation;
this.deviceType = deviceType;
inlineNavButtonsEndSpacing = closestProfile.inlineNavButtonsEndSpacing;
@@ -423,6 +426,7 @@
allAppsStyle = closestProfile.allAppsStyle;
numAllAppsColumns = closestProfile.numAllAppsColumns;
+
numDatabaseAllAppsColumns = deviceType == TYPE_MULTI_DISPLAY
? closestProfile.numDatabaseAllAppsColumns : closestProfile.numAllAppsColumns;
@@ -821,6 +825,7 @@
private final @StyleRes int allAppsStyle;
private final int numAllAppsColumns;
+ private final int mNumAllAppsRowsForCellHeightCalculation;
private final int numDatabaseAllAppsColumns;
private final int numHotseatIcons;
private final int numDatabaseHotseatIcons;
@@ -943,34 +948,37 @@
R.styleable.GridDisplayOption_workspaceSpecsId, INVALID_RESOURCE_HANDLE);
mWorkspaceSpecsTwoPanelId = a.getResourceId(
R.styleable.GridDisplayOption_workspaceSpecsTwoPanelId,
- INVALID_RESOURCE_HANDLE);
+ mWorkspaceSpecsId);
mAllAppsSpecsId = a.getResourceId(
R.styleable.GridDisplayOption_allAppsSpecsId, INVALID_RESOURCE_HANDLE);
mAllAppsSpecsTwoPanelId = a.getResourceId(
R.styleable.GridDisplayOption_allAppsSpecsTwoPanelId,
- INVALID_RESOURCE_HANDLE);
+ mAllAppsSpecsId);
mFolderSpecsId = a.getResourceId(
R.styleable.GridDisplayOption_folderSpecsId, INVALID_RESOURCE_HANDLE);
mFolderSpecsTwoPanelId = a.getResourceId(
R.styleable.GridDisplayOption_folderSpecsTwoPanelId,
- INVALID_RESOURCE_HANDLE);
+ mFolderSpecsId);
mHotseatSpecsId = a.getResourceId(
R.styleable.GridDisplayOption_hotseatSpecsId, INVALID_RESOURCE_HANDLE);
mHotseatSpecsTwoPanelId = a.getResourceId(
R.styleable.GridDisplayOption_hotseatSpecsTwoPanelId,
- INVALID_RESOURCE_HANDLE);
+ mHotseatSpecsId);
mWorkspaceCellSpecsId = a.getResourceId(
R.styleable.GridDisplayOption_workspaceCellSpecsId,
INVALID_RESOURCE_HANDLE);
mWorkspaceCellSpecsTwoPanelId = a.getResourceId(
R.styleable.GridDisplayOption_workspaceCellSpecsTwoPanelId,
- INVALID_RESOURCE_HANDLE);
+ mWorkspaceCellSpecsId);
mAllAppsCellSpecsId = a.getResourceId(
R.styleable.GridDisplayOption_allAppsCellSpecsId,
INVALID_RESOURCE_HANDLE);
mAllAppsCellSpecsTwoPanelId = a.getResourceId(
R.styleable.GridDisplayOption_allAppsCellSpecsTwoPanelId,
- INVALID_RESOURCE_HANDLE);
+ mAllAppsCellSpecsId);
+ mNumAllAppsRowsForCellHeightCalculation = a.getInt(
+ R.styleable.GridDisplayOption_numAllAppsRowsForCellHeightCalculation,
+ numRows);
} else {
mWorkspaceSpecsId = INVALID_RESOURCE_HANDLE;
mWorkspaceSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;
@@ -984,6 +992,7 @@
mWorkspaceCellSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;
mAllAppsCellSpecsId = INVALID_RESOURCE_HANDLE;
mAllAppsCellSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;
+ mNumAllAppsRowsForCellHeightCalculation = numRows;
}
int inlineForRotation = a.getInt(R.styleable.GridDisplayOption_inlineQsb,
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index e0e35a4..152ad5f 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -89,7 +89,6 @@
import static com.android.launcher3.logging.StatsLogManager.StatsLatencyLogger.LatencyType.WARM;
import static com.android.launcher3.model.ItemInstallQueue.FLAG_ACTIVITY_PAUSED;
import static com.android.launcher3.model.ItemInstallQueue.FLAG_DRAG_AND_DROP;
-import static com.android.launcher3.model.data.LauncherAppWidgetInfo.CUSTOM_WIDGET_ID;
import static com.android.launcher3.popup.SystemShortcut.APP_INFO;
import static com.android.launcher3.popup.SystemShortcut.INSTALL;
import static com.android.launcher3.popup.SystemShortcut.WIDGETS;
@@ -196,7 +195,6 @@
import com.android.launcher3.model.ItemInstallQueue;
import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.model.StringCache;
-import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
@@ -208,7 +206,6 @@
import com.android.launcher3.popup.ArrowPopup;
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.popup.SystemShortcut;
-import com.android.launcher3.qsb.QsbContainerView;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.statemanager.StatefulActivity;
@@ -252,6 +249,8 @@
import com.android.launcher3.widget.PendingAddWidgetInfo;
import com.android.launcher3.widget.PendingAppWidgetHostView;
import com.android.launcher3.widget.WidgetAddFlowHandler;
+import com.android.launcher3.widget.WidgetInflater;
+import com.android.launcher3.widget.WidgetInflater.InflationResult;
import com.android.launcher3.widget.WidgetManagerHelper;
import com.android.launcher3.widget.custom.CustomWidgetManager;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
@@ -333,6 +332,7 @@
private WidgetManagerHelper mAppWidgetManager;
private LauncherWidgetHolder mAppWidgetHolder;
+ private WidgetInflater mWidgetInflater;
private final int[] mTmpAddItemCellCoordinates = new int[2];
@@ -517,6 +517,7 @@
setupViews();
mAppWidgetManager = new WidgetManagerHelper(this);
+ mWidgetInflater = new WidgetInflater(this);
mAppWidgetHolder = createAppWidgetHolder();
mAppWidgetHolder.startListening();
mAppWidgetHolder.addProviderChangeListener(() -> refreshAndBindWidgetsForPackageUser(null));
@@ -1011,7 +1012,7 @@
AppWidgetHostView boundWidget = null;
if (resultCode == RESULT_OK) {
animationType = Workspace.COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION;
- final AppWidgetHostView layout = mAppWidgetHolder.createView(this, appWidgetId,
+ final AppWidgetHostView layout = mAppWidgetHolder.createView(appWidgetId,
requestArgs.getWidgetHandler().getProviderInfo(this));
boundWidget = layout;
onCompleteRunnable = () -> {
@@ -1464,7 +1465,7 @@
if (hostView == null) {
// Perform actual inflation because we're live
- hostView = mAppWidgetHolder.createView(this, appWidgetId, appWidgetInfo);
+ hostView = mAppWidgetHolder.createView(appWidgetId, appWidgetInfo);
}
LauncherAppWidgetInfo launcherInfo;
@@ -2309,162 +2310,30 @@
private View inflateAppWidget(LauncherAppWidgetInfo item,
@Nullable LauncherRestoreEventLogger restoreEventLogger) {
- if (item.hasOptionFlag(LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET)) {
- item.providerName = QsbContainerView.getSearchComponentName(this);
- if (item.providerName == null) {
- getModelWriter().deleteItemFromDatabase(item,
- "search widget removed because search component cannot be found");
- return null;
- }
- }
- final AppWidgetHostView view;
- if (mIsSafeModeEnabled) {
- view = new PendingAppWidgetHostView(this, item, mIconCache, true);
- prepareAppWidget(view, item);
- return view;
- }
-
TraceHelper.INSTANCE.beginSection("BIND_WIDGET_id=" + item.appWidgetId);
try {
- final LauncherAppWidgetProviderInfo appWidgetInfo;
- String removalReason = "";
- if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) {
- // If the provider is not ready, bind as a pending widget.
- appWidgetInfo = null;
- removalReason = "the provider isn't ready.";
- } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
- // The widget id is not valid. Try to find the widget based on the provider info.
- appWidgetInfo = mAppWidgetManager.findProvider(item.providerName, item.user);
- if (appWidgetInfo == null) {
- if (WidgetsModel.GO_DISABLE_WIDGETS) {
- removalReason = "widgets are disabled on go device.";
- } else {
- removalReason =
- "WidgetManagerHelper cannot find a provider from provider info.";
- }
+ InflationResult inflationResult = mWidgetInflater.inflateAppWidget(item);
+ if (inflationResult.getType() == WidgetInflater.TYPE_DELETE) {
+ getModelWriter().deleteItemFromDatabase(item, inflationResult.getReason());
+ if (restoreEventLogger != null) {
+ restoreEventLogger.logSingleFavoritesItemRestoreFailed(
+ ITEM_TYPE_APPWIDGET, RESTORE_ERROR_BIND_FAILURE);
}
- } else {
- appWidgetInfo = mAppWidgetManager.getLauncherAppWidgetInfo(item.appWidgetId,
- item.getTargetComponent());
- if (appWidgetInfo == null) {
- if (item.appWidgetId <= CUSTOM_WIDGET_ID) {
- removalReason =
- "CustomWidgetManager cannot find provider from that widget id.";
- } else {
- removalReason = "AppWidgetManager cannot find provider for that widget id."
- + " It could be because AppWidgetService is not available, or the"
- + " appWidgetId has not been bound to a the provider yet, or you"
- + " don't have access to that appWidgetId.";
- }
- }
+ return null;
}
- // If the provider is ready, but the width is not yet restored, try to restore it.
- if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)
- && (item.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED)) {
- if (appWidgetInfo == null) {
- getModelWriter().deleteItemFromDatabase(item,
- "Removing restored widget: id=" + item.appWidgetId
- + " belongs to component " + item.providerName + " user " + item.user
- + ", as the provider is null and " + removalReason);
- if (restoreEventLogger != null) {
- restoreEventLogger.logSingleFavoritesItemRestoreFailed(
- ITEM_TYPE_APPWIDGET, RESTORE_ERROR_BIND_FAILURE);
- }
- return null;
- }
-
- // If we do not have a valid id, try to bind an id.
- if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
- if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_ALLOCATED)) {
- // Id has not been allocated yet. Allocate a new id.
- item.appWidgetId = mAppWidgetHolder.allocateAppWidgetId();
- item.restoreStatus |= LauncherAppWidgetInfo.FLAG_ID_ALLOCATED;
-
- // Also try to bind the widget. If the bind fails, the user will be shown
- // a click to setup UI, which will ask for the bind permission.
- PendingAddWidgetInfo pendingInfo =
- new PendingAddWidgetInfo(appWidgetInfo, item.sourceContainer);
- pendingInfo.spanX = item.spanX;
- pendingInfo.spanY = item.spanY;
- pendingInfo.minSpanX = item.minSpanX;
- pendingInfo.minSpanY = item.minSpanY;
- Bundle options = pendingInfo.getDefaultSizeOptions(this);
-
- boolean isDirectConfig =
- item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG);
- if (isDirectConfig && item.bindOptions != null) {
- Bundle newOptions = item.bindOptions.getExtras();
- if (options != null) {
- newOptions.putAll(options);
- }
- options = newOptions;
- }
- boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed(
- item.appWidgetId, appWidgetInfo, options);
-
- // We tried to bind once. If we were not able to bind, we would need to
- // go through the permission dialog, which means we cannot skip the config
- // activity.
- item.bindOptions = null;
- item.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG;
-
- // Bind succeeded
- if (success) {
- // If the widget has a configure activity, it is still needs to set it
- // up, otherwise the widget is ready to go.
- item.restoreStatus = (appWidgetInfo.configure == null) || isDirectConfig
- ? LauncherAppWidgetInfo.RESTORE_COMPLETED
- : LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
- }
-
- getModelWriter().updateItemInDatabase(item);
- }
- } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_UI_NOT_READY)
- && (appWidgetInfo.configure == null)) {
- // The widget was marked as UI not ready, but there is no configure activity to
- // update the UI.
- item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED;
- getModelWriter().updateItemInDatabase(item);
- }
- else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_UI_NOT_READY)
- && appWidgetInfo.configure != null) {
- if (mAppWidgetManager.isAppWidgetRestored(item.appWidgetId)) {
- item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED;
- getModelWriter().updateItemInDatabase(item);
- }
- }
+ if (inflationResult.isUpdate()) {
+ getModelWriter().updateItemInDatabase(item);
}
-
- if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) {
- // Verify that we own the widget
- if (appWidgetInfo == null) {
- FileLog.e(TAG, "Removing invalid widget: id=" + item.appWidgetId);
- getModelWriter().deleteWidgetInfo(item, getAppWidgetHolder(), removalReason);
- if (restoreEventLogger != null) {
- restoreEventLogger.logSingleFavoritesItemRestoreFailed(
- ITEM_TYPE_APPWIDGET, RESTORE_ERROR_BIND_FAILURE);
- }
- return null;
- }
-
- item.minSpanX = appWidgetInfo.minSpanX;
- item.minSpanY = appWidgetInfo.minSpanY;
- view = mAppWidgetHolder.createView(this, item.appWidgetId, appWidgetInfo);
- } else if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)
- && appWidgetInfo != null) {
- mAppWidgetHolder.addPendingView(item.appWidgetId,
- new PendingAppWidgetHostView(this, item, mIconCache, false));
- view = mAppWidgetHolder.createView(this, item.appWidgetId, appWidgetInfo);
- } else {
- view = new PendingAppWidgetHostView(this, item, mIconCache, false);
- }
+ AppWidgetHostView view = inflationResult.getType() == WidgetInflater.TYPE_PENDING
+ ? new PendingAppWidgetHostView(this, item, inflationResult.getWidgetInfo())
+ : mAppWidgetHolder.createView(
+ item.appWidgetId, inflationResult.getWidgetInfo());
prepareAppWidget(view, item);
+ return view;
} finally {
TraceHelper.INSTANCE.endSection();
}
-
- return view;
}
/**
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 5ae2d71..d4bcd24 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -56,6 +56,7 @@
import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.util.SimpleBroadcastReceiver;
import com.android.launcher3.util.Themes;
+import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.widget.custom.CustomWidgetManager;
public class LauncherAppState implements SafeCloseable {
@@ -71,6 +72,8 @@
private final LauncherIconProvider mIconProvider;
private final IconCache mIconCache;
private final InvariantDeviceProfile mInvariantDeviceProfile;
+ private boolean mIsSafeModeEnabled;
+
private final RunnableList mOnTerminateCallback = new RunnableList();
public static LauncherAppState getInstance(final Context context) {
@@ -90,6 +93,8 @@
Log.v(Launcher.TAG, "LauncherAppState initiated");
Preconditions.assertUIThread();
+ mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
+ () -> context.getPackageManager().isSafeMode());
mInvariantDeviceProfile.addOnChangeListener(modelPropertiesChanged -> {
if (modelPropertiesChanged) {
refreshAndReloadLauncher();
@@ -224,6 +229,10 @@
return mInvariantDeviceProfile;
}
+ public boolean isSafeModeEnabled() {
+ return mIsSafeModeEnabled;
+ }
+
/**
* Shorthand for {@link #getInvariantDeviceProfile()}
*/
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index 51ba5c6..067d150 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -303,15 +303,11 @@
const val SHOULD_SHOW_SMARTSPACE_KEY = "SHOULD_SHOW_SMARTSPACE_KEY"
@JvmField
val ICON_STATE =
- nonRestorableItem(
- "pref_icon_shape_path",
- "",
- EncryptionType.MOVE_TO_DEVICE_PROTECTED
- )
+ nonRestorableItem("pref_icon_shape_path", "", EncryptionType.MOVE_TO_DEVICE_PROTECTED)
@JvmField
val ALL_APPS_OVERVIEW_THRESHOLD =
nonRestorableItem(
- "pref_all_apps_overview_threshold",
+ "pref_all_apps_overview_threshold",
180,
EncryptionType.MOVE_TO_DEVICE_PROTECTED
)
@@ -319,58 +315,54 @@
val LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE =
nonRestorableItem(
"pref_long_press_nav_handle_slop_percentage",
- LPNH_SLOP_PERCENTAGE.get(),
- EncryptionType.MOVE_TO_DEVICE_PROTECTED
+ LPNH_SLOP_PERCENTAGE.get(),
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
)
@JvmField
val LONG_PRESS_NAV_HANDLE_TIMEOUT_MS =
- nonRestorableItem(
- "pref_long_press_nav_handle_timeout_ms",
- LPNH_TIMEOUT_MS.get(),
- EncryptionType.MOVE_TO_DEVICE_PROTECTED
- )
+ nonRestorableItem(
+ "pref_long_press_nav_handle_timeout_ms",
+ LPNH_TIMEOUT_MS.get(),
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
+ )
@JvmField
val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_START_SCALE_PERCENT =
- nonRestorableItem(
- "pref_long_press_nav_handle_haptic_hint_start_scale_percent",
- LPNH_HAPTIC_HINT_START_SCALE_PERCENT.get(),
- EncryptionType.MOVE_TO_DEVICE_PROTECTED
- )
+ nonRestorableItem(
+ "pref_long_press_nav_handle_haptic_hint_start_scale_percent",
+ LPNH_HAPTIC_HINT_START_SCALE_PERCENT.get(),
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
+ )
@JvmField
val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_END_SCALE_PERCENT =
- nonRestorableItem(
- "pref_long_press_nav_handle_haptic_hint_end_scale_percent",
- LPNH_HAPTIC_HINT_END_SCALE_PERCENT.get(),
- EncryptionType.MOVE_TO_DEVICE_PROTECTED
- )
+ nonRestorableItem(
+ "pref_long_press_nav_handle_haptic_hint_end_scale_percent",
+ LPNH_HAPTIC_HINT_END_SCALE_PERCENT.get(),
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
+ )
@JvmField
val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_SCALE_EXPONENT =
- nonRestorableItem(
- "pref_long_press_nav_handle_haptic_hint_scale_exponent",
- LPNH_HAPTIC_HINT_SCALE_EXPONENT.get(),
- EncryptionType.MOVE_TO_DEVICE_PROTECTED
- )
+ nonRestorableItem(
+ "pref_long_press_nav_handle_haptic_hint_scale_exponent",
+ LPNH_HAPTIC_HINT_SCALE_EXPONENT.get(),
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
+ )
@JvmField
val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_ITERATIONS =
- nonRestorableItem(
- "pref_long_press_nav_handle_haptic_hint_iterations",
- LPNH_HAPTIC_HINT_ITERATIONS.get(),
- EncryptionType.MOVE_TO_DEVICE_PROTECTED
- )
+ nonRestorableItem(
+ "pref_long_press_nav_handle_haptic_hint_iterations",
+ LPNH_HAPTIC_HINT_ITERATIONS.get(),
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
+ )
@JvmField
val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_DELAY =
- nonRestorableItem(
- "pref_long_press_nav_handle_haptic_hint_delay",
- LPNH_HAPTIC_HINT_DELAY.get(),
- EncryptionType.MOVE_TO_DEVICE_PROTECTED
- )
+ nonRestorableItem(
+ "pref_long_press_nav_handle_haptic_hint_delay",
+ LPNH_HAPTIC_HINT_DELAY.get(),
+ EncryptionType.MOVE_TO_DEVICE_PROTECTED
+ )
@JvmField
val PRIVATE_SPACE_APPS =
- nonRestorableItem(
- "pref_private_space_apps",
- 0,
- EncryptionType.MOVE_TO_DEVICE_PROTECTED
- )
+ nonRestorableItem("pref_private_space_apps", 0, EncryptionType.MOVE_TO_DEVICE_PROTECTED)
@JvmField
val THEMED_ICONS =
backedUpItem(Themes.KEY_THEMED_ICONS, false, EncryptionType.MOVE_TO_DEVICE_PROTECTED)
@@ -420,7 +412,7 @@
)
@JvmField
val IS_FIRST_LOAD_AFTER_RESTORE =
- backedUpItem(
+ nonRestorableItem(
FIRST_LOAD_AFTER_RESTORE_KEY,
false,
EncryptionType.MOVE_TO_DEVICE_PROTECTED
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 03ac9df..e2c5795 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -342,7 +342,7 @@
});
}
- if(FeatureFlags.ENABLE_PREMIUM_HAPTICS_ALL_APPS.get() && config.userControlled
+ if (FeatureFlags.ENABLE_PREMIUM_HAPTICS_ALL_APPS.get() && config.isUserControlled()
&& Utilities.ATLEAST_S) {
if (toState == ALL_APPS) {
builder.addOnFrameListener(
@@ -367,7 +367,7 @@
// need to decide depending on the release velocity
Interpolator verticalProgressInterpolator = config.getInterpolator(ANIM_VERTICAL_PROGRESS,
- config.userControlled ? LINEAR : DECELERATE_1_7);
+ config.isUserControlled() ? LINEAR : DECELERATE_1_7);
Animator anim = createSpringAnimation(mProgress, targetProgress);
anim.setInterpolator(verticalProgressInterpolator);
builder.add(anim);
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 1782791..35c07c3 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -22,6 +22,7 @@
import android.content.Context;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.widget.DiffUtil;
import com.android.launcher3.Flags;
@@ -321,6 +322,8 @@
break;
case PrivateProfileManager.STATE_ENABLED:
// Add PS Apps only in Enabled State.
+ mPrivateProviderManager.addPrivateSpaceInstallAppButton(mAdapterItems);
+ position++;
addAppsWithSections(mPrivateApps, position);
if (mActivityContext.getAppsView() != null) {
mActivityContext.getAppsView().getActiveRecyclerView()
@@ -338,26 +341,14 @@
hasPrivateApps = appList.stream().
allMatch(mPrivateProviderManager.getItemInfoMatcher());
}
- int privateAppCount = 0;
- int numberOfColumns = mActivityContext.getDeviceProfile().numShownAllAppsColumns;
- int numberOfAppRows = (int) Math.ceil((double) appList.size() / numberOfColumns);
- for (AppInfo info : appList) {
+ for (int i = 0; i < appList.size(); i++) {
+ AppInfo info = appList.get(i);
// Apply decorator to private apps.
if (hasPrivateApps) {
- int roundRegion = ROUND_NOTHING;
- if ((privateAppCount / numberOfColumns) == numberOfAppRows - 1) {
- if ((privateAppCount % numberOfColumns) == 0) {
- // App is the first column
- roundRegion = ROUND_BOTTOM_LEFT;
- } else if ((privateAppCount % numberOfColumns) == numberOfColumns-1) {
- roundRegion = ROUND_BOTTOM_RIGHT;
- }
- }
mAdapterItems.add(AdapterItem.asAppWithDecorationInfo(info,
new SectionDecorationInfo(mActivityContext.getApplicationContext(),
- roundRegion,
+ getRoundRegions(i, appList.size()),
true /* decorateTogether */)));
- privateAppCount += 1;
} else {
mAdapterItems.add(AdapterItem.asApp(info));
}
@@ -372,6 +363,43 @@
}
}
+ /**
+ * Determines the corner regions that should be rounded for a specific app icon based on its
+ * position in a grid. Apps that should only be cared about rounding are the apps in the last
+ * row. In the last row on the first column, the app should only be rounded on the bottom left.
+ * Apps in the middle would not be rounded and the last app on the last row will ALWAYS have a
+ * {@link SectionDecorationInfo#ROUND_BOTTOM_RIGHT}.
+ *
+ * @param appIndex The index of the app icon within the app list.
+ * @param appListSize The total number of apps within the app list.
+ * @return An integer representing the corner regions to be rounded, using bitwise flags:
+ * - {@link SectionDecorationInfo#ROUND_NOTHING}: No corners should be rounded.
+ * - {@link SectionDecorationInfo#ROUND_TOP_LEFT}: Round the top-left corner.
+ * - {@link SectionDecorationInfo#ROUND_TOP_RIGHT}: Round the top-right corner.
+ * - {@link SectionDecorationInfo#ROUND_BOTTOM_LEFT}: Round the bottom-left corner.
+ * - {@link SectionDecorationInfo#ROUND_BOTTOM_RIGHT}: Round the bottom-right corner.
+ */
+ @VisibleForTesting
+ int getRoundRegions(int appIndex, int appListSize) {
+ int numberOfAppRows = (int) Math.ceil((double) appListSize / mNumAppsPerRowAllApps);
+ int roundRegion = ROUND_NOTHING;
+ // App is in the last row.
+ if ((appIndex / mNumAppsPerRowAllApps) == numberOfAppRows - 1) {
+ if ((appIndex % mNumAppsPerRowAllApps) == 0) {
+ // App is the first column.
+ roundRegion = ROUND_BOTTOM_LEFT;
+ } else if ((appIndex % mNumAppsPerRowAllApps) == mNumAppsPerRowAllApps-1) {
+ // App is in the last column.
+ roundRegion = ROUND_BOTTOM_RIGHT;
+ }
+ // Ensure the last private app is rounded on the bottom right.
+ if (appIndex == appListSize - 1) {
+ roundRegion |= ROUND_BOTTOM_RIGHT;
+ }
+ }
+ return roundRegion;
+ }
+
private static class MyDiffCallback extends DiffUtil.Callback {
private final List<AdapterItem> mOldList;
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index 693681b..c99b69f 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -17,11 +17,14 @@
package com.android.launcher3.allapps;
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
+import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_ICON;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
+import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.SettingsCache.PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -30,13 +33,21 @@
import androidx.annotation.VisibleForTesting;
+import com.android.launcher3.BuildConfig;
import com.android.launcher3.Flags;
+import com.android.launcher3.R;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.logging.StatsLogManager;
+import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.SettingsCache;
+import com.android.launcher3.util.UserIconInfo;
import java.util.ArrayList;
+import java.util.List;
import java.util.function.Predicate;
/**
@@ -71,6 +82,39 @@
return adapterItems.size();
}
+ /** Adds Private Space install app button to the layout. */
+ public void addPrivateSpaceInstallAppButton(List<BaseAllAppsAdapter.AdapterItem> adapterItems) {
+ Context context = mAllApps.getContext();
+ // Prepare intent
+ UserCache userCache = UserCache.getInstance(context);
+ UserHandle userHandle = userCache.getUserProfiles().stream()
+ .filter(user -> userCache.getUserInfo(user).type == UserIconInfo.TYPE_PRIVATE)
+ .findFirst()
+ .orElse(null);
+ Intent intent = ApiWrapper.getAppMarketActivityIntent(context,
+ BuildConfig.APPLICATION_ID, userHandle);
+
+ // Prepare bitmapInfo
+ Intent.ShortcutIconResource shortcut = Intent.ShortcutIconResource.fromContext(
+ context, com.android.launcher3.R.drawable.private_space_install_app_icon);
+ BitmapInfo bitmapInfo = LauncherIcons.obtain(context).createIconBitmap(shortcut);
+
+ AppInfo itemInfo = new AppInfo();
+ itemInfo.title = context.getResources().getString(R.string.ps_add_button_label);
+ itemInfo.intent = intent;
+ itemInfo.bitmap = bitmapInfo;
+ itemInfo.contentDescription = context.getResources().getString(
+ com.android.launcher3.R.string.ps_add_button_content_description);
+
+ BaseAllAppsAdapter.AdapterItem item = new BaseAllAppsAdapter.AdapterItem(VIEW_TYPE_ICON);
+ item.itemInfo = itemInfo;
+ item.decorationInfo = new SectionDecorationInfo(context, ROUND_NOTHING,
+ /* decorateTogether */ true);
+
+ adapterItems.add(item);
+ mAllApps.mAH.get(MAIN).mAdapter.notifyItemInserted(adapterItems.size() - 1);
+ }
+
/** Disables quiet mode for Private Space User Profile. */
public void unlockPrivateProfile() {
enableQuietMode(false);
diff --git a/src/com/android/launcher3/allapps/SectionDecorationInfo.java b/src/com/android/launcher3/allapps/SectionDecorationInfo.java
index 1fed2b6..c438d19 100644
--- a/src/com/android/launcher3/allapps/SectionDecorationInfo.java
+++ b/src/com/android/launcher3/allapps/SectionDecorationInfo.java
@@ -22,11 +22,11 @@
public class SectionDecorationInfo {
- public static final int ROUND_NOTHING = 1 << 1;
- public static final int ROUND_TOP_LEFT = 1 << 2;
- public static final int ROUND_TOP_RIGHT = 1 << 3;
- public static final int ROUND_BOTTOM_LEFT = 1 << 4;
- public static final int ROUND_BOTTOM_RIGHT = 1 << 5;
+ public static final int ROUND_NOTHING = 0;
+ public static final int ROUND_TOP_LEFT = 1 << 1;
+ public static final int ROUND_TOP_RIGHT = 1 << 2;
+ public static final int ROUND_BOTTOM_LEFT = 1 << 3;
+ public static final int ROUND_BOTTOM_RIGHT = 1 << 4;
public static final int DECORATOR_ALPHA = 255;
protected boolean mShouldDecorateItemsTogether;
diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java
index b39e968e..871643e 100644
--- a/src/com/android/launcher3/folder/PreviewItemManager.java
+++ b/src/com/android/launcher3/folder/PreviewItemManager.java
@@ -37,6 +37,7 @@
import android.view.View;
import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.Utilities;
@@ -71,7 +72,8 @@
private final Context mContext;
private final FolderIcon mIcon;
- private final int mIconSize;
+ @VisibleForTesting
+ public final int mIconSize;
// These variables are all associated with the drawing of the preview; they are stored
// as member variables for shared usage and to avoid computation on each frame
@@ -428,7 +430,8 @@
p.anim = anim;
}
- private void setDrawable(PreviewItemDrawingParams p, WorkspaceItemInfo item) {
+ @VisibleForTesting
+ public void setDrawable(PreviewItemDrawingParams p, WorkspaceItemInfo item) {
if (item.hasPromiseIconUi() || (item.runtimeStatusFlags
& ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) {
PreloadIconDrawable drawable = newPendingIcon(mContext, item);
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 7c40a31..7b9f6fa 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN;
import static com.android.launcher3.Flags.enableSupportForArchiving;
+import static com.android.launcher3.Flags.enableLauncherBrMetrics;
import static com.android.launcher3.LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE;
import static com.android.launcher3.LauncherPrefs.SHOULD_SHOW_SMARTSPACE;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
@@ -232,8 +233,11 @@
LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger();
mIsRestoreFromBackup =
(Boolean) LauncherPrefs.get(mApp.getContext()).get(IS_FIRST_LOAD_AFTER_RESTORE);
- LauncherRestoreEventLogger restoreEventLogger = LauncherRestoreEventLogger
- .Companion.newInstance(mApp.getContext());
+ LauncherRestoreEventLogger restoreEventLogger = null;
+ if (enableLauncherBrMetrics()) {
+ restoreEventLogger = LauncherRestoreEventLogger.Companion
+ .newInstance(mApp.getContext());
+ }
try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
List<ShortcutInfo> allShortcuts = new ArrayList<>();
@@ -364,9 +368,11 @@
transaction.commit();
memoryLogger.clearLogs();
if (mIsRestoreFromBackup) {
- restoreEventLogger.reportLauncherRestoreResults();
mIsRestoreFromBackup = false;
LauncherPrefs.get(mApp.getContext()).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(false));
+ if (restoreEventLogger != null) {
+ restoreEventLogger.reportLauncherRestoreResults();
+ }
}
} catch (CancellationException e) {
// Loader stopped, ignore
@@ -421,7 +427,7 @@
final WidgetManagerHelper widgetHelper = new WidgetManagerHelper(context);
ModelDbController dbController = mApp.getModel().getModelDbController();
- dbController.tryMigrateDB();
+ dbController.tryMigrateDB(restoreEventLogger);
Log.d(TAG, "loadWorkspace: loading default favorites");
dbController.loadDefaultFavoritesIfNecessary();
diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java
index d2b7161..c68274a 100644
--- a/src/com/android/launcher3/model/ModelDbController.java
+++ b/src/com/android/launcher3/model/ModelDbController.java
@@ -19,6 +19,7 @@
import static android.util.Base64.NO_WRAP;
import static com.android.launcher3.DefaultLayoutParser.RES_PARTNER_DEFAULT_LAYOUT;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE;
import static com.android.launcher3.LauncherSettings.Favorites.addTableToDb;
import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_KEY;
import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_LABEL;
@@ -48,6 +49,7 @@
import android.util.Log;
import android.util.Xml;
+import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import com.android.launcher3.AutoInstallsLayout;
@@ -62,6 +64,7 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Utilities;
+import com.android.launcher3.backuprestore.LauncherRestoreEventLogger;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.provider.LauncherDbUtils;
@@ -86,6 +89,7 @@
private static final String TAG = "LauncherProvider";
private static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED";
+ private static final String RESTORE_ERROR_GRID_MIGRATION_FAILURE = "grid_migration_failed";
public static final String EXTRA_DB_NAME = "db_name";
protected DatabaseHelper mOpenHelper;
@@ -261,8 +265,12 @@
/**
* Migrates the DB if needed. If the migration failed, it clears the DB.
*/
- public void tryMigrateDB() {
+ public void tryMigrateDB(@Nullable LauncherRestoreEventLogger restoreEventLogger) {
+
if (!migrateGridIfNeeded()) {
+ if (restoreEventLogger != null) {
+ sendMetricsForFailedMigration(restoreEventLogger, getDb());
+ }
FileLog.d(TAG, "Migration failed: resetting launcher database");
createEmptyDB();
LauncherPrefs.get(mContext).putSync(
@@ -313,6 +321,30 @@
}
/**
+ * In case of migration failure, report metrics for the count of each itemType in the DB.
+ * @param restoreEventLogger logger used to report Launcher restore metrics
+ */
+ private void sendMetricsForFailedMigration(LauncherRestoreEventLogger restoreEventLogger,
+ SQLiteDatabase db) {
+ try (Cursor cursor = db.rawQuery(
+ "SELECT itemType, COUNT(*) AS count FROM favorites GROUP BY itemType",
+ null
+ )) {
+ if (cursor.moveToFirst()) {
+ do {
+ restoreEventLogger.logFavoritesItemsRestoreFailed(
+ cursor.getInt(cursor.getColumnIndexOrThrow(ITEM_TYPE)),
+ cursor.getInt(cursor.getColumnIndexOrThrow("count")),
+ RESTORE_ERROR_GRID_MIGRATION_FAILURE
+ );
+ } while (cursor.moveToNext());
+ }
+ } catch (Exception e) {
+ FileLog.e(TAG, "sendMetricsForFailedDb: Error reading from database", e);
+ }
+ }
+
+ /**
* Returns the underlying model database
*/
public SQLiteDatabase getDb() {
diff --git a/src/com/android/launcher3/model/data/AppInfo.java b/src/com/android/launcher3/model/data/AppInfo.java
index 872ce4b..ea8a7a1 100644
--- a/src/com/android/launcher3/model/data/AppInfo.java
+++ b/src/com/android/launcher3/model/data/AppInfo.java
@@ -55,7 +55,8 @@
*/
public Intent intent;
- @NonNull
+ // componentName for the Private Space Install App button can be null
+ @Nullable
public ComponentName componentName;
// Section name used for indexing.
diff --git a/src/com/android/launcher3/pm/UserCache.java b/src/com/android/launcher3/pm/UserCache.java
index 4661fd4..8708d5a 100644
--- a/src/com/android/launcher3/pm/UserCache.java
+++ b/src/com/android/launcher3/pm/UserCache.java
@@ -28,6 +28,7 @@
import androidx.annotation.AnyThread;
import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
import com.android.launcher3.util.MainThreadInitializedObject;
@@ -154,6 +155,11 @@
.orElse(Process.myUserHandle());
}
+ @VisibleForTesting
+ public void putToCache(UserHandle userHandle, UserIconInfo info) {
+ mUserToSerialMap.put(userHandle, info);
+ }
+
/**
* @see UserManager#getUserProfiles()
*/
diff --git a/src/com/android/launcher3/responsive/ResponsiveSpec.kt b/src/com/android/launcher3/responsive/ResponsiveSpec.kt
index b0e1b27..65e0b32 100644
--- a/src/com/android/launcher3/responsive/ResponsiveSpec.kt
+++ b/src/com/android/launcher3/responsive/ResponsiveSpec.kt
@@ -59,7 +59,7 @@
val cellSize: SizeSpec,
) : IResponsiveSpec {
init {
- check(isValid()) { "Invalid ResponsiveSpec found." }
+ check(isValid()) { "Invalid ResponsiveSpec found. $this" }
}
constructor(
@@ -106,7 +106,7 @@
}
if (!isValidRemainderSpace()) {
- logError("The total Remainder Space used must be lower or equal to 100%.")
+ logError("The total Remainder Space used must be equal to 0 or 1.")
return false
}
@@ -131,11 +131,12 @@
}
private fun isValidRemainderSpace(): Boolean {
- // TODO(b/313621277): This validation must be update do accept only 0 or 1 instead of <= 1f.
- return startPadding.ofRemainderSpace +
- endPadding.ofRemainderSpace +
- gutter.ofRemainderSpace +
- cellSize.ofRemainderSpace <= 1f
+ val remainderSpaceUsed =
+ startPadding.ofRemainderSpace +
+ endPadding.ofRemainderSpace +
+ gutter.ofRemainderSpace +
+ cellSize.ofRemainderSpace
+ return remainderSpaceUsed == 0f || remainderSpaceUsed == 1f
}
private fun isValidAvailableSpace(): Boolean {
@@ -254,8 +255,8 @@
startPaddingPx = spec.startPadding.getRemainderSpaceValue(remainderSpace, startPaddingPx)
endPaddingPx = spec.endPadding.getRemainderSpaceValue(remainderSpace, endPaddingPx)
- gutterPx = spec.gutter.getRemainderSpaceValue(remainderSpace, gutterPx)
- cellSizePx = spec.cellSize.getRemainderSpaceValue(remainderSpace, cellSizePx)
+ gutterPx = spec.gutter.getRemainderSpaceValue(remainderSpace, gutterPx, gutters)
+ cellSizePx = spec.cellSize.getRemainderSpaceValue(remainderSpace, cellSizePx, cells)
}
override fun hashCode(): Int {
diff --git a/src/com/android/launcher3/responsive/SizeSpec.kt b/src/com/android/launcher3/responsive/SizeSpec.kt
index d146898..41dcd5e 100644
--- a/src/com/android/launcher3/responsive/SizeSpec.kt
+++ b/src/com/android/launcher3/responsive/SizeSpec.kt
@@ -57,11 +57,16 @@
/**
* Calculates the [SizeSpec] value when remainder space value is defined. If no remainderSpace
* is 0, returns a default value.
+ *
+ * @param remainderSpace The remainder space to be used for the calculation
+ * @param defaultValue The default value to be returned when no ofRemainderSpace is defined
+ * @param factor A number to divide the remainder space. The default value is 1. This property
+ * is used to split equally the remainder space by the number of cells and gutters.
*/
- fun getRemainderSpaceValue(remainderSpace: Int, defaultValue: Int): Int {
+ fun getRemainderSpaceValue(remainderSpace: Int, defaultValue: Int, factor: Int = 1): Int {
val remainderSpaceValue =
if (ofRemainderSpace > 0) {
- (ofRemainderSpace * remainderSpace).roundToInt()
+ (ofRemainderSpace * remainderSpace / factor).roundToInt()
} else {
defaultValue
}
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index 360ff7e..e8b3066 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -19,6 +19,7 @@
import static android.animation.ValueAnimator.areAnimatorsEnabled;
import static com.android.launcher3.anim.AnimatorPlaybackController.callListenerCommandRecursively;
+import static com.android.launcher3.states.StateAnimationConfig.HANDLE_STATE_APPLY;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_ALL_ANIMATIONS;
import android.animation.Animator;
@@ -36,10 +37,13 @@
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
+import com.android.launcher3.states.StateAnimationConfig.AnimationPropertyFlags;
import com.android.launcher3.testing.shared.TestProtocol;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.stream.Collectors;
/**
* Class to manage transitions between different states for a StatefulActivity based on different
@@ -189,7 +193,7 @@
public void reapplyState(boolean cancelCurrentAnimation) {
boolean wasInAnimation = mConfig.currentAnimation != null;
- if (cancelCurrentAnimation) {
+ if (cancelCurrentAnimation && (mConfig.animProps & HANDLE_STATE_APPLY) == 0) {
// Animation canceling can trigger a cleanup routine, causing problems when we are in a
// launcher state that relies on member variable data. So if we are in one of those
// states, accelerate the current animation to its end point rather than canceling it
@@ -227,7 +231,15 @@
private void goToState(
STATE_TYPE state, boolean animated, long delay, AnimatorListener listener) {
- Log.d(TestProtocol.OVERVIEW_OVER_HOME, "go to state " + state);
+ String stackTrace = Log.getStackTraceString(new Exception("tracing state transition"));
+ String truncatedTrace =
+ Arrays.stream(stackTrace.split("\\n"))
+ .limit(5)
+ .skip(1) // Removes the line "java.lang.Exception: tracing state transition"
+ .filter(traceLine -> !traceLine.contains("StateManager.goToState"))
+ .collect(Collectors.joining("\n"));
+ Log.d(TestProtocol.OVERVIEW_OVER_HOME,
+ "go to state " + state + " partial trace:\n" + truncatedTrace);
animated &= areAnimatorsEnabled();
if (mActivity.isInState(state)) {
@@ -237,7 +249,7 @@
listener.onAnimationEnd(null);
}
return;
- } else if ((!mConfig.userControlled && animated && mConfig.targetState == state)
+ } else if ((!mConfig.isUserControlled() && animated && mConfig.targetState == state)
|| mState.shouldPreserveDataStateOnReapply()) {
// We are running the same animation as requested, and/or target state should not be
// reset -- allow the current animation to complete instead of canceling it.
@@ -343,7 +355,7 @@
public AnimatorPlaybackController createAnimationToNewWorkspace(STATE_TYPE state,
StateAnimationConfig config) {
- config.userControlled = true;
+ config.animProps |= StateAnimationConfig.USER_CONTROLLED;
cancelAnimation();
config.copyTo(mConfig);
mConfig.playbackController = createAnimationToNewWorkspaceInternal(state)
@@ -418,7 +430,7 @@
}
public void moveToRestState(boolean isAnimated) {
- if (mConfig.currentAnimation != null && mConfig.userControlled) {
+ if (mConfig.currentAnimation != null && mConfig.isUserControlled()) {
// The user is doing something. Lets not mess it up
return;
}
@@ -450,10 +462,18 @@
}
}
+ /**
+ * Sets the provided controller as the current user controlled state animation
+ */
public void setCurrentUserControlledAnimation(AnimatorPlaybackController controller) {
+ setCurrentAnimation(controller, StateAnimationConfig.USER_CONTROLLED);
+ }
+
+ public void setCurrentAnimation(AnimatorPlaybackController controller,
+ @AnimationPropertyFlags int animationProps) {
clearCurrentAnimation();
setCurrentAnimation(controller.getTarget());
- mConfig.userControlled = true;
+ mConfig.animProps = animationProps;
mConfig.playbackController = controller;
}
diff --git a/src/com/android/launcher3/statemanager/StatefulActivity.java b/src/com/android/launcher3/statemanager/StatefulActivity.java
index 520f33c..30ba703 100644
--- a/src/com/android/launcher3/statemanager/StatefulActivity.java
+++ b/src/com/android/launcher3/statemanager/StatefulActivity.java
@@ -126,16 +126,8 @@
@Override
public void reapplyUi() {
- reapplyUi(true /* cancelCurrentAnimation */);
- }
-
- /**
- * Re-applies if any state transition is not running, optionally cancelling
- * the transition if requested.
- */
- public void reapplyUi(boolean cancelCurrentAnimation) {
getRootView().dispatchInsets();
- getStateManager().reapplyState(cancelCurrentAnimation);
+ getStateManager().reapplyState(true /* cancelCurrentAnimation */);
}
@Override
diff --git a/src/com/android/launcher3/states/StateAnimationConfig.java b/src/com/android/launcher3/states/StateAnimationConfig.java
index 0d9e010..0ca5afd 100644
--- a/src/com/android/launcher3/states/StateAnimationConfig.java
+++ b/src/com/android/launcher3/states/StateAnimationConfig.java
@@ -40,8 +40,19 @@
public static final int SKIP_DEPTH_CONTROLLER = 1 << 2;
public static final int SKIP_SCRIM = 1 << 3;
+ @IntDef(flag = true, value = {
+ USER_CONTROLLED,
+ HANDLE_STATE_APPLY
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AnimationPropertyFlags {}
+ // Indicates that the animation is controlled by the user
+ public static final int USER_CONTROLLED = 1 << 0;
+ // Indicates that he animation can survive state UI resets due to inset or config changes
+ public static final int HANDLE_STATE_APPLY = 1 << 1;
+
public long duration;
- public boolean userControlled;
+ public @AnimationPropertyFlags int animProps = 0;
public @AnimationFlags int animFlags = 0;
@@ -105,12 +116,16 @@
public void copyTo(StateAnimationConfig target) {
target.duration = duration;
target.animFlags = animFlags;
- target.userControlled = userControlled;
+ target.animProps = animProps;
for (int i = 0; i < ANIM_TYPES_COUNT; i++) {
target.mInterpolators[i] = mInterpolators[i];
}
}
+ public boolean isUserControlled() {
+ return (animProps & USER_CONTROLLED) != 0;
+ }
+
/**
* Returns the interpolator set for animId or fallback if nothing is set
*
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 2c834bd..ccff095 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -153,11 +153,13 @@
}, this::getCurrentActivity);
}
- case TestProtocol.REQUEST_IME_INSETS: {
+ case TestProtocol.REQUEST_SYSTEM_GESTURE_REGION: {
return getUIProperty(Bundle::putParcelable, activity -> {
WindowInsetsCompat insets = WindowInsetsCompat.toWindowInsetsCompat(
activity.getWindow().getDecorView().getRootWindowInsets());
- return insets.getInsets(WindowInsetsCompat.Type.ime()).toPlatformInsets();
+ return insets.getInsets(WindowInsetsCompat.Type.ime()
+ | WindowInsetsCompat.Type.systemGestures())
+ .toPlatformInsets();
}, this::getCurrentActivity);
}
@@ -330,6 +332,7 @@
return null;
}
T value = provider.apply(target);
+
Bundle response = new Bundle();
bundleSetter.set(response, TestProtocol.TEST_INFO_RESPONSE_FIELD, value);
return response;
diff --git a/src/com/android/launcher3/touch/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java
index 8b9bc19..fe4a83b 100644
--- a/src/com/android/launcher3/touch/AllAppsSwipeController.java
+++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java
@@ -192,7 +192,7 @@
protected StateAnimationConfig getConfigForStates(LauncherState fromState,
LauncherState toState) {
StateAnimationConfig config = super.getConfigForStates(fromState, toState);
- config.userControlled = true;
+ config.animProps |= StateAnimationConfig.USER_CONTROLLED;
if (fromState == NORMAL && toState == ALL_APPS) {
applyNormalToAllAppsAnimConfig(mLauncher, config);
} else if (fromState == ALL_APPS && toState == NORMAL) {
@@ -209,13 +209,13 @@
config.setInterpolator(ANIM_SCRIM_FADE,
Interpolators.reverse(ALL_APPS_SCRIM_RESPONDER));
config.setInterpolator(ANIM_ALL_APPS_FADE, FINAL_FRAME);
- if (!config.userControlled) {
+ if (!config.isUserControlled()) {
config.setInterpolator(ANIM_VERTICAL_PROGRESS, EMPHASIZED);
}
config.setInterpolator(ANIM_WORKSPACE_SCALE, DECELERATED_EASE);
config.setInterpolator(ANIM_DEPTH, DECELERATED_EASE);
} else {
- if (config.userControlled) {
+ if (config.isUserControlled()) {
config.setInterpolator(ANIM_DEPTH, Interpolators.reverse(BLUR_MANUAL));
config.setInterpolator(ANIM_WORKSPACE_FADE,
Interpolators.reverse(WORKSPACE_FADE_MANUAL));
@@ -250,29 +250,32 @@
if (launcher.getDeviceProfile().isTablet) {
config.setInterpolator(ANIM_ALL_APPS_FADE, INSTANT);
config.setInterpolator(ANIM_SCRIM_FADE, ALL_APPS_SCRIM_RESPONDER);
- if (!config.userControlled) {
+ if (!config.isUserControlled()) {
config.setInterpolator(ANIM_VERTICAL_PROGRESS, EMPHASIZED);
}
config.setInterpolator(ANIM_WORKSPACE_SCALE, DECELERATED_EASE);
config.setInterpolator(ANIM_DEPTH, DECELERATED_EASE);
} else {
- config.setInterpolator(ANIM_DEPTH, config.userControlled ? BLUR_MANUAL : BLUR_ATOMIC);
+ config.setInterpolator(ANIM_DEPTH,
+ config.isUserControlled() ? BLUR_MANUAL : BLUR_ATOMIC);
config.setInterpolator(ANIM_WORKSPACE_FADE,
- config.userControlled ? WORKSPACE_FADE_MANUAL : WORKSPACE_FADE_ATOMIC);
+ config.isUserControlled() ? WORKSPACE_FADE_MANUAL : WORKSPACE_FADE_ATOMIC);
config.setInterpolator(ANIM_WORKSPACE_SCALE,
- config.userControlled ? WORKSPACE_SCALE_MANUAL : WORKSPACE_SCALE_ATOMIC);
+ config.isUserControlled() ? WORKSPACE_SCALE_MANUAL : WORKSPACE_SCALE_ATOMIC);
config.setInterpolator(ANIM_HOTSEAT_FADE,
- config.userControlled ? HOTSEAT_FADE_MANUAL : HOTSEAT_FADE_ATOMIC);
+ config.isUserControlled() ? HOTSEAT_FADE_MANUAL : HOTSEAT_FADE_ATOMIC);
config.setInterpolator(ANIM_HOTSEAT_SCALE,
- config.userControlled ? HOTSEAT_SCALE_MANUAL : HOTSEAT_SCALE_ATOMIC);
+ config.isUserControlled() ? HOTSEAT_SCALE_MANUAL : HOTSEAT_SCALE_ATOMIC);
config.setInterpolator(ANIM_HOTSEAT_TRANSLATE,
- config.userControlled ? HOTSEAT_TRANSLATE_MANUAL : HOTSEAT_TRANSLATE_ATOMIC);
+ config.isUserControlled()
+ ? HOTSEAT_TRANSLATE_MANUAL
+ : HOTSEAT_TRANSLATE_ATOMIC);
config.setInterpolator(ANIM_SCRIM_FADE,
- config.userControlled ? SCRIM_FADE_MANUAL : SCRIM_FADE_ATOMIC);
+ config.isUserControlled() ? SCRIM_FADE_MANUAL : SCRIM_FADE_ATOMIC);
config.setInterpolator(ANIM_ALL_APPS_FADE,
- config.userControlled ? ALL_APPS_FADE_MANUAL : ALL_APPS_FADE_ATOMIC);
+ config.isUserControlled() ? ALL_APPS_FADE_MANUAL : ALL_APPS_FADE_ATOMIC);
config.setInterpolator(ANIM_VERTICAL_PROGRESS,
- config.userControlled
+ config.isUserControlled()
? ALL_APPS_VERTICAL_PROGRESS_MANUAL
: ALL_APPS_VERTICAL_PROGRESS_ATOMIC);
}
@@ -285,7 +288,7 @@
*/
public static void applyOverviewToAllAppsAnimConfig(
DeviceProfile deviceProfile, StateAnimationConfig config, float threshold) {
- config.userControlled = true;
+ config.animProps |= StateAnimationConfig.USER_CONTROLLED;
config.animFlags = SKIP_OVERVIEW;
if (deviceProfile.isTablet) {
config.setInterpolator(ANIM_ALL_APPS_FADE, INSTANT);
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
index dcbf7d1..7077ad9 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -285,7 +285,7 @@
primaryIconView.setTranslationX(0);
secondaryIconView.setTranslationX(0);
if (enableOverviewIconMenu()) {
- if (primaryIconView.getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
+ if (isRtl) {
primaryIconView.setTranslationY(groupedTaskViewHeight - primarySnapshotHeight);
secondaryIconView.setTranslationY(0);
} else {
@@ -295,14 +295,25 @@
} else if (splitConfig.initiatedFromSeascape) {
// if the split was initiated from seascape,
// the task on the right (secondary) is slightly larger
- primaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset
- + taskIconHeight);
- secondaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset);
+ if (isRtl) {
+ primaryIconView.setTranslationY(bottomToMidpointOffset - insetOffset
+ + taskIconHeight);
+ secondaryIconView.setTranslationY(bottomToMidpointOffset - insetOffset);
+ } else {
+ primaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset
+ + taskIconHeight);
+ secondaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset);
+ }
} else {
// if not,
// the task on the left (primary) is slightly larger
- primaryIconView.setTranslationY(-bottomToMidpointOffset + taskIconHeight);
- secondaryIconView.setTranslationY(-bottomToMidpointOffset);
+ if (isRtl) {
+ primaryIconView.setTranslationY(bottomToMidpointOffset + taskIconHeight);
+ secondaryIconView.setTranslationY(bottomToMidpointOffset);
+ } else {
+ primaryIconView.setTranslationY(-bottomToMidpointOffset + taskIconHeight);
+ secondaryIconView.setTranslationY(-bottomToMidpointOffset);
+ }
}
primaryIconView.setLayoutParams(primaryIconParams);
diff --git a/src/com/android/launcher3/util/CannedAnimationCoordinator.kt b/src/com/android/launcher3/util/CannedAnimationCoordinator.kt
index 18f8339..85f81f5 100644
--- a/src/com/android/launcher3/util/CannedAnimationCoordinator.kt
+++ b/src/com/android/launcher3/util/CannedAnimationCoordinator.kt
@@ -26,6 +26,8 @@
import com.android.launcher3.anim.AnimatorPlaybackController
import com.android.launcher3.anim.PendingAnimation
import com.android.launcher3.statemanager.StatefulActivity
+import com.android.launcher3.states.StateAnimationConfig.HANDLE_STATE_APPLY
+import com.android.launcher3.states.StateAnimationConfig.USER_CONTROLLED
import java.util.function.Consumer
private const val TAG = "CannedAnimCoordinator"
@@ -107,8 +109,15 @@
}
// Link this to the state manager so that it auto-cancels when state changes
recreatePending = false
+ // Animator coordinator takes care of reapplying the animation due to state reset. Set the
+ // flags accordingly
animationController =
- controller.apply { activity.stateManager.setCurrentUserControlledAnimation(this) }
+ controller.apply {
+ activity.stateManager.setCurrentAnimation(
+ this,
+ USER_CONTROLLED or HANDLE_STATE_APPLY
+ )
+ }
recreateAnimation(provider)
}
diff --git a/src/com/android/launcher3/util/CellContentDimensions.kt b/src/com/android/launcher3/util/CellContentDimensions.kt
index 3c8e0c4..5059c2f 100644
--- a/src/com/android/launcher3/util/CellContentDimensions.kt
+++ b/src/com/android/launcher3/util/CellContentDimensions.kt
@@ -48,7 +48,10 @@
cellContentHeight = getCellContentHeight()
// Step 3. Decrease label size
- if (cellContentHeight > cellHeightPx) {
+ if (
+ cellContentHeight > cellHeightPx &&
+ iconTextSizePx > iconSizeSteps.minimumIconLabelSize
+ ) {
iconTextSizePx =
max(
iconSizeSteps.minimumIconLabelSize,
@@ -58,6 +61,17 @@
}
}
+ // For some cases, depending on the display size, the content might not fit inside the
+ // cell height after considering the minimum icon and label size allowed.
+ // For these extreme cases, we will allow the icon size to be smaller than
+ // [IconSizeSteps.minimumIconSize] to fit inside the cell height without cropping.
+ while (
+ cellContentHeight > cellHeightPx && iconSizePx > IconSizeSteps.ICON_SIZE_STEP_EXTRA
+ ) {
+ iconSizePx -= IconSizeSteps.ICON_SIZE_STEP_EXTRA
+ cellContentHeight = getCellContentHeight()
+ }
+
return cellContentHeight
}
diff --git a/src/com/android/launcher3/util/IconSizeSteps.kt b/src/com/android/launcher3/util/IconSizeSteps.kt
index 6128eb4..a207d5c 100644
--- a/src/com/android/launcher3/util/IconSizeSteps.kt
+++ b/src/com/android/launcher3/util/IconSizeSteps.kt
@@ -49,5 +49,9 @@
companion object {
internal const val TEXT_STEP = 1
+
+ // This icon extra step is used for stepping down logic in extreme cases when it's
+ // necessary to reduce the icon size below minimum size available in [icon_size_steps].
+ internal const val ICON_SIZE_STEP_EXTRA = 2
}
}
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHost.java b/src/com/android/launcher3/widget/LauncherAppWidgetHost.java
index 739e204..b1c477c 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHost.java
@@ -21,13 +21,22 @@
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.RemoteViews;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.util.Executors;
+import com.android.launcher3.util.SafeCloseable;
+import com.android.launcher3.widget.LauncherWidgetHolder.ProviderChangedListener;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.WeakHashMap;
import java.util.function.IntConsumer;
/**
@@ -37,8 +46,7 @@
*/
class LauncherAppWidgetHost extends AppWidgetHost {
@NonNull
- private final ArrayList<LauncherWidgetHolder.ProviderChangedListener>
- mProviderChangeListeners = new ArrayList<>();
+ private final List<ProviderChangedListener> mProviderChangeListeners;
@NonNull
private final Context mContext;
@@ -46,33 +54,13 @@
@Nullable
private final IntConsumer mAppWidgetRemovedCallback;
- @NonNull
- private final LauncherWidgetHolder mHolder;
-
public LauncherAppWidgetHost(@NonNull Context context,
- @Nullable IntConsumer appWidgetRemovedCallback, @NonNull LauncherWidgetHolder holder) {
+ @Nullable IntConsumer appWidgetRemovedCallback,
+ List<ProviderChangedListener> providerChangeListeners) {
super(context, APPWIDGET_HOST_ID);
mContext = context;
mAppWidgetRemovedCallback = appWidgetRemovedCallback;
- mHolder = holder;
- }
-
- /**
- * Add a listener that is triggered when the providers of the widgets are changed
- * @param listener The listener that notifies when the providers changed
- */
- public void addProviderChangeListener(
- @NonNull LauncherWidgetHolder.ProviderChangedListener listener) {
- mProviderChangeListeners.add(listener);
- }
-
- /**
- * Remove the specified listener from the host
- * @param listener The listener that is to be removed from the host
- */
- public void removeProviderChangeListener(
- LauncherWidgetHolder.ProviderChangedListener listener) {
- mProviderChangeListeners.remove(listener);
+ mProviderChangeListeners = providerChangeListeners;
}
@Override
@@ -89,7 +77,7 @@
@NonNull
public LauncherAppWidgetHostView onCreateView(Context context, int appWidgetId,
AppWidgetProviderInfo appWidget) {
- return mHolder.onCreateView(context, appWidgetId);
+ return new ListenableHostView(context);
}
/**
@@ -115,7 +103,10 @@
if (mAppWidgetRemovedCallback == null) {
return;
}
- mAppWidgetRemovedCallback.accept(appWidgetId);
+ // Route the call via model thread, in case it comes while a loader-bind is in progress
+ Executors.MODEL_EXECUTOR.execute(
+ () -> Executors.MAIN_EXECUTOR.execute(
+ () -> mAppWidgetRemovedCallback.accept(appWidgetId)));
}
/**
@@ -126,4 +117,36 @@
super.clearViews();
}
+ public static class ListenableHostView extends LauncherAppWidgetHostView {
+
+ private Set<Runnable> mUpdateListeners = Collections.EMPTY_SET;
+
+ ListenableHostView(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void updateAppWidget(RemoteViews remoteViews) {
+ super.updateAppWidget(remoteViews);
+ mUpdateListeners.forEach(Runnable::run);
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+ info.setClassName(LauncherAppWidgetHostView.class.getName());
+ }
+
+ /**
+ * Adds a callback to be run everytime the provided app widget updates.
+ * @return a closable to remove this callback
+ */
+ public SafeCloseable addUpdateListener(Runnable callback) {
+ if (mUpdateListeners == Collections.EMPTY_SET) {
+ mUpdateListeners = Collections.newSetFromMap(new WeakHashMap<>());
+ }
+ mUpdateListeners.add(callback);
+ return () -> mUpdateListeners.remove(callback);
+ }
+ }
}
diff --git a/src/com/android/launcher3/widget/LauncherWidgetHolder.java b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
index fbd48cf..23127b3 100644
--- a/src/com/android/launcher3/widget/LauncherWidgetHolder.java
+++ b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
@@ -42,8 +42,12 @@
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.ResourceBasedOverride;
+import com.android.launcher3.util.SafeCloseable;
+import com.android.launcher3.widget.LauncherAppWidgetHost.ListenableHostView;
import com.android.launcher3.widget.custom.CustomWidgetManager;
+import java.util.ArrayList;
+import java.util.List;
import java.util.function.IntConsumer;
/**
@@ -61,15 +65,14 @@
FLAG_STATE_IS_NORMAL | FLAG_ACTIVITY_STARTED | FLAG_ACTIVITY_RESUMED;
@NonNull
- private final Context mContext;
+ protected final Context mContext;
@NonNull
private final AppWidgetHost mWidgetHost;
@NonNull
protected final SparseArray<LauncherAppWidgetHostView> mViews = new SparseArray<>();
- @NonNull
- private final SparseArray<PendingAppWidgetHostView> mPendingViews = new SparseArray<>();
+ protected final List<ProviderChangedListener> mProviderChangedListeners = new ArrayList<>();
protected int mFlags = FLAG_STATE_IS_NORMAL;
@@ -86,7 +89,8 @@
protected AppWidgetHost createHost(
Context context, @Nullable IntConsumer appWidgetRemovedCallback) {
- return new LauncherAppWidgetHost(context, appWidgetRemovedCallback, this);
+ return new LauncherAppWidgetHost(
+ context, appWidgetRemovedCallback, mProviderChangedListeners);
}
/**
@@ -158,28 +162,6 @@
}
/**
- * Add the pending view to the host for complete configuration in further steps
- * @param appWidgetId The ID of the specified app widget
- * @param view The {@link PendingAppWidgetHostView} of the app widget
- */
- public void addPendingView(int appWidgetId, @NonNull PendingAppWidgetHostView view) {
- mPendingViews.put(appWidgetId, view);
- }
-
- /**
- * @param appWidgetId The app widget id of the specified widget
- * @return The {@link PendingAppWidgetHostView} of the widget if it exists, null otherwise
- */
- @Nullable
- protected PendingAppWidgetHostView getPendingView(int appWidgetId) {
- return mPendingViews.get(appWidgetId);
- }
-
- protected void removePendingView(int appWidgetId) {
- mPendingViews.remove(appWidgetId);
- }
-
- /**
* Called when the launcher is destroyed
*/
public void destroy() {
@@ -201,18 +183,18 @@
* Add a listener that is triggered when the providers of the widgets are changed
* @param listener The listener that notifies when the providers changed
*/
- public void addProviderChangeListener(@NonNull ProviderChangedListener listener) {
- LauncherAppWidgetHost tempHost = (LauncherAppWidgetHost) mWidgetHost;
- tempHost.addProviderChangeListener(listener);
+ public void addProviderChangeListener(
+ @NonNull LauncherWidgetHolder.ProviderChangedListener listener) {
+ MAIN_EXECUTOR.execute(() -> mProviderChangedListeners.add(listener));
}
/**
* Remove the specified listener from the host
* @param listener The listener that is to be removed from the host
*/
- public void removeProviderChangeListener(ProviderChangedListener listener) {
- LauncherAppWidgetHost tempHost = (LauncherAppWidgetHost) mWidgetHost;
- tempHost.removeProviderChangeListener(listener);
+ public void removeProviderChangeListener(
+ LauncherWidgetHolder.ProviderChangedListener listener) {
+ MAIN_EXECUTOR.execute(() -> mProviderChangedListeners.remove(listener));
}
/**
@@ -316,32 +298,51 @@
}
/**
+ * Adds a callback to be run everytime the provided app widget updates.
+ * @return a closable to remove this callback
+ */
+ public SafeCloseable addOnUpdateListener(
+ int appWidgetId, LauncherAppWidgetProviderInfo appWidget, Runnable callback) {
+ if (createView(appWidgetId, appWidget) instanceof ListenableHostView lhv) {
+ return lhv.addUpdateListener(callback);
+ }
+ return () -> { };
+ }
+
+ /**
* Create a view for the specified app widget
- * @param context The activity context for which the view is created
+ *
* @param appWidgetId The ID of the widget
- * @param appWidget The {@link LauncherAppWidgetProviderInfo} of the widget
+ * @param appWidget The {@link LauncherAppWidgetProviderInfo} of the widget
* @return A view for the widget
*/
@NonNull
- public AppWidgetHostView createView(@NonNull Context context, int appWidgetId,
- @NonNull LauncherAppWidgetProviderInfo appWidget) {
-
+ public AppWidgetHostView createView(
+ int appWidgetId, @NonNull LauncherAppWidgetProviderInfo appWidget) {
if (appWidget.isCustomWidget()) {
- LauncherAppWidgetHostView lahv = new LauncherAppWidgetHostView(context);
+ LauncherAppWidgetHostView lahv = new LauncherAppWidgetHostView(mContext);
lahv.setAppWidget(0, appWidget);
- CustomWidgetManager.INSTANCE.get(context).onViewCreated(lahv);
+ CustomWidgetManager.INSTANCE.get(mContext).onViewCreated(lahv);
return lahv;
- } else if ((mFlags & FLAG_LISTENING) == 0) {
+ }
+
+ LauncherAppWidgetHostView view = createViewInternal(appWidgetId, appWidget);
+ mViews.put(appWidgetId, view);
+ return view;
+ }
+
+ @NonNull
+ protected LauncherAppWidgetHostView createViewInternal(
+ int appWidgetId, @NonNull LauncherAppWidgetProviderInfo appWidget) {
+ if ((mFlags & FLAG_LISTENING) == 0) {
// Since the launcher hasn't started listening to widget updates, we can't simply call
- // super.createView here because the later will make a binder call to retrieve
+ // host.createView here because the later will make a binder call to retrieve
// RemoteViews from system process.
- LauncherAppWidgetHostView view =
- new PendingAppWidgetHostView(context, appWidgetId, appWidget);
- mViews.put(appWidgetId, view);
- return view;
+ return new PendingAppWidgetHostView(mContext, appWidgetId, appWidget);
} else {
try {
- return mWidgetHost.createView(context, appWidgetId, appWidget);
+ return (LauncherAppWidgetHostView) mWidgetHost.createView(
+ mContext, appWidgetId, appWidget);
} catch (Exception e) {
if (!Utilities.isBinderSizeError(e)) {
throw new RuntimeException(e);
@@ -352,7 +353,7 @@
// will update.
LauncherAppWidgetHostView view = mViews.get(appWidgetId);
if (view == null) {
- view = onCreateView(mContext, appWidgetId);
+ view = new ListenableHostView(mContext);
}
view.setAppWidget(appWidgetId, appWidget);
view.switchToErrorView();
@@ -372,26 +373,6 @@
}
/**
- * Called to return a proper view when creating a view
- *
- * @param context The context for which the widget view is created
- * @param appWidgetId The ID of the added widget
- * @return A view for the specified app widget
- */
- @NonNull
- public LauncherAppWidgetHostView onCreateView(Context context, int appWidgetId) {
- final LauncherAppWidgetHostView view;
- if (getPendingView(appWidgetId) != null) {
- view = getPendingView(appWidgetId);
- removePendingView(appWidgetId);
- } else {
- view = new LauncherAppWidgetHostView(context);
- }
- mViews.put(appWidgetId, view);
- return view;
- }
-
- /**
* Clears all the views from the host
*/
public void clearViews() {
diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
index 2bd4c7e..25979c2 100644
--- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
import static com.android.launcher3.icons.FastBitmapDrawable.getDisabledColorFilter;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.content.Context;
import android.graphics.Canvas;
@@ -38,16 +39,18 @@
import android.view.View.OnClickListener;
import android.widget.RemoteViews;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.icons.FastBitmapDrawable;
-import com.android.launcher3.icons.IconCache;
import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.PackageItemInfo;
+import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.Themes;
import java.util.List;
@@ -64,12 +67,16 @@
private static final int DEFERRED_ALPHA = 0x77;
private final Rect mRect = new Rect();
- private OnClickListener mClickListener;
+
+ private final LauncherAppWidgetProviderInfo mAppwidget;
private final LauncherAppWidgetInfo mInfo;
private final int mStartState;
private final boolean mDisabledForSafeMode;
private final CharSequence mLabel;
+ private OnClickListener mClickListener;
+ private SafeCloseable mOnDetachCleanup;
+
private int mDragFlags;
private Drawable mCenterDrawable;
@@ -81,8 +88,8 @@
private Layout mSetupTextLayout;
public PendingAppWidgetHostView(Context context, LauncherAppWidgetInfo info,
- IconCache cache, boolean disabledForSafeMode) {
- this(context, info, disabledForSafeMode,
+ @Nullable LauncherAppWidgetProviderInfo appWidget) {
+ this(context, info, appWidget,
context.getResources().getText(R.string.gadget_complete_setup_text));
super.updateAppWidget(null);
@@ -91,16 +98,17 @@
if (info.pendingItemInfo == null) {
info.pendingItemInfo = new PackageItemInfo(info.providerName.getPackageName(),
info.user);
- cache.updateIconInBackground(this, info.pendingItemInfo);
+ LauncherAppState.getInstance(context).getIconCache()
+ .updateIconInBackground(this, info.pendingItemInfo);
} else {
reapplyItemInfo(info.pendingItemInfo);
}
}
public PendingAppWidgetHostView(
- Context context, int appWidgetId, LauncherAppWidgetProviderInfo appWidget) {
- this(context, new LauncherAppWidgetInfo(appWidgetId, appWidget.provider), false,
- appWidget.label);
+ Context context, int appWidgetId, @NonNull LauncherAppWidgetProviderInfo appWidget) {
+ this(context, new LauncherAppWidgetInfo(appWidgetId, appWidget.provider),
+ appWidget, appWidget.label);
getBackground().mutate().setAlpha(DEFERRED_ALPHA);
mCenterDrawable = new ColorDrawable(Color.TRANSPARENT);
@@ -109,12 +117,13 @@
}
private PendingAppWidgetHostView(Context context, LauncherAppWidgetInfo info,
- boolean disabledForSafeMode, CharSequence label) {
+ LauncherAppWidgetProviderInfo appwidget, CharSequence label) {
super(new ContextThemeWrapper(context, R.style.WidgetContainerTheme));
+ mAppwidget = appwidget;
mInfo = info;
mStartState = info.restoreStatus;
- mDisabledForSafeMode = disabledForSafeMode;
+ mDisabledForSafeMode = LauncherAppState.getInstance(context).isSafeModeEnabled();
mLabel = label;
mPaint = new TextPaint();
@@ -128,9 +137,40 @@
@Override
public void updateAppWidget(RemoteViews remoteViews) {
+ checkIfRestored();
+ }
+
+ private void checkIfRestored() {
WidgetManagerHelper widgetManagerHelper = new WidgetManagerHelper(getContext());
if (widgetManagerHelper.isAppWidgetRestored(mInfo.appWidgetId)) {
- reInflate();
+ MAIN_EXECUTOR.getHandler().post(this::reInflate);
+ }
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ if ((mAppwidget != null)
+ && !mInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)
+ && mInfo.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED) {
+ // If the widget is not completely restored, but has a valid ID, then listen of
+ // updates from provider app for potential restore complete.
+ if (mOnDetachCleanup != null) {
+ mOnDetachCleanup.close();
+ }
+ mOnDetachCleanup = mLauncher.getAppWidgetHolder()
+ .addOnUpdateListener(mInfo.appWidgetId, mAppwidget, this::checkIfRestored);
+ checkIfRestored();
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (mOnDetachCleanup != null) {
+ mOnDetachCleanup.close();
+ mOnDetachCleanup = null;
}
}
diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
index b18cd47..1cc00ef 100644
--- a/src/com/android/launcher3/widget/WidgetHostViewLoader.java
+++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
@@ -1,7 +1,6 @@
package com.android.launcher3.widget;
import android.appwidget.AppWidgetHostView;
-import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
@@ -117,7 +116,7 @@
return;
}
AppWidgetHostView hostView = mLauncher.getAppWidgetHolder().createView(
- (Context) mLauncher, mWidgetLoadingId, pInfo);
+ mWidgetLoadingId, pInfo);
mInfo.boundWidget = hostView;
// We used up the widget Id in binding the above view.
diff --git a/src/com/android/launcher3/widget/WidgetInflater.kt b/src/com/android/launcher3/widget/WidgetInflater.kt
new file mode 100644
index 0000000..00707f5
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetInflater.kt
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget
+
+import android.content.Context
+import com.android.launcher3.Launcher
+import com.android.launcher3.LauncherAppState
+import com.android.launcher3.logging.FileLog
+import com.android.launcher3.model.WidgetsModel
+import com.android.launcher3.model.data.LauncherAppWidgetInfo
+import com.android.launcher3.qsb.QsbContainerView
+
+/** Utility class for handling widget inflation taking into account all the restore state updates */
+class WidgetInflater(private val context: Context) {
+
+ private val widgetHelper = WidgetManagerHelper(context)
+
+ fun inflateAppWidget(
+ item: LauncherAppWidgetInfo,
+ ): InflationResult {
+ if (item.hasOptionFlag(LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET)) {
+ item.providerName = QsbContainerView.getSearchComponentName(context)
+ if (item.providerName == null) {
+ return InflationResult(
+ TYPE_DELETE,
+ reason = "search widget removed because search component cannot be found"
+ )
+ }
+ }
+ if (LauncherAppState.INSTANCE.get(context).isSafeModeEnabled) {
+ return InflationResult(TYPE_PENDING)
+ }
+ val appWidgetInfo: LauncherAppWidgetProviderInfo?
+ var removalReason = ""
+ if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) {
+ // If the provider is not ready, bind as a pending widget.
+ appWidgetInfo = null
+ removalReason = "the provider isn't ready."
+ } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
+ // The widget id is not valid. Try to find the widget based on the provider info.
+ appWidgetInfo = widgetHelper.findProvider(item.providerName, item.user)
+ if (appWidgetInfo == null) {
+ if (WidgetsModel.GO_DISABLE_WIDGETS) {
+ removalReason = "widgets are disabled on go device."
+ } else {
+ removalReason = "WidgetManagerHelper cannot find a provider from provider info."
+ }
+ }
+ } else {
+ appWidgetInfo =
+ widgetHelper.getLauncherAppWidgetInfo(item.appWidgetId, item.targetComponent)
+ if (appWidgetInfo == null) {
+ if (item.appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) {
+ removalReason = "CustomWidgetManager cannot find provider from that widget id."
+ } else {
+ removalReason =
+ ("AppWidgetManager cannot find provider for that widget id." +
+ " It could be because AppWidgetService is not available, or the" +
+ " appWidgetId has not been bound to a the provider yet, or you" +
+ " don't have access to that appWidgetId.")
+ }
+ }
+ }
+
+ var update = false
+
+ // If the provider is ready, but the width is not yet restored, try to restore it.
+ if (
+ !item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) &&
+ item.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED
+ ) {
+ if (appWidgetInfo == null) {
+ return InflationResult(
+ type = TYPE_DELETE,
+ reason =
+ "Removing restored widget: id=${item.appWidgetId} belongs to component" +
+ " ${item.providerName} user ${item.user}" +
+ ", as the provider is null and $removalReason"
+ )
+ }
+
+ // If we do not have a valid id, try to bind an id.
+ if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
+ if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_ALLOCATED)) {
+ // Id has not been allocated yet. Allocate a new id.
+ LauncherWidgetHolder.newInstance(context).let {
+ item.appWidgetId = it.allocateAppWidgetId()
+ it.destroy()
+ }
+ item.restoreStatus =
+ item.restoreStatus or LauncherAppWidgetInfo.FLAG_ID_ALLOCATED
+
+ // Also try to bind the widget. If the bind fails, the user will be shown
+ // a click to setup UI, which will ask for the bind permission.
+ val pendingInfo = PendingAddWidgetInfo(appWidgetInfo, item.sourceContainer)
+ pendingInfo.spanX = item.spanX
+ pendingInfo.spanY = item.spanY
+ pendingInfo.minSpanX = item.minSpanX
+ pendingInfo.minSpanY = item.minSpanY
+ var options = pendingInfo.getDefaultSizeOptions(context)
+ val isDirectConfig =
+ item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)
+ if (isDirectConfig && item.bindOptions != null) {
+ val newOptions = item.bindOptions.extras
+ if (options != null) {
+ newOptions!!.putAll(options)
+ }
+ options = newOptions
+ }
+ val success =
+ widgetHelper.bindAppWidgetIdIfAllowed(
+ item.appWidgetId,
+ appWidgetInfo,
+ options
+ )
+
+ // We tried to bind once. If we were not able to bind, we would need to
+ // go through the permission dialog, which means we cannot skip the config
+ // activity.
+ item.bindOptions = null
+ item.restoreStatus =
+ item.restoreStatus and LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG.inv()
+
+ // Bind succeeded
+ if (success) {
+ // If the widget has a configure activity, it is still needs to set it
+ // up, otherwise the widget is ready to go.
+ item.restoreStatus =
+ if ((appWidgetInfo.configure == null) || isDirectConfig)
+ LauncherAppWidgetInfo.RESTORE_COMPLETED
+ else LauncherAppWidgetInfo.FLAG_UI_NOT_READY
+ }
+ update = true
+ }
+ } else if (
+ (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_UI_NOT_READY) &&
+ (appWidgetInfo.configure == null))
+ ) {
+ // The widget was marked as UI not ready, but there is no configure activity to
+ // update the UI.
+ item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED
+ update = true
+ } else if (
+ (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_UI_NOT_READY) &&
+ appWidgetInfo.configure != null)
+ ) {
+ if (widgetHelper.isAppWidgetRestored(item.appWidgetId)) {
+ item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED
+ update = true
+ }
+ }
+ }
+
+ if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) {
+ // Verify that we own the widget
+ if (appWidgetInfo == null) {
+ FileLog.e(Launcher.TAG, "Removing invalid widget: id=" + item.appWidgetId)
+ return InflationResult(TYPE_DELETE, reason = removalReason)
+ }
+ item.minSpanX = appWidgetInfo.minSpanX
+ item.minSpanY = appWidgetInfo.minSpanY
+ return InflationResult(TYPE_REAL, isUpdate = update, widgetInfo = appWidgetInfo)
+ } else {
+ return InflationResult(TYPE_PENDING, isUpdate = update, widgetInfo = appWidgetInfo)
+ }
+ }
+
+ data class InflationResult(
+ val type: Int,
+ val reason: String? = null,
+ val isUpdate: Boolean = false,
+ val widgetInfo: LauncherAppWidgetProviderInfo? = null
+ )
+
+ companion object {
+ const val TYPE_DELETE = 0
+
+ const val TYPE_PENDING = 1
+
+ const val TYPE_REAL = 2
+ }
+}
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index bd9da0a..e5e3354 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -149,7 +149,8 @@
android:name="com.android.launcher3.testcomponent.BaseTestingActivity"
android:label="LauncherTestApp"
android:exported="true"
- android:taskAffinity="com.android.launcher3.testcomponent.Affinity1">
+ android:taskAffinity="com.android.launcher3.testcomponent.Affinity1"
+ android:theme="@style/Theme.TestActivities">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
@@ -343,6 +344,24 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity-alias>
+ <activity-alias android:name="AAAActivity"
+ android:label="AAA"
+ android:exported="true"
+ android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity-alias>
+ <activity-alias android:name="ZZZActivity"
+ android:label="ZZZ"
+ android:exported="true"
+ android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity-alias>
<!-- [b/197780098] Disable eager initialization of Jetpack libraries. -->
<provider
diff --git a/tests/res/values/styles.xml b/tests/res/values/styles.xml
new file mode 100644
index 0000000..1e1a2cd
--- /dev/null
+++ b/tests/res/values/styles.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <style name="Theme.TestActivities" parent="@android:style/Theme.DeviceDefault.DayNight">
+ <!-- Hardcoded ActionBar height to avoid changes while emulating -->
+ <!-- (56dp - default for handheld) -->
+ <item name="android:actionBarSize">168px</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/tests/res/xml/invalid_responsive_spec_1.xml b/tests/res/xml/invalid_responsive_spec_1.xml
index d1bcf65..7845d1e 100644
--- a/tests/res/xml/invalid_responsive_spec_1.xml
+++ b/tests/res/xml/invalid_responsive_spec_1.xml
@@ -27,7 +27,7 @@
<workspaceSpec
launcher:maxAvailableSize="9999dp"
launcher:dimensionType="width">
- <cellSize launcher:ofRemainderSpace="0.25" />
+ <cellSize launcher:ofRemainderSpace="1" />
<endPadding launcher:fixedSize="22dp" />
<gutter launcher:fixedSize="16dp" />
<startPadding launcher:fixedSize="22dp" />
diff --git a/tests/res/xml/invalid_responsive_spec_2.xml b/tests/res/xml/invalid_responsive_spec_2.xml
index 49e1f93..ae30bb9 100644
--- a/tests/res/xml/invalid_responsive_spec_2.xml
+++ b/tests/res/xml/invalid_responsive_spec_2.xml
@@ -28,7 +28,7 @@
<workspaceSpec
launcher:maxAvailableSize="9999dp"
launcher:dimensionType="width">
- <cellSize launcher:ofRemainderSpace="0.25" />
+ <cellSize launcher:ofRemainderSpace="1" />
<endPadding launcher:fixedSize="22dp" />
<gutter launcher:fixedSize="16dp" />
<startPadding launcher:fixedSize="22dp" />
@@ -38,7 +38,7 @@
<workspaceSpec
launcher:maxAvailableSize="9999dp"
launcher:dimensionType="width">
- <cellSize launcher:ofRemainderSpace="0.25" />
+ <cellSize launcher:ofRemainderSpace="1" />
<endPadding launcher:fixedSize="22dp" />
<gutter launcher:fixedSize="16dp" />
<startPadding launcher:fixedSize="22dp" />
diff --git a/tests/res/xml/valid_responsive_spec_unsorted.xml b/tests/res/xml/valid_responsive_spec_unsorted.xml
index 9a463d5..8676f48 100644
--- a/tests/res/xml/valid_responsive_spec_unsorted.xml
+++ b/tests/res/xml/valid_responsive_spec_unsorted.xml
@@ -22,7 +22,7 @@
<startPadding launcher:fixedSize="0dp" />
<endPadding launcher:fixedSize="34dp" />
<gutter launcher:fixedSize="12dp" />
- <cellSize launcher:ofRemainderSpace="0.25" />
+ <cellSize launcher:ofRemainderSpace="1" />
</workspaceSpec>
<!-- Height spec -->
@@ -32,7 +32,7 @@
<startPadding launcher:fixedSize="0dp" />
<endPadding launcher:fixedSize="24dp" />
<gutter launcher:fixedSize="12dp" />
- <cellSize launcher:ofRemainderSpace="0.25" />
+ <cellSize launcher:ofRemainderSpace="1" />
</workspaceSpec>
<!-- Width spec -->
@@ -42,7 +42,7 @@
<startPadding launcher:fixedSize="16dp" />
<endPadding launcher:fixedSize="64dp" />
<gutter launcher:fixedSize="12dp" />
- <cellSize launcher:ofRemainderSpace="0.25" />
+ <cellSize launcher:ofRemainderSpace="1" />
</workspaceSpec>
<workspaceSpec
launcher:dimensionType="width"
@@ -50,7 +50,7 @@
<startPadding launcher:fixedSize="36dp" />
<endPadding launcher:fixedSize="80dp" />
<gutter launcher:fixedSize="12dp" />
- <cellSize launcher:ofRemainderSpace="0.25" />
+ <cellSize launcher:ofRemainderSpace="1" />
</workspaceSpec>
<workspaceSpec
launcher:dimensionType="width"
@@ -58,7 +58,7 @@
<startPadding launcher:fixedSize="0dp" />
<endPadding launcher:fixedSize="36dp" />
<gutter launcher:fixedSize="12dp" />
- <cellSize launcher:ofRemainderSpace="0.25" />
+ <cellSize launcher:ofRemainderSpace="1" />
</workspaceSpec>
</specs>
@@ -71,7 +71,7 @@
<startPadding launcher:fixedSize="2dp" />
<endPadding launcher:fixedSize="2dp" />
<gutter launcher:fixedSize="8dp" />
- <cellSize launcher:ofRemainderSpace="0.25" />
+ <cellSize launcher:ofRemainderSpace="1" />
</workspaceSpec>
<!-- Width spec -->
@@ -81,7 +81,7 @@
<startPadding launcher:fixedSize="1dp" />
<endPadding launcher:fixedSize="1dp" />
<gutter launcher:fixedSize="8dp" />
- <cellSize launcher:ofRemainderSpace="0.25" />
+ <cellSize launcher:ofRemainderSpace="1" />
</workspaceSpec>
</specs>
@@ -122,7 +122,7 @@
<startPadding launcher:fixedSize="22dp" />
<endPadding launcher:fixedSize="22dp" />
<gutter launcher:fixedSize="16dp" />
- <cellSize launcher:ofRemainderSpace="0.25" />
+ <cellSize launcher:ofRemainderSpace="1" />
</workspaceSpec>
</specs>
</workspaceSpecs>
diff --git a/tests/res/xml/valid_workspace_file.xml b/tests/res/xml/valid_workspace_file.xml
index 9c44502..dc9963a 100644
--- a/tests/res/xml/valid_workspace_file.xml
+++ b/tests/res/xml/valid_workspace_file.xml
@@ -54,7 +54,7 @@
<startPadding launcher:fixedSize="22dp" />
<endPadding launcher:fixedSize="22dp" />
<gutter launcher:fixedSize="16dp" />
- <cellSize launcher:ofRemainderSpace="0.25" />
+ <cellSize launcher:ofRemainderSpace="1" />
</workspaceSpec>
</specs>
@@ -67,7 +67,7 @@
<startPadding launcher:fixedSize="0dp" />
<endPadding launcher:fixedSize="24dp" />
<gutter launcher:fixedSize="12dp" />
- <cellSize launcher:ofRemainderSpace="0.25" />
+ <cellSize launcher:ofRemainderSpace="1" />
</workspaceSpec>
<workspaceSpec
launcher:dimensionType="height"
@@ -75,7 +75,7 @@
<startPadding launcher:fixedSize="0dp" />
<endPadding launcher:fixedSize="34dp" />
<gutter launcher:fixedSize="12dp" />
- <cellSize launcher:ofRemainderSpace="0.25" />
+ <cellSize launcher:ofRemainderSpace="1" />
</workspaceSpec>
<!-- Width spec -->
@@ -85,7 +85,7 @@
<startPadding launcher:fixedSize="0dp" />
<endPadding launcher:fixedSize="36dp" />
<gutter launcher:fixedSize="12dp" />
- <cellSize launcher:ofRemainderSpace="0.25" />
+ <cellSize launcher:ofRemainderSpace="1" />
</workspaceSpec>
<workspaceSpec
launcher:dimensionType="width"
@@ -93,7 +93,7 @@
<startPadding launcher:fixedSize="16dp" />
<endPadding launcher:fixedSize="64dp" />
<gutter launcher:fixedSize="12dp" />
- <cellSize launcher:ofRemainderSpace="0.25" />
+ <cellSize launcher:ofRemainderSpace="1" />
</workspaceSpec>
<workspaceSpec
launcher:dimensionType="width"
@@ -101,7 +101,7 @@
<startPadding launcher:fixedSize="36dp" />
<endPadding launcher:fixedSize="80dp" />
<gutter launcher:fixedSize="12dp" />
- <cellSize launcher:ofRemainderSpace="0.25" />
+ <cellSize launcher:ofRemainderSpace="1" />
</workspaceSpec>
</specs>
</workspaceSpecs>
diff --git a/tests/res/xml/valid_workspace_unsorted_file.xml b/tests/res/xml/valid_workspace_unsorted_file.xml
index 6bf7c78..f783e9f 100644
--- a/tests/res/xml/valid_workspace_unsorted_file.xml
+++ b/tests/res/xml/valid_workspace_unsorted_file.xml
@@ -52,7 +52,7 @@
<startPadding launcher:fixedSize="22dp" />
<endPadding launcher:fixedSize="22dp" />
<gutter launcher:fixedSize="16dp" />
- <cellSize launcher:ofRemainderSpace="0.25" />
+ <cellSize launcher:ofRemainderSpace="1" />
</workspaceSpec>
</specs>
</workspaceSpecs>
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index fcb5158..3e188e6 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -107,7 +107,7 @@
public static final String REQUEST_WIDGETS_SCROLL_Y = "widgets-scroll-y";
public static final String REQUEST_TARGET_INSETS = "target-insets";
public static final String REQUEST_WINDOW_INSETS = "window-insets";
- public static final String REQUEST_IME_INSETS = "ime-insets";
+ public static final String REQUEST_SYSTEM_GESTURE_REGION = "gesture-region";
public static final String REQUEST_PID = "pid";
public static final String REQUEST_FORCE_GC = "gc";
public static final String REQUEST_RECENT_TASKS_LIST = "recent-tasks-list";
@@ -147,6 +147,8 @@
public static final String REQUEST_GET_GRID_TASK_SIZE_RECT_FOR_TABLET =
"get-grid-task-size-rect-for-tablet";
public static final String REQUEST_GET_OVERVIEW_PAGE_SPACING = "get-overview-page-spacing";
+ public static final String REQUEST_GET_OVERVIEW_CURRENT_PAGE_INDEX =
+ "get-overview-current-page-index";
public static final String REQUEST_ENABLE_ROTATION = "enable_rotation";
public static final String REQUEST_ENABLE_SUGGESTION = "enable-suggestion";
public static final String REQUEST_MODEL_QUEUE_CLEARED = "model-queue-cleared";
@@ -172,6 +174,9 @@
public static final String REQUEST_FLAG_ENABLE_GRID_ONLY_OVERVIEW = "enable-grid-only-overview";
+ public static final String REQUEST_UNSTASH_BUBBLE_BAR_IF_STASHED =
+ "unstash-bubble-bar-if-stashed";
+
/** Logs {@link Log#d(String, String)} if {@link #sDebugTracing} is true. */
public static void testLogD(String tag, String message) {
if (!sDebugTracing) {
diff --git a/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java b/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java
index 259f519..3068785 100644
--- a/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java
+++ b/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java
@@ -19,6 +19,9 @@
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
+import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_LEFT;
+import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_RIGHT;
+import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING;
import static com.android.launcher3.allapps.UserProfileManager.STATE_DISABLED;
import static com.android.launcher3.allapps.UserProfileManager.STATE_ENABLED;
import static com.android.launcher3.allapps.UserProfileManager.STATE_TRANSITION;
@@ -61,6 +64,8 @@
private static final int PRIVATE_SPACE_HEADER_ITEM_COUNT = 1;
private static final int MAIN_USER_APP_COUNT = 2;
private static final int PRIVATE_USER_APP_COUNT = 1;
+ private static final int NUM_APP_COLS = 4;
+ private static final int NUM_APP_ROWS = 3;
private AlphabeticalAppsList<?> mAlphabeticalAppsList;
@Mock
@@ -81,6 +86,7 @@
info != null && info.user.equals(PRIVATE_HANDLE));
mAlphabeticalAppsList = new AlphabeticalAppsList<>(mContext, mAllAppsStore,
null, mPrivateProfileManager);
+ mAlphabeticalAppsList.setNumAppsPerRowAllApps(NUM_APP_COLS);
}
@Test
@@ -182,6 +188,94 @@
.toList().size());
}
+ @Test
+ public void getRoundRegions_whenIndexIsMiddleOfLastRow_roundNothing() {
+ int index = 3;
+
+ int roundRegions = mAlphabeticalAppsList.getRoundRegions(index,
+ NUM_APP_COLS * NUM_APP_ROWS);
+
+ assertEquals(ROUND_NOTHING, roundRegions);
+ }
+
+ @Test
+ public void getRoundRegions_whenIndexIsInEndOfLastRow_roundBottomRight() {
+ int index = 11;
+
+ int roundRegions = mAlphabeticalAppsList.getRoundRegions(index,
+ NUM_APP_COLS * NUM_APP_ROWS);
+
+ assertEquals(ROUND_BOTTOM_RIGHT, roundRegions);
+ }
+
+ @Test
+ public void getRoundRegions_whenIndexIsInBeginningOfLastRow_roundBottomLeft() {
+ int index = 8;
+
+ int roundRegions = mAlphabeticalAppsList.getRoundRegions(index,
+ NUM_APP_COLS * NUM_APP_ROWS);
+
+ assertEquals(ROUND_BOTTOM_LEFT, roundRegions);
+ }
+
+ @Test
+ public void getRoundRegions_whenIndexIsInMiddleOfLastRow_roundNothing() {
+ int index = 9;
+
+ int roundRegions = mAlphabeticalAppsList.getRoundRegions(index,
+ NUM_APP_COLS * NUM_APP_ROWS);
+
+ assertEquals(ROUND_NOTHING, roundRegions);
+ }
+
+ @Test
+ public void getRoundRegions_whenIndexIsInMiddleRow_roundNothing() {
+ int index = 5;
+
+ int roundRegions = mAlphabeticalAppsList.getRoundRegions(index,
+ NUM_APP_COLS * NUM_APP_ROWS);
+
+ assertEquals(ROUND_NOTHING, roundRegions);
+ }
+
+ @Test
+ public void getRoundRegions_whenIndexIsInBeginningOfTopRow_roundNothing() {
+ int index = 0;
+
+ int roundRegions = mAlphabeticalAppsList.getRoundRegions(index,
+ NUM_APP_COLS * NUM_APP_ROWS);
+
+ assertEquals(ROUND_NOTHING, roundRegions);
+ }
+
+ @Test
+ public void getRoundRegions_whenIndexIsInLastOfTopRow_roundNothing() {
+ int index = 3;
+
+ int roundRegions = mAlphabeticalAppsList.getRoundRegions(index,
+ NUM_APP_COLS * NUM_APP_ROWS);
+
+ assertEquals(ROUND_NOTHING, roundRegions);
+ }
+
+ @Test
+ public void getRoundRegions_whenIndexIsInMiddleOfLastRowLastItem_roundBottomRight() {
+ int index = 9;
+
+ int roundRegions = mAlphabeticalAppsList.getRoundRegions(index, index+1);
+
+ assertEquals(ROUND_BOTTOM_RIGHT, roundRegions);
+ }
+
+ @Test
+ public void getRoundRegions_whenIndexIsInBeginningOfLastRowLastItem_roundBottomRight() {
+ int index = 8;
+
+ int roundRegions = mAlphabeticalAppsList.getRoundRegions(index, index+1);
+
+ assertEquals(ROUND_BOTTOM_RIGHT | ROUND_BOTTOM_LEFT, roundRegions);
+ }
+
private int addPrivateSpaceHeader(List<BaseAllAppsAdapter.AdapterItem> adapterItemList) {
adapterItemList.add(new BaseAllAppsAdapter.AdapterItem(VIEW_TYPE_PRIVATE_SPACE_HEADER));
return adapterItemList.size();
diff --git a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
index 92ff355..da0beb1 100644
--- a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
+++ b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
@@ -130,6 +130,7 @@
*/
@Test
@PortraitLandscape
+ @PlatinumTest(focusArea = "launcher")
public void testAllAppsFromHome() {
// Test opening all apps
assertNotNull("switchToAllApps() returned null",
@@ -181,10 +182,10 @@
executeOnLauncher(launcher -> assertTrue("flingBackward() didn't scroll App Apps",
flingBackwardY < flingForwardY));
- // Test scrolling down to YouTube.
- assertNotNull("All apps: can't find YouTube", allApps.getAppIcon("YouTube"));
- // Test scrolling up to Camera.
- assertNotNull("All apps: can't find Camera", allApps.getAppIcon("Camera"));
+ // Test scrolling down to the end of the app list.
+ assertNotNull("All apps: can't find YouTube", allApps.getAppIcon("ZZZ"));
+ // Test scrolling up to the beginning oof the app list.
+ assertNotNull("All apps: can't find Camera", allApps.getAppIcon("AAA"));
// Test failing to find a non-existing app.
final AllApps allAppsFinal = allApps;
expectFail("All apps: could find a non-existing app",
diff --git a/tests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java b/tests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
index fb364ad..dbb2715 100644
--- a/tests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
+++ b/tests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
@@ -64,7 +64,7 @@
runOnExecutorSync(MODEL_EXECUTOR, () -> {
ModelDbController controller = model.getModelDbController();
// Migrate any previous data so that the DB state is correct
- controller.tryMigrateDB();
+ controller.tryMigrateDB(null /* restoreEventLogger */);
// Create DB again to load fresh data
controller.createEmptyDB();
diff --git a/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java b/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java
index 2dc1cb2..bfa0d34 100644
--- a/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java
+++ b/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java
@@ -33,7 +33,6 @@
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.compatibility.common.util.SystemUtil;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.ui.AbstractLauncherUiTest;
@@ -141,10 +140,8 @@
@RequiresFlagsEnabled(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING)
public void testPromiseIcon_addedArchivedApp() throws Throwable {
installDummyAppAndWaitForUIUpdate();
- assertThat(
- SystemUtil.runShellCommand(
- String.format("pm archive %s", DUMMY_PACKAGE))).isEqualTo(
- "Success\n");
+ assertThat(mDevice.executeShellCommand(String.format("pm archive %s", DUMMY_PACKAGE)))
+ .isEqualTo("Success\n");
final ItemOperator findPromiseApp = (info, view) ->
info != null && TextUtils.equals(info.title, DUMMY_LABEL);
diff --git a/tests/src/com/android/launcher3/dragging/TaplDragTest.java b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
index e040367..94a96aa 100644
--- a/tests/src/com/android/launcher3/dragging/TaplDragTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
@@ -20,6 +20,8 @@
import static com.android.launcher3.util.TestConstants.AppNames.MAPS_APP_NAME;
import static com.android.launcher3.util.TestConstants.AppNames.STORE_APP_NAME;
import static com.android.launcher3.ui.AbstractLauncherUiTest.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;
@@ -40,9 +42,9 @@
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
import com.android.launcher3.util.TestUtil;
import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
+import com.android.launcher3.util.rule.TestStabilityRule;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
/**
@@ -71,7 +73,8 @@
@Test
@PortraitLandscape
@ScreenRecord
- @Ignore // b/233075289
+ // Staging; will be promoted to presubmit if stable
+ @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
@PlatinumTest(focusArea = "launcher")
public void testDragToFolder() {
// TODO: add the use case to drag an icon to an existing folder. Currently it either fails
diff --git a/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt b/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
new file mode 100644
index 0000000..4ec5b0e
--- /dev/null
+++ b/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
@@ -0,0 +1,217 @@
+/*
+ * 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.folder
+
+import android.R
+import android.content.Context
+import android.os.Process
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.LauncherPrefs
+import com.android.launcher3.LauncherPrefs.Companion.get
+import com.android.launcher3.icons.BaseIconFactory
+import com.android.launcher3.icons.FastBitmapDrawable
+import com.android.launcher3.icons.UserBadgeDrawable
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.util.FlagOp
+import com.android.launcher3.util.LauncherLayoutBuilder
+import com.android.launcher3.util.LauncherModelHelper
+import com.android.launcher3.util.UserIconInfo
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Tests for [PreviewItemManager] */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class PreviewItemManagerTest {
+
+ private lateinit var previewItemManager: PreviewItemManager
+ private lateinit var context: Context
+ private lateinit var folderItems: ArrayList<WorkspaceItemInfo>
+ private lateinit var modelHelper: LauncherModelHelper
+ private lateinit var folderIcon: FolderIcon
+
+ @Before
+ fun setup() {
+ getInstrumentation().runOnMainSync {
+ folderIcon =
+ FolderIcon(ActivityContextWrapper(ApplicationProvider.getApplicationContext()))
+ }
+ context = getInstrumentation().targetContext
+ previewItemManager = PreviewItemManager(folderIcon)
+ modelHelper = LauncherModelHelper()
+ modelHelper
+ .setupDefaultLayoutProvider(
+ LauncherLayoutBuilder()
+ .atWorkspace(0, 0, 1)
+ .putFolder(R.string.copy)
+ .addApp(LauncherModelHelper.TEST_PACKAGE, LauncherModelHelper.TEST_ACTIVITY)
+ .addApp(LauncherModelHelper.TEST_PACKAGE, LauncherModelHelper.TEST_ACTIVITY2)
+ .addApp(LauncherModelHelper.TEST_PACKAGE, LauncherModelHelper.TEST_ACTIVITY3)
+ .addApp(LauncherModelHelper.TEST_PACKAGE, LauncherModelHelper.TEST_ACTIVITY4)
+ .build()
+ )
+ .loadModelSync()
+ folderItems = modelHelper.bgDataModel.folders.valueAt(0).contents
+ folderIcon.mInfo = modelHelper.bgDataModel.folders.valueAt(0)
+ folderIcon.mInfo.contents = folderItems
+
+ // Set first icon to be themed.
+ folderItems[0]
+ .bitmap
+ .setMonoIcon(
+ folderItems[0].bitmap.icon,
+ BaseIconFactory(
+ context,
+ context.resources.configuration.densityDpi,
+ previewItemManager.mIconSize
+ )
+ )
+
+ // Set second icon to be non-themed.
+ folderItems[1]
+ .bitmap
+ .setMonoIcon(
+ null,
+ BaseIconFactory(
+ context,
+ context.resources.configuration.densityDpi,
+ previewItemManager.mIconSize
+ )
+ )
+
+ // Set third icon to be themed with badge.
+ folderItems[2]
+ .bitmap
+ .setMonoIcon(
+ folderItems[2].bitmap.icon,
+ BaseIconFactory(
+ context,
+ context.resources.configuration.densityDpi,
+ previewItemManager.mIconSize
+ )
+ )
+ folderItems[2].bitmap =
+ folderItems[2].bitmap.withFlags(profileFlagOp(UserIconInfo.TYPE_WORK))
+
+ // Set fourth icon to be non-themed with badge.
+ folderItems[3].bitmap =
+ folderItems[3].bitmap.withFlags(profileFlagOp(UserIconInfo.TYPE_WORK))
+ folderItems[3]
+ .bitmap
+ .setMonoIcon(
+ null,
+ BaseIconFactory(
+ context,
+ context.resources.configuration.densityDpi,
+ previewItemManager.mIconSize
+ )
+ )
+ }
+ @After
+ @Throws(Exception::class)
+ fun tearDown() {
+ modelHelper.destroy()
+ }
+
+ @Test
+ fun checkThemedIconWithThemingOn_iconShouldBeThemed() {
+ get(context).put(LauncherPrefs.THEMED_ICONS, true)
+ val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
+
+ previewItemManager.setDrawable(drawingParams, folderItems[0])
+
+ assert((drawingParams.drawable as FastBitmapDrawable).isThemed)
+ }
+
+ @Test
+ fun checkThemedIconWithThemingOff_iconShouldNotBeThemed() {
+ get(context).put(LauncherPrefs.THEMED_ICONS, false)
+ val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
+
+ previewItemManager.setDrawable(drawingParams, folderItems[0])
+
+ assert(!(drawingParams.drawable as FastBitmapDrawable).isThemed)
+ }
+
+ @Test
+ fun checkUnthemedIconWithThemingOn_iconShouldNotBeThemed() {
+ get(context).put(LauncherPrefs.THEMED_ICONS, true)
+ val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
+
+ previewItemManager.setDrawable(drawingParams, folderItems[1])
+
+ assert(!(drawingParams.drawable as FastBitmapDrawable).isThemed)
+ }
+
+ @Test
+ fun checkUnthemedIconWithThemingOff_iconShouldNotBeThemed() {
+ get(context).put(LauncherPrefs.THEMED_ICONS, false)
+ val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
+
+ previewItemManager.setDrawable(drawingParams, folderItems[1])
+
+ assert(!(drawingParams.drawable as FastBitmapDrawable).isThemed)
+ }
+
+ @Test
+ fun checkThemedIconWithBadgeWithThemingOn_iconAndBadgeShouldBeThemed() {
+ get(context).put(LauncherPrefs.THEMED_ICONS, true)
+ val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
+
+ previewItemManager.setDrawable(drawingParams, folderItems[2])
+
+ assert((drawingParams.drawable as FastBitmapDrawable).isThemed)
+ assert(
+ ((drawingParams.drawable as FastBitmapDrawable).badge as UserBadgeDrawable).mIsThemed
+ )
+ }
+
+ @Test
+ fun checkUnthemedIconWithBadgeWithThemingOn_badgeShouldBeThemed() {
+ get(context).put(LauncherPrefs.THEMED_ICONS, true)
+ val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
+
+ previewItemManager.setDrawable(drawingParams, folderItems[3])
+
+ assert(!(drawingParams.drawable as FastBitmapDrawable).isThemed)
+ assert(
+ ((drawingParams.drawable as FastBitmapDrawable).badge as UserBadgeDrawable).mIsThemed
+ )
+ }
+
+ @Test
+ fun checkUnthemedIconWithBadgeWithThemingOff_iconAndBadgeShouldNotBeThemed() {
+ get(context).put(LauncherPrefs.THEMED_ICONS, false)
+ val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
+
+ previewItemManager.setDrawable(drawingParams, folderItems[3])
+
+ assert(!(drawingParams.drawable as FastBitmapDrawable).isThemed)
+ assert(
+ !((drawingParams.drawable as FastBitmapDrawable).badge as UserBadgeDrawable).mIsThemed
+ )
+ }
+
+ private fun profileFlagOp(type: Int) =
+ UserIconInfo(Process.myUserHandle(), type).applyBitmapInfoFlags(FlagOp.NO_OP)
+}
diff --git a/tests/src/com/android/launcher3/responsive/ResponsiveSpecsProviderTest.kt b/tests/src/com/android/launcher3/responsive/ResponsiveSpecsProviderTest.kt
index 9681ca8..54a1dc5 100644
--- a/tests/src/com/android/launcher3/responsive/ResponsiveSpecsProviderTest.kt
+++ b/tests/src/com/android/launcher3/responsive/ResponsiveSpecsProviderTest.kt
@@ -84,7 +84,7 @@
startPadding = SizeSpec(1f.dpToPx()),
endPadding = SizeSpec(1f.dpToPx()),
gutter = SizeSpec(8f.dpToPx()),
- cellSize = SizeSpec(ofRemainderSpace = .25f)
+ cellSize = SizeSpec(ofRemainderSpace = 1f)
)
)
@@ -97,7 +97,7 @@
startPadding = SizeSpec(2f.dpToPx()),
endPadding = SizeSpec(2f.dpToPx()),
gutter = SizeSpec(8f.dpToPx()),
- cellSize = SizeSpec(ofRemainderSpace = .25f)
+ cellSize = SizeSpec(ofRemainderSpace = 1f)
),
)
@@ -182,7 +182,7 @@
startPadding = SizeSpec(22f.dpToPx()),
endPadding = SizeSpec(22f.dpToPx()),
gutter = sizeSpec16,
- cellSize = SizeSpec(ofRemainderSpace = .25f)
+ cellSize = SizeSpec(ofRemainderSpace = 1f)
)
)
@@ -231,7 +231,7 @@
startPadding = SizeSpec(0f.dpToPx()),
endPadding = SizeSpec(36f.dpToPx()),
gutter = sizeSpec12,
- cellSize = SizeSpec(ofRemainderSpace = .25f)
+ cellSize = SizeSpec(ofRemainderSpace = 1f)
),
ResponsiveSpec(
maxAvailableSize = 716.dpToPx(),
@@ -240,7 +240,7 @@
startPadding = SizeSpec(16f.dpToPx()),
endPadding = SizeSpec(64f.dpToPx()),
gutter = sizeSpec12,
- cellSize = SizeSpec(ofRemainderSpace = .25f)
+ cellSize = SizeSpec(ofRemainderSpace = 1f)
),
ResponsiveSpec(
maxAvailableSize = 9999.dpToPx(),
@@ -249,7 +249,7 @@
startPadding = SizeSpec(36f.dpToPx()),
endPadding = SizeSpec(80f.dpToPx()),
gutter = sizeSpec12,
- cellSize = SizeSpec(ofRemainderSpace = .25f)
+ cellSize = SizeSpec(ofRemainderSpace = 1f)
)
)
@@ -262,7 +262,7 @@
startPadding = SizeSpec(0f),
endPadding = SizeSpec(24f.dpToPx()),
gutter = sizeSpec12,
- cellSize = SizeSpec(ofRemainderSpace = .25f)
+ cellSize = SizeSpec(ofRemainderSpace = 1f)
),
ResponsiveSpec(
maxAvailableSize = 9999.dpToPx(),
@@ -271,7 +271,7 @@
startPadding = SizeSpec(0f),
endPadding = SizeSpec(34f.dpToPx()),
gutter = sizeSpec12,
- cellSize = SizeSpec(ofRemainderSpace = .25f)
+ cellSize = SizeSpec(ofRemainderSpace = 1f)
),
)
diff --git a/tests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt b/tests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt
index 9781645..17b0ee4 100644
--- a/tests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt
+++ b/tests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt
@@ -159,7 +159,7 @@
"maxSize=2147483647), " +
"cellSize=SizeSpec(fixedSize=0.0, " +
"ofAvailableSpace=0.0, " +
- "ofRemainderSpace=0.25, " +
+ "ofRemainderSpace=1.0, " +
"matchWorkspace=false, " +
"maxSize=2147483647)" +
")"
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
index d75b387..db38c68 100644
--- a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
@@ -18,7 +18,6 @@
import static org.junit.Assert.assertNotNull;
import android.platform.test.annotations.PlatinumTest;
-import android.platform.test.rule.ScreenRecordRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
@@ -29,9 +28,11 @@
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
import com.android.launcher3.ui.TestViewHelpers;
+import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
+import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
@@ -47,9 +48,16 @@
@Rule
public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ AbstractLauncherUiTest.initialize(this);
+ }
+
@Test
@PortraitLandscape
- @ScreenRecordRule.ScreenRecord // b/289161193
+ @ScreenRecord // b/316910614
public void testDragIcon() throws Throwable {
mLauncher.enableDebugTracing(); // b/289161193
new FavoriteItemsTransaction(mTargetContext).commitAndLoadHome(mLauncher);
@@ -99,6 +107,7 @@
*/
@PlatinumTest(focusArea = "launcher")
@Test
+ @ScreenRecord // b/316910614
public void testResizeWidget() throws Throwable {
new FavoriteItemsTransaction(mTargetContext).commitAndLoadHome(mLauncher);
diff --git a/tests/src/com/android/launcher3/util/ModelTestExtensions.kt b/tests/src/com/android/launcher3/util/ModelTestExtensions.kt
index 9d9bd517..6bd182b 100644
--- a/tests/src/com/android/launcher3/util/ModelTestExtensions.kt
+++ b/tests/src/com/android/launcher3/util/ModelTestExtensions.kt
@@ -30,7 +30,7 @@
loadModelSync()
TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
modelDbController.run {
- tryMigrateDB()
+ tryMigrateDB(null /* restoreEventLogger */)
createEmptyDB()
clearEmptyDbFlag()
}
@@ -72,7 +72,7 @@
loadModelSync()
TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
val controller: ModelDbController = modelDbController
- controller.tryMigrateDB()
+ controller.tryMigrateDB(null /* restoreEventLogger */)
modelDbController.newTransaction().use { transaction ->
val values =
ContentValues().apply {
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 0e78565..2dbc29d 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.tapl.LauncherInstrumentation.DEFAULT_POLL_INTERVAL;
import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS;
+import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
import android.graphics.Point;
import android.graphics.Rect;
@@ -362,6 +363,7 @@
/**
* Taps outside bottom sheet to dismiss it. Available on tablets only.
+ *
* @param tapRight Tap on the right of bottom sheet if true, or left otherwise.
*/
public void dismissByTappingOutsideForTablet(boolean tapRight) {
@@ -375,7 +377,7 @@
? mLauncher.waitForLauncherObject(FAST_SCROLLER_RES_ID) :
mLauncher.waitForLauncherObject(BOTTOM_SHEET_RES_ID);
- mLauncher.touchOutsideContainer(container, tapRight, false);
+ touchOutside(tapRight, container);
try (LauncherInstrumentation.Closable tapped = mLauncher.addContextLayer(
"tapped outside AllApps bottom sheet")) {
verifyVisibleContainerOnDismiss();
@@ -383,10 +385,14 @@
}
}
+ protected void touchOutside(boolean tapRight, UiObject2 container) {
+ mLauncher.touchOutsideContainer(container, tapRight, false);
+ }
+
/** Presses the meta keyboard shortcut to dismiss AllApps. */
public void dismissByKeyboardShortcut() {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
- mLauncher.getDevice().pressKeyCode(KEYCODE_META_RIGHT);
+ pressMetaKey();
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"pressed meta key")) {
verifyVisibleContainerOnDismiss();
@@ -394,12 +400,19 @@
}
}
+ protected void pressMetaKey() {
+ mLauncher.getDevice().pressKeyCode(KEYCODE_META_RIGHT);
+ }
+
/** Presses the esc key to dismiss AllApps. */
public void dismissByEscKey() {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_ESC_DOWN);
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_ESC_UP);
- mLauncher.getDevice().pressKeyCode(KEYCODE_ESCAPE);
+ mLauncher.runToState(
+ () -> mLauncher.getDevice().pressKeyCode(KEYCODE_ESCAPE),
+ NORMAL_STATE_ORDINAL,
+ "pressing esc key");
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"pressed esc key")) {
verifyVisibleContainerOnDismiss();
@@ -411,6 +424,7 @@
/**
* Return the QSB UI object on the AllApps screen.
+ *
* @return the QSB UI object.
*/
@NonNull
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 6c0010d..1bc489c 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -140,8 +140,19 @@
flingForwardImpl();
}
- mLauncher.clickLauncherObject(
- mLauncher.waitForObjectInContainer(verifyActiveContainer(), clearAllSelector));
+ final Runnable clickClearAll = () -> mLauncher.clickLauncherObject(
+ mLauncher.waitForObjectInContainer(verifyActiveContainer(),
+ clearAllSelector));
+ if (mLauncher.is3PLauncher()) {
+ mLauncher.executeAndWaitForLauncherStop(
+ clickClearAll,
+ "clicking 'Clear All'");
+ } else {
+ mLauncher.runToState(
+ clickClearAll,
+ NORMAL_STATE_ORDINAL,
+ "clicking 'Clear All'");
+ }
mLauncher.waitUntilLauncherObjectGone(clearAllSelector);
}
@@ -162,9 +173,12 @@
OverviewTask currentTask = flingToFirstTask();
- mLauncher.touchOutsideContainer(currentTask.getUiObject(),
- /* tapRight= */ true,
- /* halfwayToEdge= */ false);
+ mLauncher.runToState(
+ () -> mLauncher.touchOutsideContainer(currentTask.getUiObject(),
+ /* tapRight= */ true,
+ /* halfwayToEdge= */ false),
+ NORMAL_STATE_ORDINAL,
+ "touching outside of first task");
return new Workspace(mLauncher);
}
@@ -197,11 +211,15 @@
public void touchTaskbarBottomCorner(boolean tapRight) {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
Taskbar taskbar = new Taskbar(mLauncher);
- taskbar.touchBottomCorner(tapRight);
if (mLauncher.isTransientTaskbar()) {
+ mLauncher.runToState(
+ () -> taskbar.touchBottomCorner(tapRight),
+ NORMAL_STATE_ORDINAL,
+ "touching taskbar");
// Tapping outside Transient Taskbar returns to Workspace, wait for that state.
new Workspace(mLauncher);
} else {
+ taskbar.touchBottomCorner(tapRight);
// Should stay in Overview.
verifyActiveContainer();
verifyActionsViewVisibility();
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
index 9ca2dc8..f8e1c10 100644
--- a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
@@ -30,8 +30,8 @@
/**
* Swipes up or down to dismiss to Workspace.
- * @param swipeDown Swipe all apps down to dismiss, otherwise swipe up to dismiss by going home.
*
+ * @param swipeDown Swipe all apps down to dismiss, otherwise swipe up to dismiss by going home.
* @return the Workspace object.
*/
@NonNull
@@ -131,4 +131,20 @@
return new Workspace(mLauncher);
}
}
+
+ @Override
+ protected void touchOutside(boolean tapRight, UiObject2 container) {
+ mLauncher.runToState(
+ () -> super.touchOutside(tapRight, container),
+ NORMAL_STATE_ORDINAL,
+ "touching outside");
+ }
+
+ @Override
+ protected void pressMetaKey() {
+ mLauncher.runToState(
+ () -> super.pressMetaKey(),
+ NORMAL_STATE_ORDINAL,
+ "pressing meta key");
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeQsb.java b/tests/tapl/com/android/launcher3/tapl/HomeQsb.java
index 5385c65..c1fc45f 100644
--- a/tests/tapl/com/android/launcher3/tapl/HomeQsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/HomeQsb.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.tapl;
+import static com.android.launcher3.testing.shared.TestProtocol.ALL_APPS_STATE_ORDINAL;
+
import androidx.test.uiautomator.UiObject2;
/**
@@ -25,4 +27,13 @@
HomeQsb(LauncherInstrumentation launcher, UiObject2 hotseat) {
super(launcher, hotseat, "search_container_hotseat");
}
+
+ @Override
+ protected void clickQsb() {
+ // Clicking Qsb will switch to All Apps state.
+ mLauncher.runToState(
+ () -> super.clickQsb(),
+ ALL_APPS_STATE_ORDINAL,
+ "Clicking Qsb");
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index 501c4c3..200f2ff 100644
--- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -130,8 +130,11 @@
int endX = startX;
int endY = startY - taskbarFromNavThreshold;
- mLauncher.linearGesture(startX, startY, endX, endY, 10, /* slowDown= */ true,
- LauncherInstrumentation.GestureScope.EXPECT_PILFER);
+ mLauncher.executeAndWaitForLauncherStop(
+ () -> mLauncher.linearGesture(startX, startY, endX, endY, 10,
+ /* slowDown= */ true,
+ LauncherInstrumentation.GestureScope.EXPECT_PILFER),
+ "swiping");
LauncherInstrumentation.log("swipeUpToUnstashTaskbar: sent linear swipe up gesture");
return new Taskbar(mLauncher);
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 508f39b..e359cc8 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -385,8 +385,8 @@
.getParcelable(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
- Insets getImeInsets() {
- return getTestInfo(TestProtocol.REQUEST_IME_INSETS)
+ Insets getSystemGestureRegion() {
+ return getTestInfo(TestProtocol.REQUEST_SYSTEM_GESTURE_REGION)
.getParcelable(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
@@ -420,6 +420,11 @@
.getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
+ public int getOverviewCurrentPageIndex() {
+ return getTestInfo(TestProtocol.REQUEST_GET_OVERVIEW_CURRENT_PAGE_INDEX)
+ .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ }
+
float getExactScreenCenterX() {
return getRealDisplaySize().x / 2f;
}
@@ -1022,11 +1027,11 @@
return;
}
- linearGesture(
- displaySize.x / 2, displaySize.y - 1,
- displaySize.x / 2, 0,
- ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
- false, GestureScope.EXPECT_PILFER);
+ if (isLauncher3()) {
+ gestureToDismissPopup(displaySize);
+ } else {
+ runToState(() -> gestureToDismissPopup(displaySize), NORMAL_STATE_ORDINAL, "swiping");
+ }
try (LauncherInstrumentation.Closable c1 = addContextLayer(
String.format("Swiped up from floating view %s to home", floatingRes.get()))) {
@@ -1035,6 +1040,14 @@
}
}
+ private void gestureToDismissPopup(Point displaySize) {
+ linearGesture(
+ displaySize.x / 2, displaySize.y - 1,
+ displaySize.x / 2, 0,
+ ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
+ false, GestureScope.EXPECT_PILFER);
+ }
+
/**
* @return the Workspace object.
* @deprecated use goHome().
@@ -2155,6 +2168,11 @@
getTestInfo(TestProtocol.REQUEST_UNSTASH_TASKBAR_IF_STASHED);
}
+ /** Shows the bubble bar if it is stashed, otherwise this does nothing. */
+ public void showBubbleBarIfHidden() {
+ getTestInfo(TestProtocol.REQUEST_UNSTASH_BUBBLE_BAR_IF_STASHED);
+ }
+
/** Blocks the taskbar from automatically stashing based on time. */
public void enableBlockTimeout(boolean enable) {
getTestInfo(enable
@@ -2348,12 +2366,13 @@
: containerBounds.left - 1;
}
// If IME is visible and overlaps the container bounds, touch above it.
+ final Insets systemGestureRegion = getSystemGestureRegion();
int bottomBound = Math.min(
containerBounds.bottom,
- getRealDisplaySize().y - getImeInsets().bottom);
+ getRealDisplaySize().y - systemGestureRegion.bottom);
int y = (bottomBound - containerBounds.top) / 2;
// Do not tap in the status bar.
- y = Math.max(y, getWindowInsets().top);
+ y = Math.max(y, systemGestureRegion.top);
final long downTime = SystemClock.uptimeMillis();
final Point tapTarget = new Point(x, y);
diff --git a/tests/tapl/com/android/launcher3/tapl/Qsb.java b/tests/tapl/com/android/launcher3/tapl/Qsb.java
index fe2a63d..d67b8a3 100644
--- a/tests/tapl/com/android/launcher3/tapl/Qsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/Qsb.java
@@ -118,9 +118,7 @@
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to open search result page");
LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
- mLauncher.clickLauncherObject(waitForQsbObject());
- // wait for the result rendering to complete
- mLauncher.waitForIdle();
+ clickQsb();
try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer(
"clicked qsb to open search result page")) {
return createSearchResult();
@@ -128,6 +126,10 @@
}
}
+ protected void clickQsb() {
+ mLauncher.clickLauncherObject(waitForQsbObject());
+ }
+
@Override
public LauncherInstrumentation getLauncher() {
return mLauncher;
diff --git a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
index 963bf79..8d3a631 100644
--- a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.tapl;
+import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
+
import android.widget.TextView;
import androidx.test.uiautomator.By;
@@ -87,7 +89,7 @@
+ (tapRight ? "right" : "left"))) {
final UiObject2 allAppsBottomSheet =
mLauncher.waitForLauncherObject(BOTTOM_SHEET_RES_ID);
- mLauncher.touchOutsideContainer(allAppsBottomSheet, tapRight);
+ tapOutside(tapRight, allAppsBottomSheet);
try (LauncherInstrumentation.Closable tapped = mLauncher.addContextLayer(
"tapped outside AllApps bottom sheet")) {
verifyVisibleContainerOnDismiss();
@@ -95,6 +97,13 @@
}
}
+ protected void tapOutside(boolean tapRight, UiObject2 allAppsBottomSheet) {
+ mLauncher.runToState(
+ () -> mLauncher.touchOutsideContainer(allAppsBottomSheet, tapRight),
+ NORMAL_STATE_ORDINAL,
+ "tappig outside");
+ }
+
protected void verifyVisibleContainerOnDismiss() {
mLauncher.getWorkspace();
}
diff --git a/tests/tapl/com/android/launcher3/tapl/SearchResultFromTaskbarQsb.java b/tests/tapl/com/android/launcher3/tapl/SearchResultFromTaskbarQsb.java
index 00291a3..f4b4a91 100644
--- a/tests/tapl/com/android/launcher3/tapl/SearchResultFromTaskbarQsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/SearchResultFromTaskbarQsb.java
@@ -50,4 +50,9 @@
protected void verifyVisibleContainerOnDismiss() {
mLauncher.getLaunchedAppState().assertTaskbarVisible();
}
+
+ @Override
+ protected void tapOutside(boolean tapRight, UiObject2 allAppsBottomSheet) {
+ mLauncher.touchOutsideContainer(allAppsBottomSheet, tapRight);
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/SelectModeButtons.java b/tests/tapl/com/android/launcher3/tapl/SelectModeButtons.java
index 146a67c..e2bc17b 100644
--- a/tests/tapl/com/android/launcher3/tapl/SelectModeButtons.java
+++ b/tests/tapl/com/android/launcher3/tapl/SelectModeButtons.java
@@ -18,6 +18,8 @@
import static android.view.KeyEvent.KEYCODE_ESCAPE;
+import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_STATE_ORDINAL;
+
import androidx.annotation.NonNull;
import androidx.test.uiautomator.UiObject2;
@@ -69,7 +71,10 @@
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_ESC_DOWN);
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_ESC_UP);
- mLauncher.getDevice().pressKeyCode(KEYCODE_ESCAPE);
+ mLauncher.runToState(
+ () -> mLauncher.getDevice().pressKeyCode(KEYCODE_ESCAPE),
+ OVERVIEW_STATE_ORDINAL,
+ "pressing Esc");
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"pressed esc key")) {
return new Overview(mLauncher);
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index ada0a7f..a911de4 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -121,7 +121,10 @@
LauncherInstrumentation.Closable c =
mLauncher.addContextLayer("want to open all apps search")) {
verifyActiveContainer();
- mLauncher.getDevice().pressKeyCode(KEYCODE_META_RIGHT);
+ mLauncher.runToState(
+ () -> mLauncher.getDevice().pressKeyCode(KEYCODE_META_RIGHT),
+ ALL_APPS_STATE_ORDINAL,
+ "pressing keyboard shortcut");
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
"pressed meta key")) {
return new HomeAllApps(mLauncher);