Merge "Update the KQS app launch animation to match the spec exactly" 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 a62f809..3166d82 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -71,13 +71,6 @@
}
flag {
- name: "enable_launcher_br_metrics"
- namespace: "launcher"
- description: "Enables logging of Launcher restore metrics to the Backup & Restore team"
- bug: "307527314"
-}
-
-flag {
name: "enable_unfolded_two_pane_picker"
namespace: "launcher"
description: "Enables two pane widget picker for unfolded foldables"
@@ -97,3 +90,18 @@
description: "Enables support for archived apps in Launcher3, such as empty progress bar etc."
bug: "210590852"
}
+
+flag {
+ name: "enable_private_space_install_shortcut"
+ namespace: "launcher"
+ description: "Enables long-press shortcut to install a copy of an app to Private space"
+ bug: "316118005"
+}
+
+flag {
+ name: "enable_launcher_br_metrics_fixed"
+ namespace: "launcher"
+ description: "Enables logging of Launcher restore metrics to the Backup & Restore team"
+ bug: "307527314"
+ is_fixed_read_only: true
+}
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/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 3d4ce43..12c72e1 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -65,7 +65,7 @@
<string name="home_gesture_intro_title" msgid="836590312858441830">"Den Startbildschirm aufrufen"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Wenn du zum Startbildschirm gehen möchtest, wische einfach vom unteren Displayrand nach oben."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Wische mit zwei Fingern vom unteren Displayrand nach oben. So gelangst du immer zum Startbildschirm."</string>
- <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Zum StartU+00ADbildschirm"</string>
+ <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Zum Startbildschirm"</string>
<string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Wische vom unteren Displayrand nach oben"</string>
<string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Gut gemacht!"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Wische vom unteren Displayrand nach oben"</string>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 67d3827..8c9dc6a 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -1087,7 +1087,12 @@
}
backgroundRadiusAnim.addListener(
- AnimatorListeners.forEndCallback(depthController::dispose));
+ AnimatorListeners.forEndCallback(() -> {
+ // reset the depth to match the main depth controller's depth
+ depthController.stateDepth
+ .setValue(mLauncher.getDepthController().stateDepth.getValue());
+ depthController.dispose();
+ }));
return backgroundRadiusAnim;
}
@@ -1161,6 +1166,7 @@
SystemUiProxy.INSTANCE.get(mLauncher)
.registerRemoteTransition(mLauncherOpenTransition, homeCheck);
if (mBackAnimationController != null) {
+ mBackAnimationController.registerComponentCallbacks();
mBackAnimationController.registerBackCallbacks(mHandler);
}
}
@@ -1168,6 +1174,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 +1207,7 @@
mWallpaperOpenTransitionRunner = null;
if (mBackAnimationController != null) {
mBackAnimationController.unregisterBackCallbacks();
+ mBackAnimationController.unregisterComponentCallbacks();
mBackAnimationController = null;
}
}
diff --git a/quickstep/src/com/android/launcher3/model/AppEventProducer.java b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
index 7209bd8..8dded8f 100644
--- a/quickstep/src/com/android/launcher3/model/AppEventProducer.java
+++ b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
@@ -191,7 +191,7 @@
@Nullable
AppTarget toAppTarget(LauncherAtom.ItemInfo info) {
int iconInfoType = getIconInfoTypeFromItemInfo(info);
- UserCache userCache = UserCache.getInstance(mContext);
+ UserCache userCache = UserCache.INSTANCE.get(mContext);
UserHandle userHandle = userCache.getUserProfiles().stream()
.filter(user -> userCache.getUserInfo(user).type == iconInfoType)
.findFirst()
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/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index d62e117..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;
@@ -41,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;
@@ -200,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);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index e5a6021..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;
@@ -234,8 +237,21 @@
/** Called when taskbar is stashed or unstashed. */
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 (mIsStashed) {
+ 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 913ca6c..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
@@ -845,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.
*/
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
index dab9950..12f1e63 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
@@ -181,7 +181,7 @@
measuredWidth.toFloat(),
measuredHeight.toFloat(),
(measuredWidth - arrowWidth) / 2, // arrowOffsetX
- 0f, // arrowOffsetY
+ -mArrowOffsetVertical.toFloat(), // arrowOffsetY
false, // isPointingUp
true, // leftAligned
context.getColor(R.color.popup_shade_first),
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index f9fc983..491938d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -169,6 +169,7 @@
mBackgroundRenderer.setBackgroundProgress(mTaskbarBackgroundProgress);
mBackgroundRenderer.draw(canvas);
super.dispatchDraw(canvas);
+ mControllerCallbacks.drawDebugUi(canvas);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 3823c5a..3f5402f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -19,8 +19,10 @@
import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_TRANSIENT;
import android.content.res.Resources;
+import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.SystemProperties;
import android.view.ViewTreeObserver;
import com.android.launcher3.DeviceProfile;
@@ -39,6 +41,9 @@
public class TaskbarDragLayerController implements TaskbarControllers.LoggableTaskbarController,
TaskbarControllers.BackgroundRendererController {
+ private static final boolean DEBUG = SystemProperties.getBoolean(
+ "persist.debug.draw_taskbar_debug_ui", false);
+
private final TaskbarActivityContext mActivity;
private final TaskbarDragLayer mTaskbarDragLayer;
private final int mFolderMargin;
@@ -299,5 +304,15 @@
mTaskbarStashViaTouchController,
};
}
+
+ /**
+ * Draws debug UI on top of everything in TaskbarDragLayer.
+ */
+ public void drawDebugUi(Canvas canvas) {
+ if (!DEBUG) {
+ return;
+ }
+ mControllers.taskbarInsetsController.drawDebugTouchableRegionBounds(canvas);
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 7ebc18d..633383d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -15,7 +15,11 @@
*/
package com.android.launcher3.taskbar
+import android.graphics.Canvas
+import android.graphics.Color
import android.graphics.Insets
+import android.graphics.Paint
+import android.graphics.Rect
import android.graphics.Region
import android.inputmethodservice.InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR
import android.os.Binder
@@ -47,6 +51,7 @@
import com.android.launcher3.util.DisplayController
import java.io.PrintWriter
import kotlin.jvm.optionals.getOrNull
+import kotlin.math.max
/** Handles the insets that Taskbar provides to underlying apps and the IME. */
class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTaskbarController {
@@ -58,7 +63,8 @@
/** The bottom insets taskbar provides to the IME when IME is visible. */
val taskbarHeightForIme: Int = context.resources.getDimensionPixelSize(R.dimen.taskbar_ime_size)
- private val touchableRegion: Region = Region()
+ // The touchableRegion we will set unless some other state takes precedence.
+ private val defaultTouchableRegion: Region = Region()
private val insetsOwner: IBinder = Binder()
private val deviceProfileChangeListener = { _: DeviceProfile ->
onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
@@ -69,6 +75,7 @@
context,
this::onTaskbarOrBubblebarWindowHeightOrInsetsChanged
)
+ private val debugTouchableRegion = DebugTouchableRegion()
// Initialized in init.
private lateinit var controllers: TaskbarControllers
@@ -100,9 +107,9 @@
}
windowLayoutParams.providedInsets =
- if (enableTaskbarNoRecreate()) {
+ if (enableTaskbarNoRecreate() && controllers.sharedState != null) {
getProvidedInsets(
- controllers.sharedState!!.insetsFrameProviders!!,
+ controllers.sharedState!!.insetsFrameProviders,
insetsRoundedCornerFlag
)
} else {
@@ -124,7 +131,7 @@
} else {
0
}
- val touchableHeight = Math.max(taskbarTouchableHeight, bubblesTouchableHeight)
+ val touchableHeight = max(taskbarTouchableHeight, bubblesTouchableHeight)
if (
controllers.bubbleControllers.isPresent &&
@@ -132,14 +139,14 @@
) {
val iconBounds =
controllers.bubbleControllers.get().bubbleBarViewController.bubbleBarBounds
- touchableRegion.set(
+ defaultTouchableRegion.set(
iconBounds.left,
iconBounds.top,
iconBounds.right,
iconBounds.bottom
)
} else {
- touchableRegion.set(
+ defaultTouchableRegion.set(
0,
windowLayoutParams.height - touchableHeight,
context.deviceProfile.widthPx,
@@ -296,6 +303,8 @@
context.dragLayer,
insetsInfo.touchableRegion
)
+ debugTouchableRegion.lastSetTouchableBounds.set(insetsInfo.touchableRegion.bounds)
+
val bubbleBarVisible =
controllers.bubbleControllers.isPresent &&
controllers.bubbleControllers.get().bubbleBarViewController.isBubbleBarVisible()
@@ -303,21 +312,28 @@
if (context.dragLayer.alpha < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
// Let touches pass through us.
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
+ debugTouchableRegion.lastSetTouchableReason = "Taskbar is invisible"
} else if (
controllers.navbarButtonsViewController.isImeVisible &&
controllers.taskbarStashController.isStashed
) {
+ // Let touches pass through us.
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
+ debugTouchableRegion.lastSetTouchableReason = "Stashed over IME"
} else if (!controllers.uiController.isTaskbarTouchable) {
// Let touches pass through us.
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
+ debugTouchableRegion.lastSetTouchableReason = "Taskbar is not touchable"
} else if (controllers.taskbarDragController.isSystemDragInProgress) {
// Let touches pass through us.
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
+ debugTouchableRegion.lastSetTouchableReason = "System drag is in progress"
} else if (context.isTaskbarWindowFullscreen) {
// Intercept entire fullscreen window.
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME)
insetsIsTouchableRegion = false
+ debugTouchableRegion.lastSetTouchableReason = "Taskbar is fullscreen"
+ context.dragLayer.getBoundsInWindow(debugTouchableRegion.lastSetTouchableBounds, false)
} else if (
controllers.taskbarViewController.areIconsVisible() ||
context.isNavBarKidsModeActive ||
@@ -346,19 +362,33 @@
region.op(bubbleBarBounds, Region.Op.UNION)
}
insetsInfo.touchableRegion.set(region)
+ debugTouchableRegion.lastSetTouchableReason = "Transient Taskbar is in Overview"
+ debugTouchableRegion.lastSetTouchableBounds.set(region.bounds)
} else {
- insetsInfo.touchableRegion.set(touchableRegion)
+ insetsInfo.touchableRegion.set(defaultTouchableRegion)
+ debugTouchableRegion.lastSetTouchableReason = "Using default touchable region"
+ debugTouchableRegion.lastSetTouchableBounds.set(defaultTouchableRegion.bounds)
}
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
insetsIsTouchableRegion = false
} else {
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
+ debugTouchableRegion.lastSetTouchableReason =
+ "Icons are not visible, but other components such as 3 buttons might be"
}
context.excludeFromMagnificationRegion(insetsIsTouchableRegion)
}
+ /** Draws the last set touchableRegion as a red rectangle onto the given Canvas. */
+ fun drawDebugTouchableRegionBounds(canvas: Canvas) {
+ val paint = Paint()
+ paint.color = Color.RED
+ paint.style = Paint.Style.STROKE
+ canvas.drawRect(debugTouchableRegion.lastSetTouchableBounds, paint)
+ }
+
override fun dumpLogs(prefix: String, pw: PrintWriter) {
- pw.println(prefix + "TaskbarInsetsController:")
+ pw.println("${prefix}TaskbarInsetsController:")
pw.println("$prefix\twindowHeight=${windowLayoutParams.height}")
for (provider in windowLayoutParams.providedInsets) {
pw.print(
@@ -377,5 +407,12 @@
}
pw.println()
}
+ pw.println("$prefix\tlastSetTouchableBounds=${debugTouchableRegion.lastSetTouchableBounds}")
+ pw.println("$prefix\tlastSetTouchableReason=${debugTouchableRegion.lastSetTouchableReason}")
+ }
+
+ class DebugTouchableRegion {
+ val lastSetTouchableBounds = Rect()
+ var lastSetTouchableReason = ""
}
}
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 5b117fc..2f2d636 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
@@ -25,6 +25,8 @@
import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_PINNED
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_UNPINNED
import com.android.launcher3.taskbar.TaskbarDividerPopupView.Companion.createAndPopulate
import java.io.PrintWriter
@@ -54,8 +56,10 @@
}
val animateToValue =
if (!launcherPrefs.get(TASKBAR_PINNING)) {
+ statsLogManager.logger().log(LAUNCHER_TASKBAR_PINNED)
PINNING_PERSISTENT
} else {
+ statsLogManager.logger().log(LAUNCHER_TASKBAR_UNPINNED)
PINNING_TRANSIENT
}
taskbarSharedState.taskbarWasPinned = animateToValue == PINNING_TRANSIENT
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/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
index 784c560..3ebc8ed 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -80,6 +80,9 @@
if (android.os.Flags.allowPrivateProfile() && Flags.enablePrivateSpace()) {
LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
LauncherUserInfo launcherUserInfo = launcherApps.getLauncherUserInfo(user);
+ if (launcherUserInfo == null) {
+ continue;
+ }
// UserTypes not supported in Launcher are deemed to be the current
// Foreground User.
int userType = switch (launcherUserInfo.getUserType()) {
@@ -129,8 +132,10 @@
public static Intent getAppMarketActivityIntent(Context context, String packageName,
UserHandle user) {
LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
- if (android.os.Flags.allowPrivateProfile() && Flags.enablePrivateSpace()
- && Flags.privateSpaceAppInstallerButton()) {
+ if (android.os.Flags.allowPrivateProfile()
+ && Flags.enablePrivateSpace()
+ && (Flags.privateSpaceAppInstallerButton()
+ || Flags.enablePrivateSpaceInstallShortcut())) {
StartActivityParams params = new StartActivityParams((PendingIntent) null, 0);
params.intentSender = launcherApps.getAppMarketActivityIntent(packageName, user);
return ProxyActivityStarter.getLaunchIntent(context, params);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 71f4faf..0d4a7f0 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -40,6 +40,7 @@
import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
import static com.android.launcher3.popup.SystemShortcut.APP_INFO;
import static com.android.launcher3.popup.SystemShortcut.INSTALL;
+import static com.android.launcher3.popup.SystemShortcut.PRIVATE_PROFILE_INSTALL;
import static com.android.launcher3.popup.SystemShortcut.WIDGETS;
import static com.android.launcher3.taskbar.LauncherTaskbarUIController.ALL_APPS_PAGE_PROGRESS_INDEX;
import static com.android.launcher3.taskbar.LauncherTaskbarUIController.MINUS_ONE_PAGE_PROGRESS_INDEX;
@@ -95,6 +96,7 @@
import com.android.app.viewcapture.SettingsAwareViewCapture;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
import com.android.launcher3.HomeTransitionController;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings.Favorites;
@@ -415,6 +417,10 @@
shortcuts.addAll(getSplitShortcuts());
shortcuts.add(WIDGETS);
shortcuts.add(INSTALL);
+
+ if (Flags.enablePrivateSpaceInstallShortcut()) {
+ shortcuts.add(PRIVATE_PROFILE_INSTALL);
+ }
return shortcuts.stream();
}
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/LauncherRestoreEventLoggerImpl.kt b/quickstep/src/com/android/quickstep/LauncherRestoreEventLoggerImpl.kt
index 0913fca..27bd03d 100644
--- a/quickstep/src/com/android/quickstep/LauncherRestoreEventLoggerImpl.kt
+++ b/quickstep/src/com/android/quickstep/LauncherRestoreEventLoggerImpl.kt
@@ -5,10 +5,9 @@
import android.app.backup.BackupRestoreEventLogger.BackupRestoreDataType
import android.app.backup.BackupRestoreEventLogger.BackupRestoreError
import android.content.Context
-import com.android.launcher3.Flags.enableLauncherBrMetrics
+import com.android.launcher3.Flags.enableLauncherBrMetricsFixed
import com.android.launcher3.LauncherSettings.Favorites
import com.android.launcher3.backuprestore.LauncherRestoreEventLogger
-import com.android.launcher3.config.FeatureFlags.ENABLE_LAUNCHER_BR_METRICS
/**
* Concrete implementation for wrapper to log Restore event metrics for both success and failure to
@@ -45,7 +44,7 @@
count: Int,
@BackupRestoreError error: String?
) {
- if (enableLauncherBrMetrics() || ENABLE_LAUNCHER_BR_METRICS.get()) {
+ if (enableLauncherBrMetricsFixed()) {
restoreEventLogger.logItemsRestoreFailed(dataType, count, error)
}
}
@@ -57,7 +56,7 @@
* @param count the number of data items restored.
*/
override fun logLauncherItemsRestored(@BackupRestoreDataType dataType: String, count: Int) {
- if (enableLauncherBrMetrics() || ENABLE_LAUNCHER_BR_METRICS.get()) {
+ if (enableLauncherBrMetricsFixed()) {
restoreEventLogger.logItemsRestored(dataType, count)
}
}
@@ -68,7 +67,7 @@
* @param favoritesId The id of the item type from [Favorites] that was restored.
*/
override fun logSingleFavoritesItemRestored(favoritesId: Int) {
- if (enableLauncherBrMetrics() || ENABLE_LAUNCHER_BR_METRICS.get()) {
+ if (enableLauncherBrMetricsFixed()) {
restoreEventLogger.logItemsRestored(favoritesIdToDataType(favoritesId), 1)
}
}
@@ -80,7 +79,7 @@
* @param count number of items that restored.
*/
override fun logFavoritesItemsRestored(favoritesId: Int, count: Int) {
- if (enableLauncherBrMetrics() || ENABLE_LAUNCHER_BR_METRICS.get()) {
+ if (enableLauncherBrMetricsFixed()) {
restoreEventLogger.logItemsRestored(favoritesIdToDataType(favoritesId), count)
}
}
@@ -95,7 +94,7 @@
favoritesId: Int,
@BackupRestoreError error: String?
) {
- if (enableLauncherBrMetrics() || ENABLE_LAUNCHER_BR_METRICS.get()) {
+ if (enableLauncherBrMetricsFixed()) {
restoreEventLogger.logItemsRestoreFailed(favoritesIdToDataType(favoritesId), 1, error)
}
}
@@ -112,7 +111,7 @@
count: Int,
@BackupRestoreError error: String?
) {
- if (enableLauncherBrMetrics() || ENABLE_LAUNCHER_BR_METRICS.get()) {
+ if (enableLauncherBrMetricsFixed()) {
restoreEventLogger.logItemsRestoreFailed(
favoritesIdToDataType(favoritesId),
count,
@@ -126,7 +125,7 @@
* done restoring items for Launcher.
*/
override fun reportLauncherRestoreResults() {
- if (enableLauncherBrMetrics() || ENABLE_LAUNCHER_BR_METRICS.get()) {
+ if (enableLauncherBrMetricsFixed()) {
BackupManager(context).reportDelayedRestoreResult(restoreEventLogger)
}
}
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/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/tests/src/com/android/launcher3/model/AppEventProducerTest.java b/quickstep/tests/src/com/android/launcher3/model/AppEventProducerTest.java
index d6c1447..d4dd580 100644
--- a/quickstep/tests/src/com/android/launcher3/model/AppEventProducerTest.java
+++ b/quickstep/tests/src/com/android/launcher3/model/AppEventProducerTest.java
@@ -28,7 +28,6 @@
import android.app.prediction.AppTarget;
import android.content.ComponentName;
-import android.content.Context;
import android.content.Intent;
import android.os.Process;
import android.os.UserHandle;
@@ -39,13 +38,12 @@
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.util.ActivityContextWrapper;
+import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
import com.android.launcher3.util.UserIconInfo;
-import com.android.launcher3.util.rule.StaticMockitoRule;
import com.android.systemui.shared.system.SysUiStatsLog;
+import org.junit.After;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -65,22 +63,24 @@
private static final UserIconInfo PRIVATE_ICON_INFO =
new UserIconInfo(PRIVATE_HANDLE, UserIconInfo.TYPE_PRIVATE);
- private Context mContext;
+ private SandboxContext mContext;
private AppEventProducer mAppEventProducer;
@Mock
private UserCache mUserCache;
- @Rule
- public final StaticMockitoRule mStaticMockitoRule = new StaticMockitoRule(UserCache.class);
-
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mContext = new ActivityContextWrapper(getApplicationContext());
- when(UserCache.getInstance(any(Context.class))).thenReturn(mUserCache);
+ mContext = new SandboxContext(getApplicationContext());
+ mContext.putObject(UserCache.INSTANCE, mUserCache);
mAppEventProducer = new AppEventProducer(mContext, null);
}
+ @After
+ public void tearDown() {
+ mContext.onDestroy();
+ }
+
@Test
public void buildAppTarget_containsCorrectUser() {
when(mUserCache.getUserProfiles())
diff --git a/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
index 728fe67..4aa7cb0 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
@@ -17,8 +17,6 @@
import static androidx.test.InstrumentationRegistry.getInstrumentation;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -84,8 +82,7 @@
}
private DigitalWellBeingToast getToast() {
- executeOnLauncher(launcher -> launcher.getStateManager().goToState(OVERVIEW));
- waitForState("Launcher internal state didn't switch to Overview", () -> OVERVIEW);
+ mLauncher.getWorkspace().switchToOverview();
final TaskView task = getOnceNotNull("No latest task", launcher -> getLatestTask(launcher));
return getFromLauncher(launcher -> {
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
index c9e536a..b165876 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
@@ -17,16 +17,23 @@
import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT;
+import android.graphics.Rect;
+
import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
+import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.Closeable;
+import java.io.IOException;
+
@LargeTest
@RunWith(AndroidJUnit4.class)
public class TaplTestsPersistentTaskbar extends AbstractTaplTestsTaskbar {
@@ -39,4 +46,28 @@
// Width check is performed inside TAPL whenever getTaskbar() is called.
getTaskbar();
}
+
+ @Test
+ @NavigationModeSwitch(mode = NavigationModeSwitchRule.Mode.THREE_BUTTON)
+ public void testThreeButtonsTaskbarBoundsAfterConfigChangeDuringIme() {
+ // Start off in light mode.
+ try (Closeable c = InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .executeShellCommand("cmd uimode night no")) {
+ Rect taskbarBoundsBefore = getTaskbar().getVisibleBounds();
+ startImeTestActivity();
+ // IME should stash the taskbar, which hides icons even in 3 button mode.
+ mLauncher.getLaunchedAppState().assertTaskbarHidden();
+ // Switch to dark mode (any configuration change here would do).
+ InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+ "cmd uimode night yes").close();
+ // Close IME to check new taskbar bounds.
+ mLauncher.pressBack();
+ Rect taskbarBoundsAfter = getTaskbar().getVisibleBounds();
+ Assert.assertEquals(
+ "Taskbar bounds are not the same after a configuration change while stashed.",
+ taskbarBoundsBefore, taskbarBoundsAfter);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
diff --git a/res/drawable/ic_install_to_private.xml b/res/drawable/ic_install_to_private.xml
new file mode 100644
index 0000000..7f00f8d
--- /dev/null
+++ b/res/drawable/ic_install_to_private.xml
@@ -0,0 +1,28 @@
+<?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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="960"
+ android:viewportHeight="960"
+ android:tint="?attr/colorControlNormal">
+
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M420,600L540,600L517,471Q537,461 548.5,442Q560,423 560,400Q560,367 536.5,343.5Q513,320 480,320Q447,320 423.5,343.5Q400,367 400,400Q400,423 411.5,442Q423,461 443,471L420,600ZM480,880Q341,845 250.5,720.5Q160,596 160,444L160,200L480,80L800,200L800,444Q800,596 709.5,720.5Q619,845 480,880ZM480,796Q584,763 652,664Q720,565 720,444L720,255L480,165L240,255L240,444Q240,565 308,664Q376,763 480,796ZM480,480Q480,480 480,480Q480,480 480,480L480,480L480,480L480,480L480,480Q480,480 480,480Q480,480 480,480Z"/>
+</vector>
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-af/strings.xml b/res/values-af/strings.xml
index ea6e0fa..44c29ec 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Privaat Ruimte-instellings"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Sluit/ontsluit Privaat Ruimte"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Privaat Ruimte-oorgang"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Oorvloei"</string>
</resources>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 893f4c4..b56c79a 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"የግል ቦታ ቅንብሮች"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"የግል ቦታን ቆልፍ/ክፈት"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"የግል ቦታ ሽግግር"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ትርፍ ፍሰት"</string>
</resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index a2a43db..1394661 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"إعدادات المساحة الخاصة"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"قفل المساحة الخاصة أو فتح قفلها"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"النقل إلى المساحة الخاصة"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"القائمة الكاملة"</string>
</resources>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 93c5e3a..9deda79 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"ব্যক্তিগত স্পে’চৰ ছেটিং"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ব্যক্তিগত স্পে’চ লক/আনলক কৰক"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"ব্যক্তিগত স্পে’চৰ স্থানান্তৰণ"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"অ’ভাৰফ্ল’"</string>
</resources>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 31d485d..971163e 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Şəxsi məkan ayarları"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Şəxsi məkanı kilidləyin/kiliddən çıxarın"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Şəxsi məkana keçid"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Kənara çıxma"</string>
</resources>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index aa08cc4..c13989c 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Podešavanja privatnog prostora"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaključaj/otključaj privatni prostor"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Prenos privatnog prostora"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Preklopno"</string>
</resources>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index ae47fa0..31709c0 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Налады прыватнай вобласці"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заблакіраваць (разблакіраваць) прыватную вобласць"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Пераход у прыватную вобласць"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Дадатковае меню"</string>
</resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 2f196ca..01ee2df 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Настройки за личното пространство"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заключване/отключване на личното пространство"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Преминаване към личното пространство"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Препълване"</string>
</resources>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 8c08794..665a95f 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"ব্যক্তিগত স্পেসের সেটিংস"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ব্যক্তিগত স্পেস লক/আনলক করুন"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"ব্যক্তিগত স্পেস ট্রানজিট করা"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ওভারফ্লো"</string>
</resources>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 9641416..f0ee1b4 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Postavke privatnog prostora"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaključavanje/otključavanje privatnog prostora"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Prelazak u privatan prostor"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Preklopni meni"</string>
</resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 25a8ce6..e1c9a2b 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Configuració d\'Espai privat"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloqueja o desbloqueja Espai privat"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Canvia a Espai privat"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menú addicional"</string>
</resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 4927508..7a5e838 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Nastavení soukromého prostoru"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zamknout/odemknout soukromý prostor"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Převádění soukromého prostoru"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Rozbalovací nabídka"</string>
</resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 415d1f3..9c46dd9 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Indstillinger for privat rum"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lås/oplås det private område"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Ændringer af tilstanden for det private område"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overløb"</string>
</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 04d9682..f27cb90 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Einstellungen für privaten Bereich"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privaten Bereich sperren/entsperren"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Sperrzustand des privaten Bereichs wird gerade geändert"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Weitere Optionen"</string>
</resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index bc8458b..d4740d4 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Ρυθμίσεις Ιδιωτικού χώρου"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Κλείδωμα/Ξεκλείδωμα Ιδιωτικού χώρου"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Μετάβαση στον Ιδιωτικό χώρο"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Υπερχείλιση"</string>
</resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index c002ef9..85ab76b 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space transitioning"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
</resources>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 1ad42f3..bb03769 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space Transitioning"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
</resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index c002ef9..85ab76b 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space transitioning"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
</resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index c002ef9..85ab76b 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space transitioning"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
</resources>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 81bb474..ef85c5c 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space Transitioning"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index d37b1e9..bce0430 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Configuración de Espacio privado"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear o desbloquear Espacio privado"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Pasar a Espacio privado"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Ampliada"</string>
</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 7db8239..6bb325c 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Ajustes del espacio privado"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear/Desbloquear espacio privado"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Cambiar a espacio privado"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Desplegable"</string>
</resources>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 9e4a534..cabd7ab 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Privaatse ruumi seaded"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privaatse ruumi lukustamine/avamine"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Privaatse ruumi üleviimine"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Ületäide"</string>
</resources>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 4123096..ff68d74 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Eremu pribatuaren ezarpenak"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Blokeatu/Desblokeatu eremu pribatua"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Eremu pribaturako trantsizioa"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Luzapena"</string>
</resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 161c7c5..444d550 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"تنظیمات «فضای خصوصی»"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"قفل/ باز کردن «فضای خصوصی»"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"انتقال «فضای خصوصی»"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"سرریز"</string>
</resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 87e3040..d812e99 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Yksityisen tilan asetukset"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lukitse yksityinen tila / avaa sen lukitus"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Yksityisen tilan siirtäminen"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Ylivuoto"</string>
</resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 0e8fe9c..0fc6129 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Paramètres de l\'Espace privé"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Verrouiller/Déverrouiller l\'Espace privé"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Transition vers l\'Espace privé"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menu à développer"</string>
</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 9aa6ad2..fb658f5 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Paramètres d\'Espace privé"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Verrouiller/Déverrouiller Espace privé"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Transition vers Espace privé"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Dépassement"</string>
</resources>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 4eda3cf..4a455f5 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Configuración do espazo privado"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear ou desbloquear o espazo privado"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Transición ao espazo privado"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menú adicional"</string>
</resources>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index deaee86..be0fdba 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"ખાનગી સ્પેસના સેટિંગ"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ખાનગી સ્પેસને લૉક/અનલૉક કરો"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"ખાનગી સ્પેસ પર સ્થાનાંતરણ"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ઓવરફ્લો"</string>
</resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 52bc50a..f7972eb 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"प्राइवेट स्पेस सेटिंग"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"प्राइवेट स्पेस को लॉक करें/अनलॉक करें"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"प्राइवेट स्पेस की सेटिंग में बदलाव किया जा रहा है"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ओवरफ़्लो"</string>
</resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 9694428..9f6ae3a 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Postavke privatnog prostora"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaključavanje/otključavanje privatnog prostora"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Prelazak na privatni prostor"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Dodatni izbornik"</string>
</resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 7c83ec0..8e0fa14 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Privát terület beállításai"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privát terület zárolása/zárolásának feloldása"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Átállás privát területre…"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Túlcsordulás"</string>
</resources>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 7aa432b..c909b54 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Անձնական տարածքի կարգավորումներ"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Կողպել/ապակողպել անձնական տարածքը"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Անցում անձնական տարածք"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Լրացուցիչ ընտրացանկ"</string>
</resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index b7ce5e3..d7bb8dc 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Setelan Ruang Pribadi"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Kunci/Buka Kunci Ruang Pribadi"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Ruang Pribadi Bertransisi"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menu tambahan"</string>
</resources>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 4ba0623..1c9759f 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Stillingar einkarýmis"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Læsaeinkarými/taka einkarými úr lás"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Einkarými að breytast"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Yfirflæði"</string>
</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 644d680..fd7c4bf 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Impostazioni dello Spazio privato"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Blocca/sblocca Spazio privato"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Transizione dello Spazio privato in corso…"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Extra"</string>
</resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index c91e57c..79a6e88 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"הגדרות המרחב הפרטי"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"נעילה או ביטול הנעילה של המרחב הפרטי"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"מעבר למרחב הפרטי"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"אפשרויות נוספות"</string>
</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 00b061f..ac63dab 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"プライベート スペースの設定"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"プライベート スペースをロック / ロック解除する"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"プライベート スペース移行中"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"オーバーフロー"</string>
</resources>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index d428447..eeb33fb 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"პირადი სივრცის პარამეტრები"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"პირადი სივრცის ჩაკეტვა/განბლოკვა"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"პირად სივრცეზე გადასვლა"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"გადავსება"</string>
</resources>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 4f6c6fd..85e7b6c 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Жеке бөлме параметрлері"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Жеке бөлмені құлыптау/оның құлпын ашу"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Жеке бөлмеге өту"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Қосымша мәзір"</string>
</resources>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 91622f0..49c2b35 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"ការកំណត់ Private Space"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ចាក់សោ/ដោះសោ Private Space"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"ការផ្លាស់ប្ដូរ Private Space"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ម៉ឺនុយបន្ថែម"</string>
</resources>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index ad208f2..21e226c 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"ಖಾಸಗಿ ಸ್ಪೇಸ್ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ಖಾಸಗಿ ಸ್ಪೇಸ್ ಅನ್ನು ಲಾಕ್/ಅನ್ಲಾಕ್ ಮಾಡಿ"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"ಖಾಸಗಿ ಸ್ಪೇಸ್ ಪರಿವರ್ತನೆಯಾಗುತ್ತಿದೆ"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ಓವರ್ಫ್ಲೋ"</string>
</resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index b2b0c0c..643a513 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"비공개 스페이스 설정"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"비공개 스페이스 잠금/잠금 해제"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"비공개 스페이스 전환"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"오버플로"</string>
</resources>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 78e96a6..2274389 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Жеке чөйрөнүн параметрлери"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Жеке чөйрөнү кулпулоо/кулпусун ачуу"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Жеке чөйрөгө өтүү"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Кошумча меню"</string>
</resources>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index bb99150..175e8f5 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"ການຕັ້ງຄ່າພື້ນທີ່ສ່ວນຕົວ"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ລັອກ/ປົດລັອກພື້ນທີ່ສ່ວນຕົວ"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"ການປ່ຽນແປງພື້ນທີ່ສ່ວນຕົວ"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ການດຳເນີນການເພີ່ມເຕີມ"</string>
</resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 075bbb2..ef56c1a 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Privačios erdvės nustatymai"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Užrakinti ir (arba) atrakinti privačią erdvę"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Privačios erdvės perkėlimas"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Perpildymas"</string>
</resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 5edee25..f2e8a87 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Privātās mapes iestatījumi"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloķēt/atbloķēt privāto mapi"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Pāriet uz privāto mapi"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Pārpilde"</string>
</resources>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index a95b7bf..cfbd3ba 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Поставки за „Приватен простор“"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заклучување/отклучување на „Приватен простор“"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Префрлање на „Приватен простор“"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Проширено балонче"</string>
</resources>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 1cdcb09..2ae3c2f 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"സ്വകാര്യ സ്പേസ് ക്രമീകരണം"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"സ്വകാര്യ സ്പേസ് ലോക്ക് ചെയ്യുക/അൺലോക്ക് ചെയ്യുക"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"പ്രൈവറ്റ് സ്പേസ് ട്രാൻസിഷനിംഗ്"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ഓവർഫ്ലോ"</string>
</resources>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 2d53dea..31dda29 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Private Space-н тохиргоо"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Private Space-г түгжих/түгжээг тайлах"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space-н шилжилт"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Урт цэс"</string>
</resources>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 9e44733..635a422 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"खाजगी स्पेस ची सेटिंग्ज"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"खाजगी स्पेस लॉक/अनलॉक करा"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"खाजगी स्पेस वर स्विच करणे"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ओव्हरफ्लो"</string>
</resources>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index c90082a..566ea85 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Tetapan Ruang Peribadi"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Kunci/Buka kunci Ruang Peribadi"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Peralihan Ruang Peribadi"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Limpahan"</string>
</resources>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index d1bef97..ced9f61 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"သီးသန့်ချတ်ခန်း ဆက်တင်များ"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"သီးသန့်ချတ်ခန်း လော့ခ်ချ/ဖွင့်ရန်"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"သီးသန့်ချတ်ခန်း အပြောင်းအလဲ"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"မီနူးအပို"</string>
</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index cd2fb1f..cb0fd95 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Innstillinger for Private Space"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lås / lås opp Private Space"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space-overgang"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflyt"</string>
</resources>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index b9397a0..d8df060 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"निजी स्पेससम्बन्धी सेटिङ"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"निजी स्पेस लक/अनलक गर्नुहोस्"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"निजी स्पेस ट्रान्जिसन गरिँदै छ"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ओभरफ्लो"</string>
</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 84d5c15..86a5f40 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Instellingen voor privéruimte"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privéruimte vergrendelen/ontgrendelen"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Overschakelen naar privéruimte"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overloop"</string>
</resources>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 3fa8754..c726e50 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"ପ୍ରାଇଭେଟ ସ୍ପେସ ସେଟିଂସ"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ପ୍ରାଇଭେଟ ସ୍ପେସକୁ ଲକ/ଅନଲକ କରନ୍ତୁ"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"ପ୍ରାଇଭେଟ ସ୍ପେସ ଟ୍ରାଞ୍ଜିସନିଂ"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ଓଭରଫ୍ଲୋ"</string>
</resources>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 98bc36d..46e750a 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"ਨਿੱਜੀ ਸਪੇਸ ਸੰਬੰਧੀ ਸੈਟਿੰਗਾਂ"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ਨਿੱਜੀ ਸਪੇਸ ਨੂੰ ਲਾਕ/ਅਣਲਾਕ ਕਰੋ"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"ਨਿੱਜੀ ਸਪੇਸ ਨੂੰ ਤਬਦੀਲ ਕਰਨਾ"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ਓਵਰਫ਼ਲੋ"</string>
</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 30a953c..4b6a612 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Ustawienia obszaru prywatnego"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zablokuj/odblokuj obszar prywatny"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Przenoszenie obszaru prywatnego"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Rozwiń menu"</string>
</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index af760f8..4803138 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Definições do espaço privado"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear/desbloquear espaço privado"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Transição do espaço privado"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menu adicional"</string>
</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 4359e9a..40af95d 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Configurações do Espaço particular"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear/desbloquear o Espaço particular"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Espaço particular em transição"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Balão flutuante"</string>
</resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 836ac99..2d66f9b 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Setări spațiu privat"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Blochează / deblochează spațiul privat"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Tranziție pentru spațiul privat"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Suplimentar"</string>
</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index bb7b0a0..063126d 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Настройки личного пространства"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Блокировка и разблокировка личного пространства"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Переход к личному пространству"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Дополнительное меню"</string>
</resources>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 401e0fb..e5660ce 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"පෞද්ගලික අවකාශ සැකසීම්"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"පෞද්ගලික අවකාශය අගුළු දමන්න/අගුළු හරින්න"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"පෞද්ගලික අවකාශ සංක්රමණය"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"පිටාර යාම"</string>
</resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index fbe64a8..89c64bf 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Nastavenia súkromného priestoru"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Súkromný priestor zamykania a odomykania"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Prechod súkromného priestoru"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Rozšírená ponuka"</string>
</resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index d91e83f..5f18f26 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Nastavitve zasebnega prostora"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaklepanje/odklepanje zasebnega prostora"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Preklapljanje zasebnega prostora"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Oblaček z dodatnimi elementi"</string>
</resources>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index a3bd673..c06fc7e 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Cilësimet e \"Hapësirës private\""</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Kyç/Shkyç \"Hapësirën private\""</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Kalimi te \"Hapësira private\""</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Tejkalimi"</string>
</resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 5242848..eb3bc64 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Подешавања приватног простора"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Закључај/откључај приватни простор"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Пренос приватног простора"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Преклопно"</string>
</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 1e1436f..6824cc1 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Inställningar för privat rum"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lås eller lås upp ditt privata rum"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Överföring av privat rum"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Fler alternativ"</string>
</resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 2486cae..788a06a 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Mipangilio ya Nafasi ya Faragha"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Funga/Fungua Nafasi ya Faragha"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Mabadiliko ya Nafasi ya Faragha"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menyu ya vipengee vya ziada"</string>
</resources>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index cb0ca67..6c89de9 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"தனிப்பட்ட சேமிப்பிட அமைப்புகள்"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"தனிப்பட்ட சேமிப்பிடத்தை லாக்/அன்லாக் செய்யும்"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"தனிப்பட்ட சேமிப்பிடத்திற்கு மாற்றுகிறது"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"கூடுதல் விருப்பங்களைக் காட்டும்"</string>
</resources>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 27cec72..e58039f 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"ప్రైవేట్ స్పేస్ సెట్టింగ్లు"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ప్రైవేట్ స్పేస్ను లాక్/అన్లాక్ చేయండి"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"ప్రైవేట్ స్పేస్ కేటాయించడం జరుగుతుంది"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ఓవర్ఫ్లో"</string>
</resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 78cbcfa..0eff887 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"การตั้งค่าพื้นที่ส่วนตัว"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ล็อก/ปลดล็อกพื้นที่ส่วนตัว"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"การเปลี่ยนไปใช้พื้นที่ส่วนตัว"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"การดำเนินการเพิ่มเติม"</string>
</resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index acf60ff..3db2aba 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Mga Setting ng Pribadong Space"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"I-lock/I-unlock ang Pribadong Space"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Pag-transition ng Pribadong Space"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
</resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 1449202..78fc596 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Gizli Alan Ayarları"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Gizli Alanı Kilitleyin/Kilidini Açın"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Gizli Alana Geçiş"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Taşma"</string>
</resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index ad325cc..b69558f 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Налаштування приватного простору"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заблокувати/розблокувати приватний простір"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Перехід у приватний простір"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Додаткове меню"</string>
</resources>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 1c0e3ae..549f2a1 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"نجی اسپیس کی ترتیبات"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"نجی اسپیس کو مقفل کریں/غیر مقفل کریں"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"نجی اسپیس کی منتقلی"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"اوورفلو"</string>
</resources>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 8e6d392..7cacd96 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Shaxsiy xona sozlamalari"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Shaxsiy xonani ochish/qulflash"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Maxfiy joyga almashtirish"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Kengaytirish"</string>
</resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 8ed3089..7f4487c 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Cài đặt không gian riêng tư"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Khoá/mở khoá không gian riêng tư"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Chuyển đổi sang không gian riêng tư"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Bong bóng bổ sung"</string>
</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 53b85f2..cfae584 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"私密空间设置"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"锁定/解锁私密空间"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"私密空间转换"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"菜单"</string>
</resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index e6aaef5..e94a808 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"「私人空間」設定"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"鎖定/解鎖「私人空間」"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"轉為「私人空間」"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"顯示更多"</string>
</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 462b651..957bf45 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"私人空間設定"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"鎖定/取消鎖定私人空間"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"轉換私人空間狀態"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"溢位"</string>
</resources>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index efc0824..3051d09 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -178,5 +178,9 @@
<string name="ps_container_settings" msgid="6059734123353320479">"Amasethingi Esikhala Esiyimfihlo"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Khiya/Vula Isikhala Esiyimfihlo"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Ukuguqulwa Kwendawo Yangasese"</string>
+ <!-- no translation found for ps_add_button_label (8611055839242385935) -->
+ <skip />
+ <!-- no translation found for ps_add_button_content_description (3254274107740952556) -->
+ <skip />
<string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Ukugcwala kakhulu"</string>
</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 77af671..e54539f 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -223,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/strings.xml b/res/values/strings.xml
index 6a4a9a4..34677f6 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -171,6 +171,8 @@
<string name="uninstall_drop_target_label">Uninstall</string>
<!-- Label for app info drop target. [CHAR_LIMIT=20] -->
<string name="app_info_drop_target_label">App info</string>
+ <!-- Label for install to private profile shortcut label. [CHAR_LIMIT=20] -->
+ <string name="install_private_system_shortcut_label">Install in private</string>
<!-- Label for install drop target. [CHAR_LIMIT=20] -->
<string name="install_drop_target_label">Install</string>
<!-- Label for install dismiss prediction. -->
@@ -461,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/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 78c12e5..42d4d50 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -948,34 +948,34 @@
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);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 5c49b89..b5dd10e 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];
@@ -515,8 +515,10 @@
mStateManager = new StateManager<>(this, NORMAL);
setupViews();
+ updateDisallowBack();
mAppWidgetManager = new WidgetManagerHelper(this);
+ mWidgetInflater = new WidgetInflater(this);
mAppWidgetHolder = createAppWidgetHolder();
mAppWidgetHolder.startListening();
mAppWidgetHolder.addProviderChangeListener(() -> refreshAndBindWidgetsForPackageUser(null));
@@ -2309,157 +2311,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, null, 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(item.appWidgetId, appWidgetInfo);
- } else {
- view = new PendingAppWidgetHostView(this, item, appWidgetInfo, 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..e015021 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -44,6 +44,7 @@
import com.android.launcher3.icons.IconProvider;
import com.android.launcher3.icons.LauncherIconProvider;
import com.android.launcher3.icons.LauncherIcons;
+import com.android.launcher3.model.ModelLauncherCallbacks;
import com.android.launcher3.notification.NotificationListener;
import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.pm.InstallSessionTracker;
@@ -56,6 +57,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 +73,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,15 +94,18 @@
Log.v(Launcher.TAG, "LauncherAppState initiated");
Preconditions.assertUIThread();
+ mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
+ () -> context.getPackageManager().isSafeMode());
mInvariantDeviceProfile.addOnChangeListener(modelPropertiesChanged -> {
if (modelPropertiesChanged) {
refreshAndReloadLauncher();
}
});
- mContext.getSystemService(LauncherApps.class).registerCallback(mModel);
+ ModelLauncherCallbacks callbacks = mModel.newModelCallbacks();
+ mContext.getSystemService(LauncherApps.class).registerCallback(callbacks);
mOnTerminateCallback.add(() ->
- mContext.getSystemService(LauncherApps.class).unregisterCallback(mModel));
+ mContext.getSystemService(LauncherApps.class).unregisterCallback(callbacks));
SimpleBroadcastReceiver modelChangeReceiver =
new SimpleBroadcastReceiver(mModel::onBroadcastIntent);
@@ -224,6 +231,10 @@
return mInvariantDeviceProfile;
}
+ public boolean isSafeModeEnabled() {
+ return mIsSafeModeEnabled;
+ }
+
/**
* Shorthand for {@link #getInvariantDeviceProfile()}
*/
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index c81db63..d124746 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.LauncherAppState.ACTION_FORCE_ROLOAD;
import static com.android.launcher3.config.FeatureFlags.IS_STUDIO_BUILD;
+import static com.android.launcher3.model.PackageUpdatedTask.OP_UPDATE;
import static com.android.launcher3.pm.UserCache.ACTION_PROFILE_AVAILABLE;
import static com.android.launcher3.pm.UserCache.ACTION_PROFILE_UNAVAILABLE;
import static com.android.launcher3.testing.shared.TestProtocol.sDebugTracing;
@@ -28,7 +29,6 @@
import android.content.Context;
import android.content.Intent;
-import android.content.pm.LauncherApps;
import android.content.pm.PackageInstaller;
import android.content.pm.ShortcutInfo;
import android.os.UserHandle;
@@ -43,7 +43,6 @@
import com.android.launcher3.celllayout.CellPosMapper;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.AddWorkspaceItemsTask;
import com.android.launcher3.model.AllAppsList;
import com.android.launcher3.model.BaseModelUpdateTask;
@@ -55,8 +54,8 @@
import com.android.launcher3.model.LoaderTask;
import com.android.launcher3.model.ModelDbController;
import com.android.launcher3.model.ModelDelegate;
+import com.android.launcher3.model.ModelLauncherCallbacks;
import com.android.launcher3.model.ModelWriter;
-import com.android.launcher3.model.PackageIncrementalDownloadUpdatedTask;
import com.android.launcher3.model.PackageInstallStateChangedTask;
import com.android.launcher3.model.PackageUpdatedTask;
import com.android.launcher3.model.ReloadStringCacheTask;
@@ -89,7 +88,7 @@
* LauncherModel object held in a static. Also provide APIs for updating the database state
* for the Launcher.
*/
-public class LauncherModel extends LauncherApps.Callback implements InstallSessionTracker.Callback {
+public class LauncherModel implements InstallSessionTracker.Callback {
private static final boolean DEBUG_RECEIVER = false;
static final String TAG = "Launcher.Model";
@@ -168,6 +167,10 @@
return mModelDbController;
}
+ public ModelLauncherCallbacks newModelCallbacks() {
+ return new ModelLauncherCallbacks(this::enqueueModelUpdateTask);
+ }
+
/**
* Adds the provided items to the workspace.
*/
@@ -186,77 +189,6 @@
owner);
}
- @Override
- public void onPackageChanged(
- @NonNull final String packageName, @NonNull final UserHandle user) {
- int op = PackageUpdatedTask.OP_UPDATE;
- enqueueModelUpdateTask(new PackageUpdatedTask(op, user, packageName));
- }
-
- @Override
- public void onPackageRemoved(
- @NonNull final String packageName, @NonNull final UserHandle user) {
- onPackagesRemoved(user, packageName);
- }
-
- public void onPackagesRemoved(
- @NonNull final UserHandle user, @NonNull final String... packages) {
- int op = PackageUpdatedTask.OP_REMOVE;
- FileLog.d(TAG, "package removed received " + TextUtils.join(",", packages));
- enqueueModelUpdateTask(new PackageUpdatedTask(op, user, packages));
- }
-
- @Override
- public void onPackageAdded(@NonNull final String packageName, @NonNull final UserHandle user) {
- int op = PackageUpdatedTask.OP_ADD;
- enqueueModelUpdateTask(new PackageUpdatedTask(op, user, packageName));
- }
-
- @Override
- public void onPackagesAvailable(@NonNull final String[] packageNames,
- @NonNull final UserHandle user, final boolean replacing) {
- enqueueModelUpdateTask(
- new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE, user, packageNames));
- }
-
- @Override
- public void onPackagesUnavailable(@NonNull final String[] packageNames,
- @NonNull final UserHandle user, final boolean replacing) {
- if (!replacing) {
- enqueueModelUpdateTask(new PackageUpdatedTask(
- PackageUpdatedTask.OP_UNAVAILABLE, user, packageNames));
- }
- }
-
- @Override
- public void onPackagesSuspended(
- @NonNull final String[] packageNames, @NonNull final UserHandle user) {
- enqueueModelUpdateTask(new PackageUpdatedTask(
- PackageUpdatedTask.OP_SUSPEND, user, packageNames));
- }
-
- @Override
- public void onPackagesUnsuspended(
- @NonNull final String[] packageNames, @NonNull final UserHandle user) {
- enqueueModelUpdateTask(new PackageUpdatedTask(
- PackageUpdatedTask.OP_UNSUSPEND, user, packageNames));
- }
-
- @Override
- public void onPackageLoadingProgressChanged(@NonNull final String packageName,
- @NonNull final UserHandle user, final float progress) {
- if (Utilities.ATLEAST_S) {
- enqueueModelUpdateTask(new PackageIncrementalDownloadUpdatedTask(
- packageName, user, progress));
- }
- }
-
- @Override
- public void onShortcutsChanged(@NonNull final String packageName,
- @NonNull final List<ShortcutInfo> shortcuts, @NonNull final UserHandle user) {
- enqueueModelUpdateTask(new ShortcutsChangedTask(packageName, shortcuts, user, true));
- }
-
/**
* Called when the icon for an app changes, outside of package event
*/
@@ -265,7 +197,7 @@
@NonNull final UserHandle user) {
// Update the icon for the calendar package
Context context = mApp.getContext();
- onPackageChanged(packageName, user);
+ enqueueModelUpdateTask(new PackageUpdatedTask(OP_UPDATE, user, packageName));
List<ShortcutInfo> pinnedShortcuts = new ShortcutRequest(context, user)
.forPackage(packageName).query(ShortcutRequest.PINNED);
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/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 4ad4c71..ad764e3 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -1315,6 +1315,10 @@
: mViewPager == null ? AdapterHolder.MAIN : mViewPager.getNextPage();
}
+ public PrivateProfileManager getPrivateProfileManager() {
+ return mPrivateProfileManager;
+ }
+
/**
* Adds an update listener to animator that adds springs to the animation.
*/
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 3e55f61..35c07c3 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -322,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()
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/UserProfileManager.java b/src/com/android/launcher3/allapps/UserProfileManager.java
index 0261010..6bef725 100644
--- a/src/com/android/launcher3/allapps/UserProfileManager.java
+++ b/src/com/android/launcher3/allapps/UserProfileManager.java
@@ -94,6 +94,19 @@
return mCurrentState;
}
+ /** Returns if user profile is enabled. */
+ public boolean isEnabled() {
+ return mCurrentState == STATE_ENABLED;
+ }
+
+ /** Returns the UserHandle corresponding to the profile type, null in case no matches found. */
+ public UserHandle getProfileUser() {
+ return mUserCache.getUserProfiles().stream()
+ .filter(getUserMatcher())
+ .findAny()
+ .orElse(null);
+ }
+
/** Logs Event to StatsLogManager. */
protected void logEvents(StatsLogManager.EventEnum event) {
mStatsLogManager.logger().log(event);
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 61e853e..3ccd3e1 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -167,8 +167,6 @@
"Enable the ability to generate monochromatic icons, if it is not provided by the app");
// TODO(Block 8): Clean up flags
- public static final BooleanFlag ENABLE_LAUNCHER_BR_METRICS = getDebugFlag(305984208,
- "ENABLE_LAUNCHER_BR_METRICS", TEAMFOOD, "Enable metrics for Launcher restore");
// TODO(Block 9): Clean up flags
public static final BooleanFlag MULTI_SELECT_EDIT_MODE = getDebugFlag(270709220,
@@ -225,7 +223,7 @@
// Task bar pinning and task bar nav bar unification are both dependent on
// ENABLE_TASKBAR_NO_RECREATION. We want to turn ENABLE_TASKBAR_NO_RECREATION on
// when either of the dependent features is turned on.
- || ENABLE_TASKBAR_PINNING.get() || ENABLE_TASKBAR_NAVBAR_UNIFICATION;
+ || enableTaskbarPinning() || ENABLE_TASKBAR_NAVBAR_UNIFICATION;
}
// TODO(Block 16): Clean up flags
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 6651fa0..0dc0d02 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -701,6 +701,9 @@
@UiEvent(doc = "User tapped private space settings button")
LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP(1550),
+ @UiEvent(doc = "User tapped on install to private space system shortcut.")
+ LAUNCHER_PRIVATE_SPACE_INSTALL_SYSTEM_SHORTCUT_TAP(1565),
+
// ADD MORE
;
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 7b9f6fa..795450a 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -17,18 +17,11 @@
package com.android.launcher3.model;
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.Flags.enableLauncherBrMetricsFixed;
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;
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
-import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_APP_NOT_INSTALLED;
-import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_INVALID_LOCATION;
-import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_MISSING_INFO;
-import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_PROFILE_DELETED;
-import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_SHORTCUT_NOT_FOUND;
-import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_WIDGETS_DISABLED;
import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
import static com.android.launcher3.config.FeatureFlags.SMARTSPACE_AS_A_WIDGET;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
@@ -37,16 +30,10 @@
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_WORK_PROFILE_QUIET_MODE_ENABLED;
import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
-import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
-import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE;
-import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermission;
-import static com.android.launcher3.util.PackageManagerHelper.isSystemApp;
-import android.annotation.SuppressLint;
import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -56,12 +43,10 @@
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
-import android.graphics.Point;
import android.os.Bundle;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
-import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.LongSparseArray;
@@ -69,10 +54,9 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
-import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Flags;
-import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherPrefs;
@@ -95,13 +79,11 @@
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.IconRequestInfo;
import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.qsb.QsbContainerView;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.shortcuts.ShortcutRequest.QueryResult;
@@ -113,9 +95,7 @@
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.TraceHelper;
-import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.WidgetManagerHelper;
-import com.android.launcher3.widget.custom.CustomWidgetManager;
import java.util.ArrayList;
import java.util.Collections;
@@ -123,6 +103,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CancellationException;
@@ -185,7 +166,7 @@
mLauncherBinder = launcherBinder;
mLauncherApps = mApp.getContext().getSystemService(LauncherApps.class);
mUserManager = mApp.getContext().getSystemService(UserManager.class);
- mUserCache = UserCache.getInstance(mApp.getContext());
+ mUserCache = UserCache.INSTANCE.get(mApp.getContext());
mSessionHelper = InstallSessionHelper.INSTANCE.get(mApp.getContext());
mIconCache = mApp.getIconCache();
mUserManagerState = userManagerState;
@@ -234,7 +215,7 @@
mIsRestoreFromBackup =
(Boolean) LauncherPrefs.get(mApp.getContext()).get(IS_FIRST_LOAD_AFTER_RESTORE);
LauncherRestoreEventLogger restoreEventLogger = null;
- if (enableLauncherBrMetrics()) {
+ if (enableLauncherBrMetricsFixed()) {
restoreEventLogger = LauncherRestoreEventLogger.Companion
.newInstance(mApp.getContext());
}
@@ -247,7 +228,7 @@
// sanitizeData should not be invoked if the workspace is loaded from a db different
// from the main db as defined in the invariant device profile.
// (e.g. both grid preview and minimal device mode uses a different db)
- if (mApp.getInvariantDeviceProfile().dbFile.equals(mDbName)) {
+ if (Objects.equals(mApp.getInvariantDeviceProfile().dbFile, mDbName)) {
verifyNotStopped();
sanitizeFolders(mItemsDeleted);
sanitizeWidgetsShortcutsAndPackages();
@@ -452,43 +433,19 @@
mDbName = extras == null ? null : extras.getString(ModelDbController.EXTRA_DB_NAME);
try {
final LongSparseArray<Boolean> unlockedUsers = new LongSparseArray<>();
-
- mUserManagerState.init(mUserCache, mUserManager);
-
- for (UserHandle user : mUserCache.getUserProfiles()) {
- long serialNo = mUserCache.getSerialNumberForUser(user);
- boolean userUnlocked = mUserManager.isUserUnlocked(user);
-
- // We can only query for shortcuts when the user is unlocked.
- if (userUnlocked) {
- QueryResult pinnedShortcuts = new ShortcutRequest(context, user)
- .query(ShortcutRequest.PINNED);
- if (pinnedShortcuts.wasSuccess()) {
- for (ShortcutInfo shortcut : pinnedShortcuts) {
- mShortcutKeyToPinnedShortcuts.put(ShortcutKey.fromInfo(shortcut),
- shortcut);
- }
- if (pinnedShortcuts.isEmpty()) {
- FileLog.d(TAG, "No pinned shortcuts found for user " + user);
- }
- } else {
- // Shortcut manager can fail due to some race condition when the
- // lock state changes too frequently. For the purpose of the loading
- // shortcuts, consider the user is still locked.
- FileLog.d(TAG, "Shortcut request failed for user "
- + user + ", user may still be locked.");
- userUnlocked = false;
- }
- }
- unlockedUsers.put(serialNo, userUnlocked);
- }
+ queryPinnedShortcutsForUnlockedUsers(context, unlockedUsers);
List<IconRequestInfo<WorkspaceItemInfo>> iconRequestInfos = new ArrayList<>();
+ WorkspaceItemProcessor itemProcessor = new WorkspaceItemProcessor(c, memoryLogger,
+ restoreEventLogger, mUserManagerState, mLauncherApps, mPendingPackages,
+ mShortcutKeyToPinnedShortcuts, mApp, mIconCache, mBgDataModel,
+ mWidgetProvidersMap, mIsRestoreFromBackup, installingPkgs, isSdCardReady,
+ tempPackageKey, widgetHelper, pmHelper, iconRequestInfos, unlockedUsers,
+ isSafeMode, allDeepShortcuts);
+
while (!mStopped && c.moveToNext()) {
- processWorkspaceItem(c, memoryLogger, restoreEventLogger, installingPkgs,
- isSdCardReady, tempPackageKey, widgetHelper, pmHelper,
- iconRequestInfos, unlockedUsers, isSafeMode, allDeepShortcuts);
+ itemProcessor.processItem();
}
tryLoadWorkspaceIconsInBulk(iconRequestInfos);
} finally {
@@ -513,502 +470,85 @@
// Remove dead items
mItemsDeleted = c.commitDeleted();
- // Sort the folder items, update ranks, and make sure all preview items are high res.
- List<FolderGridOrganizer> verifiers =
- mApp.getInvariantDeviceProfile().supportedProfiles.stream().map(
- FolderGridOrganizer::new).toList();
- for (FolderInfo folder : mBgDataModel.folders) {
- Collections.sort(folder.contents, Folder.ITEM_POS_COMPARATOR);
- verifiers.forEach(verifier -> verifier.setFolderInfo(folder));
- int size = folder.contents.size();
-
- // Update ranks here to ensure there are no gaps caused by removed folder items.
- // Ranks are the source of truth for folder items, so cellX and cellY can be
- // ignored for now. Database will be updated once user manually modifies folder.
- for (int rank = 0; rank < size; ++rank) {
- WorkspaceItemInfo info = folder.contents.get(rank);
- // rank is used differently in app pairs, so don't reset
- if (folder.itemType != ITEM_TYPE_APP_PAIR) {
- info.rank = rank;
- }
-
- if (info.usingLowResIcon() && info.itemType == Favorites.ITEM_TYPE_APPLICATION
- && verifiers.stream().anyMatch(
- verifier -> verifier.isItemInPreview(info.rank))) {
- mIconCache.getTitleAndIcon(info, false);
- }
- }
- }
+ processFolderItems();
c.commitRestoredItems();
}
}
- private void processWorkspaceItem(LoaderCursor c,
- LoaderMemoryLogger memoryLogger,
- @Nullable LauncherRestoreEventLogger restoreEventLogger,
- HashMap<PackageUserKey, SessionInfo> installingPkgs,
- boolean isSdCardReady,
- PackageUserKey tempPackageKey,
- WidgetManagerHelper widgetHelper,
- PackageManagerHelper pmHelper,
- List<IconRequestInfo<WorkspaceItemInfo>> iconRequestInfos,
- LongSparseArray<Boolean> unlockedUsers,
- boolean isSafeMode,
- List<ShortcutInfo> allDeepShortcuts) {
+ /**
+ * Initialized the UserManagerState, and determines which users are unlocked. Additionally, if
+ * the user is unlocked, it queries LauncherAppsService for pinned shortcuts and stores the
+ * result in a class variable to be used in other methods while processing workspace items.
+ *
+ * @param context used to query LauncherAppsService
+ * @param unlockedUsers this param is changed, and the updated value is used outside this method
+ */
+ @WorkerThread
+ private void queryPinnedShortcutsForUnlockedUsers(Context context,
+ LongSparseArray<Boolean> unlockedUsers) {
+ mUserManagerState.init(mUserCache, mUserManager);
- try {
- if (c.user == null) {
- // User has been deleted, remove the item.
- c.markDeleted("User of this item has been deleted");
- if (mIsRestoreFromBackup && restoreEventLogger != null) {
- restoreEventLogger.logSingleFavoritesItemRestoreFailed(
- c.itemType, RESTORE_ERROR_PROFILE_DELETED);
+ for (UserHandle user : mUserCache.getUserProfiles()) {
+ long serialNo = mUserCache.getSerialNumberForUser(user);
+ boolean userUnlocked = mUserManager.isUserUnlocked(user);
+
+ // We can only query for shortcuts when the user is unlocked.
+ if (userUnlocked) {
+ QueryResult pinnedShortcuts = new ShortcutRequest(context, user)
+ .query(ShortcutRequest.PINNED);
+ if (pinnedShortcuts.wasSuccess()) {
+ for (ShortcutInfo shortcut : pinnedShortcuts) {
+ mShortcutKeyToPinnedShortcuts.put(ShortcutKey.fromInfo(shortcut),
+ shortcut);
+ }
+ if (pinnedShortcuts.isEmpty()) {
+ FileLog.d(TAG, "No pinned shortcuts found for user " + user);
+ }
+ } else {
+ // Shortcut manager can fail due to some race condition when the
+ // lock state changes too frequently. For the purpose of the loading
+ // shortcuts, consider the user is still locked.
+ FileLog.d(TAG, "Shortcut request failed for user "
+ + user + ", user may still be locked.");
+ userUnlocked = false;
}
- return;
}
+ unlockedUsers.put(serialNo, userUnlocked);
+ }
- boolean allowMissingTarget = false;
- switch (c.itemType) {
- case Favorites.ITEM_TYPE_APPLICATION:
- case Favorites.ITEM_TYPE_DEEP_SHORTCUT:
- Intent intent = c.parseIntent();
- if (intent == null) {
- c.markDeleted("Invalid or null intent");
- if (mIsRestoreFromBackup && restoreEventLogger != null) {
- restoreEventLogger.logSingleFavoritesItemRestoreFailed(
- c.itemType, RESTORE_ERROR_MISSING_INFO);
- }
- return;
- }
+ }
- int disabledState = mUserManagerState.isUserQuiet(c.serialNumber)
- ? WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER : 0;
- ComponentName cn = intent.getComponent();
- String targetPkg = cn == null ? intent.getPackage() : cn.getPackageName();
+ /**
+ * After all items have been processed and added to the BgDataModel, this method can correctly
+ * rank items inside folders and load the correct miniature preview icons to be shown when the
+ * folder is collapsed.
+ */
+ @WorkerThread
+ private void processFolderItems() {
+ // Sort the folder items, update ranks, and make sure all preview items are high res.
+ List<FolderGridOrganizer> verifiers = mApp.getInvariantDeviceProfile().supportedProfiles
+ .stream().map(FolderGridOrganizer::new).toList();
+ for (FolderInfo folder : mBgDataModel.folders) {
+ Collections.sort(folder.contents, Folder.ITEM_POS_COMPARATOR);
+ verifiers.forEach(verifier -> verifier.setFolderInfo(folder));
+ int size = folder.contents.size();
- if (TextUtils.isEmpty(targetPkg)) {
- c.markDeleted("Shortcuts can't have null package");
- if (mIsRestoreFromBackup && restoreEventLogger != null) {
- restoreEventLogger.logSingleFavoritesItemRestoreFailed(
- c.itemType, RESTORE_ERROR_MISSING_INFO);
- }
- return;
- }
+ // Update ranks here to ensure there are no gaps caused by removed folder items.
+ // Ranks are the source of truth for folder items, so cellX and cellY can be
+ // ignored for now. Database will be updated once user manually modifies folder.
+ for (int rank = 0; rank < size; ++rank) {
+ WorkspaceItemInfo info = folder.contents.get(rank);
+ // rank is used differently in app pairs, so don't reset
+ if (folder.itemType != ITEM_TYPE_APP_PAIR) {
+ info.rank = rank;
+ }
- // If there is no target package, it's an implicit intent
- // (legacy shortcut) which is always valid
- boolean validTarget = TextUtils.isEmpty(targetPkg)
- || mLauncherApps.isPackageEnabled(targetPkg, c.user);
-
- // If it's a deep shortcut, we'll use pinned shortcuts to restore it
- if (cn != null && validTarget && c.itemType
- != Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
- // If the apk is present and the shortcut points to a specific component.
-
- // If the component is already present
- if (mLauncherApps.isActivityEnabled(cn, c.user)) {
- // no special handling necessary for this item
- c.markRestored();
- if (mIsRestoreFromBackup && restoreEventLogger != null) {
- restoreEventLogger.logSingleFavoritesItemRestored(c.itemType);
- }
- } else {
- // Gracefully try to find a fallback activity.
- intent = pmHelper.getAppLaunchIntent(targetPkg, c.user);
- if (intent != null) {
- c.restoreFlag = 0;
- c.updater().put(
- Favorites.INTENT,
- intent.toUri(0)).commit();
- cn = intent.getComponent();
- } else {
- c.markDeleted("Intent null, unable to find a launch target");
- if (mIsRestoreFromBackup && restoreEventLogger != null) {
- restoreEventLogger.logSingleFavoritesItemRestoreFailed(
- c.itemType, RESTORE_ERROR_MISSING_INFO);
- }
- return;
- }
- }
- }
- // else if cn == null => can't infer much, leave it
- // else if !validPkg => could be restored icon or missing sd-card
-
- if (!TextUtils.isEmpty(targetPkg) && !validTarget) {
- // Points to a valid app (superset of cn != null) but the apk
- // is not available.
-
- if (c.restoreFlag != 0) {
- // Package is not yet available but might be
- // installed later.
- FileLog.d(TAG, "package not yet restored: " + targetPkg);
- tempPackageKey.update(targetPkg, c.user);
- if (c.hasRestoreFlag(WorkspaceItemInfo.FLAG_RESTORE_STARTED)) {
- // Restore has started once.
- } else if (installingPkgs.containsKey(tempPackageKey)) {
- // App restore has started. Update the flag
- c.restoreFlag |= WorkspaceItemInfo.FLAG_RESTORE_STARTED;
- FileLog.d(TAG, "restore started for installing app: " + targetPkg);
- c.updater().put(Favorites.RESTORED, c.restoreFlag).commit();
- } else {
- c.markDeleted("removing app that is not restored and not "
- + "installing. package: " + targetPkg);
- if (mIsRestoreFromBackup && restoreEventLogger != null) {
- restoreEventLogger.logSingleFavoritesItemRestoreFailed(
- c.itemType, RESTORE_ERROR_APP_NOT_INSTALLED);
- }
- return;
- }
- } else if (pmHelper.isAppOnSdcard(targetPkg, c.user)) {
- // Package is present but not available.
- disabledState |= WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE;
- // Add the icon on the workspace anyway.
- allowMissingTarget = true;
- } else if (!isSdCardReady) {
- // SdCard is not ready yet. Package might get available,
- // once it is ready.
- Log.d(TAG, "Missing package, will check later: " + targetPkg);
- mPendingPackages.add(new PackageUserKey(targetPkg, c.user));
- // Add the icon on the workspace anyway.
- allowMissingTarget = true;
- } else {
- // Do not wait for external media load anymore.
- c.markDeleted("Invalid package removed: " + targetPkg);
- if (mIsRestoreFromBackup && restoreEventLogger != null) {
- restoreEventLogger.logSingleFavoritesItemRestoreFailed(
- c.itemType, RESTORE_ERROR_APP_NOT_INSTALLED);
- }
- return;
- }
- }
-
- if ((c.restoreFlag & WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI) != 0) {
- validTarget = false;
- }
-
- if (validTarget) {
- // The shortcut points to a valid target (either no target
- // or something which is ready to be used)
- c.markRestored();
- }
-
- boolean useLowResIcon = !c.isOnWorkspaceOrHotseat();
-
- WorkspaceItemInfo info;
- if (c.restoreFlag != 0) {
- // Already verified above that user is same as default user
- info = c.getRestoredItemInfo(intent);
- } else if (c.itemType == Favorites.ITEM_TYPE_APPLICATION) {
- info = c.getAppShortcutInfo(
- intent, allowMissingTarget, useLowResIcon, false);
- } else if (c.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
- ShortcutKey key = ShortcutKey.fromIntent(intent, c.user);
- if (unlockedUsers.get(c.serialNumber)) {
- ShortcutInfo pinnedShortcut = mShortcutKeyToPinnedShortcuts.get(key);
- if (pinnedShortcut == null) {
- // The shortcut is no longer valid.
- c.markDeleted("Pinned shortcut not found from request."
- + " package=" + key.getPackageName() + ", user=" + c.user);
- if (mIsRestoreFromBackup && restoreEventLogger != null) {
- restoreEventLogger.logSingleFavoritesItemRestoreFailed(
- c.itemType, RESTORE_ERROR_SHORTCUT_NOT_FOUND);
- }
- return;
- }
- info = new WorkspaceItemInfo(pinnedShortcut, mApp.getContext());
- // If the pinned deep shortcut is no longer published,
- // use the last saved icon instead of the default.
- mIconCache.getShortcutIcon(info, pinnedShortcut, c::loadIcon);
-
- if (pmHelper.isAppSuspended(
- pinnedShortcut.getPackage(), info.user)) {
- info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED;
- }
- intent = info.getIntent();
- allDeepShortcuts.add(pinnedShortcut);
- } else {
- // Create a shortcut info in disabled mode for now.
- info = c.loadSimpleWorkspaceItem();
- info.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
- }
- if (mIsRestoreFromBackup && restoreEventLogger != null) {
- restoreEventLogger.logSingleFavoritesItemRestored(c.itemType);
- }
- } else { // item type == ITEM_TYPE_SHORTCUT
- info = c.loadSimpleWorkspaceItem();
-
- // Shortcuts are only available on the primary profile
- if (!TextUtils.isEmpty(targetPkg)
- && pmHelper.isAppSuspended(targetPkg, c.user)) {
- disabledState |= FLAG_DISABLED_SUSPENDED;
- }
- info.options = c.getOptions();
-
- // App shortcuts that used to be automatically added to Launcher
- // didn't always have the correct intent flags set, so do that here
- if (intent.getAction() != null
- && intent.getCategories() != null
- && intent.getAction().equals(Intent.ACTION_MAIN)
- && intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- }
- }
-
- if (info != null) {
- if (info.itemType != Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
- // Skip deep shortcuts; their title and icons have already been
- // loaded above.
- iconRequestInfos.add(c.createIconRequestInfo(info, useLowResIcon));
- }
-
- c.applyCommonProperties(info);
-
- info.intent = intent;
- info.rank = c.getRank();
- info.spanX = 1;
- info.spanY = 1;
- info.runtimeStatusFlags |= disabledState;
- if (isSafeMode && !isSystemApp(mApp.getContext(), intent)) {
- info.runtimeStatusFlags |= FLAG_DISABLED_SAFEMODE;
- }
- LauncherActivityInfo activityInfo = c.getLauncherActivityInfo();
- if (activityInfo != null) {
- info.setProgressLevel(
- PackageManagerHelper.getLoadingProgress(activityInfo),
- PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
- }
-
- if ((c.restoreFlag != 0
- || (enableSupportForArchiving()
- && activityInfo != null
- && activityInfo.getApplicationInfo().isArchived))
- && !TextUtils.isEmpty(targetPkg)) {
- tempPackageKey.update(targetPkg, c.user);
- SessionInfo si = installingPkgs.get(tempPackageKey);
- if (si == null) {
- info.runtimeStatusFlags
- &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
- } else if (activityInfo == null
- // For archived apps, include progress info in case there is
- // a pending install session post restart of device.
- || (enableSupportForArchiving()
- && activityInfo.getApplicationInfo().isArchived)) {
- int installProgress = (int) (si.getProgress() * 100);
-
- info.setProgressLevel(installProgress,
- PackageInstallInfo.STATUS_INSTALLING);
- }
- }
-
- c.checkAndAddItem(info, mBgDataModel, memoryLogger);
- } else {
- throw new RuntimeException("Unexpected null WorkspaceItemInfo");
- }
- break;
-
- case Favorites.ITEM_TYPE_FOLDER:
- case Favorites.ITEM_TYPE_APP_PAIR:
- FolderInfo folderInfo = mBgDataModel.findOrMakeFolder(c.id);
- c.applyCommonProperties(folderInfo);
-
- folderInfo.itemType = c.itemType;
- // Do not trim the folder label, as is was set by the user.
- folderInfo.title = c.getString(c.mTitleIndex);
- folderInfo.spanX = 1;
- folderInfo.spanY = 1;
- folderInfo.options = c.getOptions();
-
- // no special handling required for restored folders
- c.markRestored();
- if (mIsRestoreFromBackup && restoreEventLogger != null) {
- restoreEventLogger.logSingleFavoritesItemRestored(c.itemType);
- }
- c.checkAndAddItem(folderInfo, mBgDataModel, memoryLogger);
- break;
-
- case Favorites.ITEM_TYPE_APPWIDGET:
- if (WidgetsModel.GO_DISABLE_WIDGETS) {
- c.markDeleted("Only legacy shortcuts can have null package");
- if (mIsRestoreFromBackup && restoreEventLogger != null) {
- restoreEventLogger.logSingleFavoritesItemRestoreFailed(
- c.itemType, RESTORE_ERROR_WIDGETS_DISABLED);
- }
- return;
- }
- // Follow through
- case Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
- // Read all Launcher-specific widget details
- boolean customWidget = c.itemType
- == Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
-
- int appWidgetId = c.getAppWidgetId();
- String savedProvider = c.getAppWidgetProvider();
- final ComponentName component;
-
- if ((c.getOptions() & LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET) != 0) {
- component = QsbContainerView.getSearchComponentName(mApp.getContext());
- if (component == null) {
- c.markDeleted("Discarding SearchWidget without packagename ");
- if (mIsRestoreFromBackup && restoreEventLogger != null) {
- restoreEventLogger.logSingleFavoritesItemRestoreFailed(
- c.itemType, RESTORE_ERROR_MISSING_INFO);
- }
- return;
- }
- } else {
- component = ComponentName.unflattenFromString(savedProvider);
- }
- final boolean isIdValid =
- !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID);
- final boolean wasProviderReady =
- !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY);
-
- ComponentKey providerKey = new ComponentKey(component, c.user);
- if (!mWidgetProvidersMap.containsKey(providerKey)) {
- if (customWidget) {
- mWidgetProvidersMap.put(providerKey, CustomWidgetManager.INSTANCE
- .get(mApp.getContext()).getWidgetProvider(component));
- } else {
- mWidgetProvidersMap.put(providerKey,
- widgetHelper.findProvider(component, c.user));
- }
- }
- final AppWidgetProviderInfo provider = mWidgetProvidersMap.get(providerKey);
-
- final boolean isProviderReady = isValidProvider(provider);
- if (!isSafeMode && !customWidget && wasProviderReady && !isProviderReady) {
- c.markDeleted("Deleting widget that isn't installed anymore: " + provider);
- if (mIsRestoreFromBackup && restoreEventLogger != null) {
- restoreEventLogger.logSingleFavoritesItemRestoreFailed(
- c.itemType, RESTORE_ERROR_APP_NOT_INSTALLED);
- }
- } else {
- LauncherAppWidgetInfo appWidgetInfo;
- if (isProviderReady) {
- appWidgetInfo =
- new LauncherAppWidgetInfo(appWidgetId, provider.provider);
-
- // The provider is available. So the widget is either
- // available or not available. We do not need to track
- // any future restore updates.
- int status = c.restoreFlag
- & ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED
- & ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
- if (!wasProviderReady) {
- // If provider was not previously ready, update status and UI flag.
-
- // Id would be valid only if the widget restore broadcast received.
- if (isIdValid) {
- status |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
- }
- }
- appWidgetInfo.restoreStatus = status;
- } else {
- Log.v(TAG, "Widget restore pending id=" + c.id
- + " appWidgetId=" + appWidgetId
- + " status=" + c.restoreFlag);
- appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, component);
- appWidgetInfo.restoreStatus = c.restoreFlag;
-
- tempPackageKey.update(component.getPackageName(), c.user);
- SessionInfo si = installingPkgs.get(tempPackageKey);
- Integer installProgress = si == null
- ? null
- : (int) (si.getProgress() * 100);
-
- if (c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED)) {
- // Restore has started once.
- } else if (installProgress != null) {
- // App restore has started. Update the flag
- appWidgetInfo.restoreStatus
- |= LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
- } else if (!isSafeMode) {
- c.markDeleted("Unrestored widget removed: " + component);
- if (mIsRestoreFromBackup && restoreEventLogger != null) {
- restoreEventLogger.logSingleFavoritesItemRestoreFailed(
- c.itemType, RESTORE_ERROR_APP_NOT_INSTALLED);
- }
- return;
- }
-
- appWidgetInfo.installProgress =
- installProgress == null ? 0 : installProgress;
- }
- if (appWidgetInfo.hasRestoreFlag(
- LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)) {
- appWidgetInfo.bindOptions = c.parseIntent();
- }
-
- c.applyCommonProperties(appWidgetInfo);
- appWidgetInfo.spanX = c.getSpanX();
- appWidgetInfo.spanY = c.getSpanY();
- appWidgetInfo.options = c.getOptions();
- appWidgetInfo.user = c.user;
- appWidgetInfo.sourceContainer = c.getAppWidgetSource();
-
- if (appWidgetInfo.spanX <= 0 || appWidgetInfo.spanY <= 0) {
- c.markDeleted("Widget has invalid size: "
- + appWidgetInfo.spanX + "x" + appWidgetInfo.spanY);
- if (mIsRestoreFromBackup && restoreEventLogger != null) {
- restoreEventLogger.logSingleFavoritesItemRestoreFailed(
- c.itemType, RESTORE_ERROR_INVALID_LOCATION);
- }
- return;
- }
- LauncherAppWidgetProviderInfo widgetProviderInfo =
- widgetHelper.getLauncherAppWidgetInfo(appWidgetId,
- appWidgetInfo.getTargetComponent());
- if (widgetProviderInfo != null
- && (appWidgetInfo.spanX < widgetProviderInfo.minSpanX
- || appWidgetInfo.spanY < widgetProviderInfo.minSpanY)) {
- FileLog.d(TAG, "Widget " + widgetProviderInfo.getComponent()
- + " minSizes not meet: span=" + appWidgetInfo.spanX
- + "x" + appWidgetInfo.spanY + " minSpan="
- + widgetProviderInfo.minSpanX + "x"
- + widgetProviderInfo.minSpanY);
- logWidgetInfo(mApp.getInvariantDeviceProfile(), widgetProviderInfo);
- }
- if (!c.isOnWorkspaceOrHotseat()) {
- c.markDeleted("Widget found where container != CONTAINER_DESKTOP"
- + "nor CONTAINER_HOTSEAT - ignoring!");
- if (mIsRestoreFromBackup && restoreEventLogger != null) {
- restoreEventLogger.logSingleFavoritesItemRestoreFailed(
- c.itemType, RESTORE_ERROR_INVALID_LOCATION);
- }
- return;
- }
-
- if (!customWidget) {
- String providerName = appWidgetInfo.providerName.flattenToString();
- if (!providerName.equals(savedProvider)
- || (appWidgetInfo.restoreStatus != c.restoreFlag)) {
- c.updater()
- .put(Favorites.APPWIDGET_PROVIDER,
- providerName)
- .put(Favorites.RESTORED,
- appWidgetInfo.restoreStatus)
- .commit();
- }
- }
-
- if (appWidgetInfo.restoreStatus
- != LauncherAppWidgetInfo.RESTORE_COMPLETED) {
- appWidgetInfo.pendingItemInfo = WidgetsModel.newPendingItemInfo(
- mApp.getContext(),
- appWidgetInfo.providerName,
- appWidgetInfo.user);
- mIconCache.getTitleAndIconForApp(
- appWidgetInfo.pendingItemInfo, false);
- }
-
- c.checkAndAddItem(appWidgetInfo, mBgDataModel);
- }
- break;
+ if (info.usingLowResIcon() && info.itemType == Favorites.ITEM_TYPE_APPLICATION
+ && verifiers.stream().anyMatch(it -> it.isItemInPreview(info.rank))) {
+ mIconCache.getTitleAndIcon(info, false);
+ }
}
- } catch (Exception e) {
- Log.e(TAG, "Desktop items loading interrupted", e);
}
}
@@ -1206,52 +746,6 @@
&& (provider.provider.getPackageName() != null);
}
- @SuppressLint("NewApi") // Already added API check.
- private static void logWidgetInfo(InvariantDeviceProfile idp,
- LauncherAppWidgetProviderInfo widgetProviderInfo) {
- Point cellSize = new Point();
- for (DeviceProfile deviceProfile : idp.supportedProfiles) {
- deviceProfile.getCellSize(cellSize);
- FileLog.d(TAG, "DeviceProfile available width: " + deviceProfile.availableWidthPx
- + ", available height: " + deviceProfile.availableHeightPx
- + ", cellLayoutBorderSpacePx Horizontal: "
- + deviceProfile.cellLayoutBorderSpacePx.x
- + ", cellLayoutBorderSpacePx Vertical: "
- + deviceProfile.cellLayoutBorderSpacePx.y
- + ", cellSize: " + cellSize);
- }
-
- StringBuilder widgetDimension = new StringBuilder();
- widgetDimension.append("Widget dimensions:\n")
- .append("minResizeWidth: ")
- .append(widgetProviderInfo.minResizeWidth)
- .append("\n")
- .append("minResizeHeight: ")
- .append(widgetProviderInfo.minResizeHeight)
- .append("\n")
- .append("defaultWidth: ")
- .append(widgetProviderInfo.minWidth)
- .append("\n")
- .append("defaultHeight: ")
- .append(widgetProviderInfo.minHeight)
- .append("\n");
- if (Utilities.ATLEAST_S) {
- widgetDimension.append("targetCellWidth: ")
- .append(widgetProviderInfo.targetCellWidth)
- .append("\n")
- .append("targetCellHeight: ")
- .append(widgetProviderInfo.targetCellHeight)
- .append("\n")
- .append("maxResizeWidth: ")
- .append(widgetProviderInfo.maxResizeWidth)
- .append("\n")
- .append("maxResizeHeight: ")
- .append(widgetProviderInfo.maxResizeHeight)
- .append("\n");
- }
- FileLog.d(TAG, widgetDimension.toString());
- }
-
private static void logASplit(String label) {
if (DEBUG) {
Log.d(TAG, label);
diff --git a/src/com/android/launcher3/model/ModelLauncherCallbacks.kt b/src/com/android/launcher3/model/ModelLauncherCallbacks.kt
new file mode 100644
index 0000000..b12b2bc
--- /dev/null
+++ b/src/com/android/launcher3/model/ModelLauncherCallbacks.kt
@@ -0,0 +1,103 @@
+/*
+ * 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.model
+
+import android.content.pm.LauncherApps
+import android.content.pm.ShortcutInfo
+import android.os.UserHandle
+import android.text.TextUtils
+import com.android.launcher3.LauncherModel.ModelUpdateTask
+import com.android.launcher3.logging.FileLog
+import com.android.launcher3.model.PackageUpdatedTask.OP_ADD
+import com.android.launcher3.model.PackageUpdatedTask.OP_REMOVE
+import com.android.launcher3.model.PackageUpdatedTask.OP_SUSPEND
+import com.android.launcher3.model.PackageUpdatedTask.OP_UNAVAILABLE
+import com.android.launcher3.model.PackageUpdatedTask.OP_UNSUSPEND
+import com.android.launcher3.model.PackageUpdatedTask.OP_UPDATE
+import java.util.function.Consumer
+
+/**
+ * Implementation of {@link LauncherApps#Callbacks} which converts various events to corresponding
+ * model tasks
+ */
+class ModelLauncherCallbacks(private var taskExecutor: Consumer<ModelUpdateTask>) :
+ LauncherApps.Callback() {
+
+ override fun onPackageAdded(packageName: String, user: UserHandle) {
+ taskExecutor.accept(PackageUpdatedTask(OP_ADD, user, packageName))
+ }
+
+ override fun onPackageChanged(packageName: String, user: UserHandle) {
+ taskExecutor.accept(PackageUpdatedTask(OP_UPDATE, user, packageName))
+ }
+
+ override fun onPackageLoadingProgressChanged(
+ packageName: String,
+ user: UserHandle,
+ progress: Float
+ ) {
+ taskExecutor.accept(PackageIncrementalDownloadUpdatedTask(packageName, user, progress))
+ }
+
+ override fun onPackageRemoved(packageName: String, user: UserHandle) {
+ FileLog.d(TAG, "package removed received $packageName")
+ taskExecutor.accept(PackageUpdatedTask(OP_REMOVE, user, packageName))
+ }
+
+ override fun onPackagesAvailable(
+ vararg packageNames: String,
+ user: UserHandle,
+ replacing: Boolean
+ ) {
+ taskExecutor.accept(PackageUpdatedTask(OP_UPDATE, user, *packageNames))
+ }
+
+ override fun onPackagesSuspended(vararg packageNames: String, user: UserHandle) {
+ taskExecutor.accept(PackageUpdatedTask(OP_SUSPEND, user, *packageNames))
+ }
+
+ override fun onPackagesUnavailable(
+ packageNames: Array<String>,
+ user: UserHandle,
+ replacing: Boolean
+ ) {
+ if (!replacing) {
+ taskExecutor.accept(PackageUpdatedTask(OP_UNAVAILABLE, user, *packageNames))
+ }
+ }
+
+ override fun onPackagesUnsuspended(vararg packageNames: String, user: UserHandle) {
+ taskExecutor.accept(PackageUpdatedTask(OP_UNSUSPEND, user, *packageNames))
+ }
+
+ override fun onShortcutsChanged(
+ packageName: String,
+ shortcuts: MutableList<ShortcutInfo>,
+ user: UserHandle
+ ) {
+ taskExecutor.accept(ShortcutsChangedTask(packageName, shortcuts, user, true))
+ }
+
+ fun onPackagesRemoved(user: UserHandle, packages: List<String>) {
+ FileLog.d(TAG, "package removed received " + TextUtils.join(",", packages))
+ taskExecutor.accept(PackageUpdatedTask(OP_REMOVE, user, *packages.toTypedArray()))
+ }
+
+ companion object {
+ private const val TAG = "LauncherAppsCallbackImpl"
+ }
+}
diff --git a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
index 76a87ed..2457a42 100644
--- a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
+++ b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
@@ -52,7 +52,8 @@
ApplicationInfo ai = app.getContext()
.getPackageManager().getApplicationInfo(mInstallInfo.packageName, 0);
if (InstantAppResolver.newInstance(app.getContext()).isInstantApp(ai)) {
- app.getModel().onPackageAdded(ai.packageName, mInstallInfo.user);
+ app.getModel().newModelCallbacks()
+ .onPackageAdded(ai.packageName, mInstallInfo.user);
}
} catch (PackageManager.NameNotFoundException e) {
// Ignore
diff --git a/src/com/android/launcher3/model/SdCardAvailableReceiver.java b/src/com/android/launcher3/model/SdCardAvailableReceiver.java
index 3798575..8cfa3aa 100644
--- a/src/com/android/launcher3/model/SdCardAvailableReceiver.java
+++ b/src/com/android/launcher3/model/SdCardAvailableReceiver.java
@@ -67,11 +67,10 @@
}
}
if (!packagesRemoved.isEmpty()) {
- mModel.onPackagesRemoved(user,
- packagesRemoved.toArray(new String[packagesRemoved.size()]));
+ mModel.newModelCallbacks().onPackagesRemoved(user, packagesRemoved);
}
if (!packagesUnavailable.isEmpty()) {
- mModel.onPackagesUnavailable(
+ mModel.newModelCallbacks().onPackagesUnavailable(
packagesUnavailable.toArray(new String[packagesUnavailable.size()]),
user, false);
}
diff --git a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
new file mode 100644
index 0000000..5389d38
--- /dev/null
+++ b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
@@ -0,0 +1,672 @@
+/*
+ * 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.model
+
+import android.annotation.SuppressLint
+import android.appwidget.AppWidgetProviderInfo
+import android.content.ComponentName
+import android.content.Intent
+import android.content.pm.LauncherApps
+import android.content.pm.PackageInstaller
+import android.content.pm.ShortcutInfo
+import android.graphics.Point
+import android.text.TextUtils
+import android.util.Log
+import android.util.LongSparseArray
+import androidx.annotation.VisibleForTesting
+import com.android.launcher3.Flags
+import com.android.launcher3.InvariantDeviceProfile
+import com.android.launcher3.LauncherAppState
+import com.android.launcher3.LauncherSettings.Favorites
+import com.android.launcher3.Utilities
+import com.android.launcher3.backuprestore.LauncherRestoreEventLogger
+import com.android.launcher3.icons.IconCache
+import com.android.launcher3.logging.FileLog
+import com.android.launcher3.model.data.IconRequestInfo
+import com.android.launcher3.model.data.ItemInfoWithIcon
+import com.android.launcher3.model.data.LauncherAppWidgetInfo
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.pm.PackageInstallInfo
+import com.android.launcher3.qsb.QsbContainerView
+import com.android.launcher3.shortcuts.ShortcutKey
+import com.android.launcher3.util.ComponentKey
+import com.android.launcher3.util.PackageManagerHelper
+import com.android.launcher3.util.PackageUserKey
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo
+import com.android.launcher3.widget.WidgetManagerHelper
+import com.android.launcher3.widget.custom.CustomWidgetManager
+
+/**
+ * This items is used by LoaderTask to process items that have been loaded from the Launcher's DB.
+ * This data, stored in the Favorites table, needs to be processed in order to be shown on the Home
+ * Page.
+ *
+ * This class processes each of those items: App Shortcuts, Widgets, Folders, etc., one at a time.
+ */
+class WorkspaceItemProcessor(
+ private val c: LoaderCursor,
+ private val memoryLogger: LoaderMemoryLogger?,
+ private val restoreEventLogger: LauncherRestoreEventLogger?,
+ private val userManagerState: UserManagerState,
+ private val launcherApps: LauncherApps,
+ private val pendingPackages: MutableSet<PackageUserKey>,
+ private val shortcutKeyToPinnedShortcuts: Map<ShortcutKey, ShortcutInfo>,
+ private val app: LauncherAppState,
+ private val iconCache: IconCache,
+ private val bgDataModel: BgDataModel,
+ private val widgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?>,
+ private val isRestoreFromBackup: Boolean,
+ private val installingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo>,
+ private val isSdCardReady: Boolean,
+ private val tempPackageKey: PackageUserKey,
+ private val widgetHelper: WidgetManagerHelper,
+ private val pmHelper: PackageManagerHelper,
+ private val iconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>>,
+ private val unlockedUsers: LongSparseArray<Boolean>,
+ private val isSafeMode: Boolean,
+ private val allDeepShortcuts: MutableList<ShortcutInfo>
+) {
+ /**
+ * This is the entry point for processing 1 workspace item. This method is like the midfielder
+ * that delegates the actual processing to either processAppShortcut, processFolder, or
+ * processWidget depending on what type of item is being processed.
+ *
+ * All the parameters are expected to be shared between many repeated calls of this method, one
+ * for each workspace item.
+ */
+ fun processItem() {
+ try {
+ if (c.user == null) {
+ // User has been deleted, remove the item.
+ c.markDeleted("User has been deleted")
+ if (isRestoreFromBackup) {
+ restoreEventLogger?.logSingleFavoritesItemRestoreFailed(
+ c.itemType,
+ LauncherRestoreEventLogger.RESTORE_ERROR_PROFILE_DELETED
+ )
+ }
+ return
+ }
+ when (c.itemType) {
+ Favorites.ITEM_TYPE_APPLICATION,
+ Favorites.ITEM_TYPE_DEEP_SHORTCUT -> processAppOrDeepShortcut()
+ Favorites.ITEM_TYPE_FOLDER,
+ Favorites.ITEM_TYPE_APP_PAIR -> processFolderOrAppPair()
+ Favorites.ITEM_TYPE_APPWIDGET,
+ Favorites.ITEM_TYPE_CUSTOM_APPWIDGET -> processWidget()
+ }
+ } catch (e: Exception) {
+ Log.e(TAG, "Desktop items loading interrupted", e)
+ }
+ }
+
+ /**
+ * This method verifies that an app shortcut should be shown on the home screen, updates the
+ * database accordingly, formats the data in such a way that it is ready to be added to the data
+ * model, and then adds it to the launcher’s data model.
+ *
+ * In this method, verification means that an an app shortcut database entry is required to:
+ * Have a Launch Intent. This is how the app component symbolized by the shortcut is launched.
+ * Have a Package Name. Not be in a funky “Restoring, but never actually restored” state. Not
+ * have null or missing ShortcutInfos or ItemInfos in other data models.
+ *
+ * If any of the above are found to be true, the database entry is deleted, and not shown on the
+ * user’s home screen. When an app is verified, it is marked as restored, meaning that the app
+ * is viable to show on the home screen.
+ *
+ * In order to accommodate different types and versions of App Shortcuts, different properties
+ * and flags are set on the ItemInfo objects that are added to the data model. For example,
+ * icons that are not a part of the workspace or hotseat are marked as using low resolution icon
+ * bitmaps. Currently suspended app icons are marked as such. Installing packages are also
+ * marked as such. Lastly, after applying common properties to the ItemInfo, it is added to the
+ * data model to be bound to the launcher’s data model.
+ */
+ @SuppressLint("NewApi")
+ @VisibleForTesting
+ fun processAppOrDeepShortcut() {
+ var allowMissingTarget = false
+ var intent = c.parseIntent()
+ if (intent == null) {
+ c.markDeleted("Invalid or null intent")
+ if (isRestoreFromBackup) {
+ restoreEventLogger?.logSingleFavoritesItemRestoreFailed(
+ c.itemType,
+ LauncherRestoreEventLogger.RESTORE_ERROR_MISSING_INFO
+ )
+ }
+ return
+ }
+ var disabledState =
+ if (userManagerState.isUserQuiet(c.serialNumber))
+ WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER
+ else 0
+ var cn = intent.component
+ val targetPkg = if (cn == null) intent.getPackage() else cn.packageName
+ if (TextUtils.isEmpty(targetPkg)) {
+ c.markDeleted("Shortcuts can't have null package")
+ if (isRestoreFromBackup) {
+ restoreEventLogger?.logSingleFavoritesItemRestoreFailed(
+ c.itemType,
+ LauncherRestoreEventLogger.RESTORE_ERROR_MISSING_INFO
+ )
+ }
+ return
+ }
+
+ // If there is no target package, it's an implicit intent
+ // (legacy shortcut) which is always valid
+ var validTarget =
+ (TextUtils.isEmpty(targetPkg) || launcherApps.isPackageEnabled(targetPkg, c.user))
+
+ // If it's a deep shortcut, we'll use pinned shortcuts to restore it
+ if (cn != null && validTarget && (c.itemType != Favorites.ITEM_TYPE_DEEP_SHORTCUT)) {
+ // If the apk is present and the shortcut points to a specific component.
+
+ // If the component is already present
+ if (launcherApps.isActivityEnabled(cn, c.user)) {
+ // no special handling necessary for this item
+ c.markRestored()
+ if (isRestoreFromBackup) {
+ restoreEventLogger?.logSingleFavoritesItemRestored(c.itemType)
+ }
+ } else {
+ // Gracefully try to find a fallback activity.
+ intent = pmHelper.getAppLaunchIntent(targetPkg, c.user)
+ if (intent != null) {
+ c.restoreFlag = 0
+ c.updater().put(Favorites.INTENT, intent.toUri(0)).commit()
+ } else {
+ c.markDeleted("Intent null, unable to find a launch target")
+ if (isRestoreFromBackup) {
+ restoreEventLogger?.logSingleFavoritesItemRestoreFailed(
+ c.itemType,
+ LauncherRestoreEventLogger.RESTORE_ERROR_MISSING_INFO
+ )
+ }
+ return
+ }
+ }
+ }
+ // else if cn == null => can't infer much, leave it
+ // else if !validPkg => could be restored icon or missing sd-card
+ when {
+ !TextUtils.isEmpty(targetPkg) && !validTarget -> {
+ // Points to a valid app (superset of cn != null) but the apk
+ // is not available.
+ when {
+ c.restoreFlag != 0 -> {
+ // Package is not yet available but might be
+ // installed later.
+ FileLog.d(TAG, "package not yet restored: $targetPkg")
+ tempPackageKey.update(targetPkg, c.user)
+ when {
+ c.hasRestoreFlag(WorkspaceItemInfo.FLAG_RESTORE_STARTED) -> {
+ // Restore has started once.
+ }
+ installingPkgs.containsKey(tempPackageKey) -> {
+ // App restore has started. Update the flag
+ c.restoreFlag =
+ c.restoreFlag or WorkspaceItemInfo.FLAG_RESTORE_STARTED
+ FileLog.d(TAG, "restore started for installing app: $targetPkg")
+ c.updater().put(Favorites.RESTORED, c.restoreFlag).commit()
+ }
+ else -> {
+ c.markDeleted(
+ "removing app that is not restored and not installing. package: $targetPkg"
+ )
+ if (isRestoreFromBackup) {
+ restoreEventLogger?.logSingleFavoritesItemRestoreFailed(
+ c.itemType,
+ LauncherRestoreEventLogger.RESTORE_ERROR_APP_NOT_INSTALLED
+ )
+ }
+ return
+ }
+ }
+ }
+ pmHelper.isAppOnSdcard(targetPkg!!, c.user) -> {
+ // Package is present but not available.
+ disabledState =
+ disabledState or WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE
+ // Add the icon on the workspace anyway.
+ allowMissingTarget = true
+ }
+ !isSdCardReady -> {
+ // SdCard is not ready yet. Package might get available,
+ // once it is ready.
+ Log.d(TAG, "Missing package, will check later: $targetPkg")
+ pendingPackages.add(PackageUserKey(targetPkg, c.user))
+ // Add the icon on the workspace anyway.
+ allowMissingTarget = true
+ }
+ else -> {
+ // Do not wait for external media load anymore.
+ c.markDeleted("Invalid package removed: $targetPkg")
+ if (isRestoreFromBackup) {
+ restoreEventLogger?.logSingleFavoritesItemRestoreFailed(
+ c.itemType,
+ LauncherRestoreEventLogger.RESTORE_ERROR_APP_NOT_INSTALLED
+ )
+ }
+ return
+ }
+ }
+ }
+ }
+ if (c.restoreFlag and WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI != 0) {
+ validTarget = false
+ }
+ if (validTarget) {
+ // The shortcut points to a valid target (either no target
+ // or something which is ready to be used)
+ c.markRestored()
+ }
+ val useLowResIcon = !c.isOnWorkspaceOrHotseat
+ val info: WorkspaceItemInfo?
+ when {
+ c.restoreFlag != 0 -> {
+ // Already verified above that user is same as default user
+ info = c.getRestoredItemInfo(intent)
+ }
+ c.itemType == Favorites.ITEM_TYPE_APPLICATION ->
+ info = c.getAppShortcutInfo(intent, allowMissingTarget, useLowResIcon, false)
+ c.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT -> {
+ val key = ShortcutKey.fromIntent(intent, c.user)
+ if (unlockedUsers[c.serialNumber]) {
+ val pinnedShortcut = shortcutKeyToPinnedShortcuts[key]
+ if (pinnedShortcut == null) {
+ // The shortcut is no longer valid.
+ c.markDeleted(
+ "Pinned shortcut not found from request. package=${key.packageName}, user=${c.user}"
+ )
+ if (isRestoreFromBackup) {
+ restoreEventLogger?.logSingleFavoritesItemRestoreFailed(
+ c.itemType,
+ LauncherRestoreEventLogger.RESTORE_ERROR_SHORTCUT_NOT_FOUND
+ )
+ }
+ return
+ }
+ info = WorkspaceItemInfo(pinnedShortcut, app.context)
+ // If the pinned deep shortcut is no longer published,
+ // use the last saved icon instead of the default.
+ iconCache.getShortcutIcon(info, pinnedShortcut, c::loadIcon)
+ if (pmHelper.isAppSuspended(pinnedShortcut.getPackage(), info.user)) {
+ info.runtimeStatusFlags =
+ info.runtimeStatusFlags or ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED
+ }
+ intent = info.getIntent()
+ allDeepShortcuts.add(pinnedShortcut)
+ } else {
+ // Create a shortcut info in disabled mode for now.
+ info = c.loadSimpleWorkspaceItem()
+ info.runtimeStatusFlags =
+ info.runtimeStatusFlags or ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER
+ }
+ if (isRestoreFromBackup) {
+ restoreEventLogger?.logSingleFavoritesItemRestored(c.itemType)
+ }
+ }
+ else -> { // item type == ITEM_TYPE_SHORTCUT
+ info = c.loadSimpleWorkspaceItem()
+
+ // Shortcuts are only available on the primary profile
+ if (!TextUtils.isEmpty(targetPkg) && pmHelper.isAppSuspended(targetPkg!!, c.user)) {
+ disabledState = disabledState or ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED
+ }
+ info.options = c.options
+
+ // App shortcuts that used to be automatically added to Launcher
+ // didn't always have the correct intent flags set, so do that here
+ if (
+ intent.action != null &&
+ intent.categories != null &&
+ intent.action == Intent.ACTION_MAIN &&
+ intent.categories.contains(Intent.CATEGORY_LAUNCHER)
+ ) {
+ intent.addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+ )
+ }
+ }
+ }
+ if (info != null) {
+ if (info.itemType != Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+ // Skip deep shortcuts; their title and icons have already been
+ // loaded above.
+ iconRequestInfos.add(c.createIconRequestInfo(info, useLowResIcon))
+ }
+ c.applyCommonProperties(info)
+ info.intent = intent
+ info.rank = c.rank
+ info.spanX = 1
+ info.spanY = 1
+ info.runtimeStatusFlags = info.runtimeStatusFlags or disabledState
+ if (isSafeMode && !PackageManagerHelper.isSystemApp(app.context, intent)) {
+ info.runtimeStatusFlags =
+ info.runtimeStatusFlags or ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE
+ }
+ val activityInfo = c.launcherActivityInfo
+ if (activityInfo != null) {
+ info.setProgressLevel(
+ PackageManagerHelper.getLoadingProgress(activityInfo),
+ PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING
+ )
+ }
+ if (
+ (c.restoreFlag != 0 ||
+ Flags.enableSupportForArchiving() &&
+ activityInfo != null &&
+ activityInfo.applicationInfo.isArchived) && !TextUtils.isEmpty(targetPkg)
+ ) {
+ tempPackageKey.update(targetPkg, c.user)
+ val si = installingPkgs[tempPackageKey]
+ if (si == null) {
+ info.runtimeStatusFlags =
+ info.runtimeStatusFlags and
+ ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE.inv()
+ } else if (
+ activityInfo ==
+ null // For archived apps, include progress info in case there is
+ // a pending install session post restart of device.
+ ||
+ (Flags.enableSupportForArchiving() &&
+ activityInfo.applicationInfo.isArchived)
+ ) {
+ val installProgress = (si.getProgress() * 100).toInt()
+ info.setProgressLevel(installProgress, PackageInstallInfo.STATUS_INSTALLING)
+ }
+ }
+ c.checkAndAddItem(info, bgDataModel, memoryLogger)
+ } else {
+ throw RuntimeException("Unexpected null WorkspaceItemInfo")
+ }
+ }
+
+ /**
+ * Loads the folder information from the database and formats it into a FolderInfo. Some of the
+ * processing for folder content items is done in LoaderTask after all the items in the
+ * workspace have been loaded. The loaded FolderInfos are stored in the BgDataModel.
+ */
+ @VisibleForTesting
+ fun processFolderOrAppPair() {
+ val folderInfo =
+ bgDataModel.findOrMakeFolder(c.id).apply {
+ c.applyCommonProperties(this)
+ itemType = c.itemType
+ // Do not trim the folder label, as is was set by the user.
+ title = c.getString(c.mTitleIndex)
+ spanX = 1
+ spanY = 1
+ options = c.options
+ }
+
+ // no special handling required for restored folders
+ c.markRestored()
+ if (isRestoreFromBackup) {
+ restoreEventLogger?.logSingleFavoritesItemRestored(c.itemType)
+ }
+ c.checkAndAddItem(folderInfo, bgDataModel, memoryLogger)
+ }
+
+ /**
+ * This method, similar to processAppShortcut above, verifies that a widget should be shown on
+ * the home screen, updates the database accordingly, formats the data in such a way that it is
+ * ready to be added to the data model, and then adds it to the launcher’s data model.
+ *
+ * It verifies that: Widgets are not disabled due to the Launcher variety being of the `Go`
+ * type. Search Widgets have a package name. The app behind the widget is still installed on the
+ * device. The app behind the widget is not in a funky “Restoring, but never actually restored”
+ * state. The widget has a valid size. The widget is in the workspace or the hotseat. If any of
+ * the above are found to be true, the database entry is deleted, and the widget is not shown on
+ * the user’s home screen. When a widget is verified, it is marked as restored, meaning that the
+ * widget is viable to show on the home screen.
+ *
+ * Common properties are applied to the Widget’s Info object, and other information as well
+ * depending on the type of widget. Custom widgets are treated differently than non-custom
+ * widgets, installing / restoring widgets are treated differently, etc.
+ */
+ @VisibleForTesting
+ fun processWidget() {
+ if (WidgetsModel.GO_DISABLE_WIDGETS && c.itemType == Favorites.ITEM_TYPE_APPWIDGET) {
+ c.markDeleted("Only legacy shortcuts can have null package")
+ if (isRestoreFromBackup) {
+ restoreEventLogger?.logSingleFavoritesItemRestoreFailed(
+ c.itemType,
+ LauncherRestoreEventLogger.RESTORE_ERROR_WIDGETS_DISABLED
+ )
+ }
+ return
+ }
+
+ // Read all Launcher-specific widget details
+ val customWidget = (c.itemType == Favorites.ITEM_TYPE_CUSTOM_APPWIDGET)
+ val appWidgetId = c.appWidgetId
+ val savedProvider = c.appWidgetProvider
+ val component: ComponentName?
+ if (c.options and LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET != 0) {
+ component = QsbContainerView.getSearchComponentName(app.context)
+ if (component == null) {
+ c.markDeleted("Discarding SearchWidget without package name")
+ if (isRestoreFromBackup) {
+ restoreEventLogger?.logSingleFavoritesItemRestoreFailed(
+ c.itemType,
+ LauncherRestoreEventLogger.RESTORE_ERROR_MISSING_INFO
+ )
+ }
+ return
+ }
+ } else {
+ component = ComponentName.unflattenFromString(savedProvider)
+ }
+ val isIdValid = !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)
+ val wasProviderReady = !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)
+ val providerKey = ComponentKey(component, c.user)
+ if (!widgetProvidersMap.containsKey(providerKey)) {
+ if (customWidget) {
+ widgetProvidersMap[providerKey] =
+ CustomWidgetManager.INSTANCE[app.context].getWidgetProvider(component)
+ } else {
+ widgetProvidersMap[providerKey] = widgetHelper.findProvider(component, c.user)
+ }
+ }
+ val provider = widgetProvidersMap[providerKey]
+ val isProviderReady = LoaderTask.isValidProvider(provider)
+ if (!isSafeMode && !customWidget && wasProviderReady && !isProviderReady) {
+ c.markDeleted("Deleting widget that isn't installed anymore: $provider")
+ if (isRestoreFromBackup) {
+ restoreEventLogger?.logSingleFavoritesItemRestoreFailed(
+ c.itemType,
+ LauncherRestoreEventLogger.RESTORE_ERROR_APP_NOT_INSTALLED
+ )
+ }
+ } else {
+ val appWidgetInfo: LauncherAppWidgetInfo
+ if (isProviderReady) {
+ appWidgetInfo = LauncherAppWidgetInfo(appWidgetId, provider!!.provider)
+
+ // The provider is available. So the widget is either
+ // available or not available. We do not need to track
+ // any future restore updates.
+ var status =
+ (c.restoreFlag and
+ LauncherAppWidgetInfo.FLAG_RESTORE_STARTED.inv() and
+ LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY.inv())
+ if (!wasProviderReady) {
+ // If provider was not previously ready, update status and UI flag.
+
+ // Id would be valid only if the widget restore broadcast received.
+ if (isIdValid) {
+ status = status or LauncherAppWidgetInfo.FLAG_UI_NOT_READY
+ }
+ }
+ appWidgetInfo.restoreStatus = status
+ } else {
+ Log.v(
+ TAG,
+ "Widget restore pending id=${c.id} appWidgetId=$appWidgetId status=${c.restoreFlag}"
+ )
+ appWidgetInfo = LauncherAppWidgetInfo(appWidgetId, component)
+ appWidgetInfo.restoreStatus = c.restoreFlag
+ tempPackageKey.update(component!!.packageName, c.user)
+ val si = installingPkgs[tempPackageKey]
+ val installProgress = if (si == null) null else (si.getProgress() * 100).toInt()
+ when {
+ c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED) -> {
+ // Restore has started once.
+ }
+ installProgress != null -> {
+ // App restore has started. Update the flag
+ appWidgetInfo.restoreStatus =
+ appWidgetInfo.restoreStatus or
+ LauncherAppWidgetInfo.FLAG_RESTORE_STARTED
+ }
+ !isSafeMode -> {
+ c.markDeleted("Unrestored widget removed: $component")
+ if (isRestoreFromBackup) {
+ restoreEventLogger?.logSingleFavoritesItemRestoreFailed(
+ c.itemType,
+ LauncherRestoreEventLogger.RESTORE_ERROR_APP_NOT_INSTALLED
+ )
+ }
+ return
+ }
+ }
+ appWidgetInfo.installProgress = installProgress ?: 0
+ }
+ if (appWidgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)) {
+ appWidgetInfo.bindOptions = c.parseIntent()
+ }
+ c.applyCommonProperties(appWidgetInfo)
+ appWidgetInfo.spanX = c.spanX
+ appWidgetInfo.spanY = c.spanY
+ appWidgetInfo.options = c.options
+ appWidgetInfo.user = c.user
+ appWidgetInfo.sourceContainer = c.appWidgetSource
+ if (appWidgetInfo.spanX <= 0 || appWidgetInfo.spanY <= 0) {
+ c.markDeleted(
+ "Widget has invalid size: ${appWidgetInfo.spanX}x${appWidgetInfo.spanY}"
+ )
+ if (isRestoreFromBackup) {
+ restoreEventLogger?.logSingleFavoritesItemRestoreFailed(
+ c.itemType,
+ LauncherRestoreEventLogger.RESTORE_ERROR_INVALID_LOCATION
+ )
+ }
+ return
+ }
+ val widgetProviderInfo =
+ widgetHelper.getLauncherAppWidgetInfo(appWidgetId, appWidgetInfo.targetComponent)
+ if (
+ widgetProviderInfo != null &&
+ (appWidgetInfo.spanX < widgetProviderInfo.minSpanX ||
+ appWidgetInfo.spanY < widgetProviderInfo.minSpanY)
+ ) {
+ FileLog.d(
+ TAG,
+ "Widget ${widgetProviderInfo.component} minSizes not meet:" +
+ " span=${appWidgetInfo.spanX}x${appWidgetInfo.spanY}" +
+ " minSpan=${widgetProviderInfo.minSpanX}x${widgetProviderInfo.minSpanY}"
+ )
+ logWidgetInfo(app.invariantDeviceProfile, widgetProviderInfo)
+ }
+ if (!c.isOnWorkspaceOrHotseat) {
+ c.markDeleted(
+ "Widget found where container != CONTAINER_DESKTOP" +
+ " nor CONTAINER_HOTSEAT - ignoring!"
+ )
+ if (isRestoreFromBackup) {
+ restoreEventLogger?.logSingleFavoritesItemRestoreFailed(
+ c.itemType,
+ LauncherRestoreEventLogger.RESTORE_ERROR_INVALID_LOCATION
+ )
+ }
+ return
+ }
+ if (!customWidget) {
+ val providerName = appWidgetInfo.providerName.flattenToString()
+ if (providerName != savedProvider || appWidgetInfo.restoreStatus != c.restoreFlag) {
+ c.updater()
+ .put(Favorites.APPWIDGET_PROVIDER, providerName)
+ .put(Favorites.RESTORED, appWidgetInfo.restoreStatus)
+ .commit()
+ }
+ }
+ if (appWidgetInfo.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED) {
+ appWidgetInfo.pendingItemInfo =
+ WidgetsModel.newPendingItemInfo(
+ app.context,
+ appWidgetInfo.providerName,
+ appWidgetInfo.user
+ )
+ iconCache.getTitleAndIconForApp(appWidgetInfo.pendingItemInfo, false)
+ }
+ c.checkAndAddItem(appWidgetInfo, bgDataModel)
+ }
+ }
+
+ companion object {
+ private val TAG = WorkspaceItemProcessor::class.java.simpleName
+ private fun logWidgetInfo(
+ idp: InvariantDeviceProfile,
+ widgetProviderInfo: LauncherAppWidgetProviderInfo
+ ) {
+ val cellSize = Point()
+ for (deviceProfile in idp.supportedProfiles) {
+ deviceProfile.getCellSize(cellSize)
+ FileLog.d(
+ TAG,
+ "DeviceProfile available width: ${deviceProfile.availableWidthPx}," +
+ " available height: ${deviceProfile.availableHeightPx}," +
+ " cellLayoutBorderSpacePx Horizontal: ${deviceProfile.cellLayoutBorderSpacePx.x}," +
+ " cellLayoutBorderSpacePx Vertical: ${deviceProfile.cellLayoutBorderSpacePx.y}," +
+ " cellSize: $cellSize"
+ )
+ }
+ val widgetDimension = StringBuilder()
+ widgetDimension
+ .append("Widget dimensions:\n")
+ .append("minResizeWidth: ")
+ .append(widgetProviderInfo.minResizeWidth)
+ .append("\n")
+ .append("minResizeHeight: ")
+ .append(widgetProviderInfo.minResizeHeight)
+ .append("\n")
+ .append("defaultWidth: ")
+ .append(widgetProviderInfo.minWidth)
+ .append("\n")
+ .append("defaultHeight: ")
+ .append(widgetProviderInfo.minHeight)
+ .append("\n")
+ if (Utilities.ATLEAST_S) {
+ widgetDimension
+ .append("targetCellWidth: ")
+ .append(widgetProviderInfo.targetCellWidth)
+ .append("\n")
+ .append("targetCellHeight: ")
+ .append(widgetProviderInfo.targetCellHeight)
+ .append("\n")
+ .append("maxResizeWidth: ")
+ .append(widgetProviderInfo.maxResizeWidth)
+ .append("\n")
+ .append("maxResizeHeight: ")
+ .append(widgetProviderInfo.maxResizeHeight)
+ .append("\n")
+ }
+ FileLog.d(TAG, widgetDimension.toString())
+ }
+ }
+}
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/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index f39f806..8463361 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -1,5 +1,6 @@
package com.android.launcher3.popup;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_INSTALL_SYSTEM_SHORTCUT_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP;
@@ -8,6 +9,7 @@
import android.content.Intent;
import android.graphics.Rect;
import android.os.Process;
+import android.os.UserHandle;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ImageView;
@@ -20,10 +22,12 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.allapps.PrivateProfileManager;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.uioverrides.ApiWrapper;
+import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.InstantAppResolver;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
@@ -212,6 +216,69 @@
}
}
+ public static final Factory<Launcher> PRIVATE_PROFILE_INSTALL =
+ (launcher, itemInfo, originalView) -> {
+ if (itemInfo.getTargetComponent() == null
+ || !(itemInfo instanceof com.android.launcher3.model.data.AppInfo)
+ || !itemInfo.getContainerInfo().hasAllAppsContainer()
+ || !Process.myUserHandle().equals(itemInfo.user)) {
+ return null;
+ }
+
+ PrivateProfileManager privateProfileManager =
+ launcher.getAppsView().getPrivateProfileManager();
+ if (privateProfileManager == null || !privateProfileManager.isEnabled()) {
+ return null;
+ }
+
+ UserHandle privateProfileUser = privateProfileManager.getProfileUser();
+ if (privateProfileUser == null) {
+ return null;
+ }
+ // Do not show shortcut if an app is already installed to the space
+ ComponentKey targetKey =
+ new ComponentKey(itemInfo.getTargetComponent(), privateProfileUser);
+ if (launcher.getAppsView().getAppsStore().getApp(targetKey) != null) {
+ return null;
+ }
+
+ // TODO(b/302666597): do not install app if it's in deny list (e.g. settings)
+
+ return new InstallToPrivateProfile(
+ launcher, itemInfo, originalView, privateProfileUser);
+ };
+
+ static class InstallToPrivateProfile extends SystemShortcut<Launcher> {
+ UserHandle mSpaceUser;
+
+ InstallToPrivateProfile(
+ Launcher target, ItemInfo itemInfo, View originalView, UserHandle spaceUser) {
+ // TODO(b/302666597): update icon once available
+ super(
+ R.drawable.ic_install_to_private,
+ R.string.install_private_system_shortcut_label,
+ target,
+ itemInfo,
+ originalView);
+ mSpaceUser = spaceUser;
+ }
+
+ @Override
+ public void onClick(View view) {
+ Intent intent =
+ ApiWrapper.getAppMarketActivityIntent(
+ view.getContext(),
+ mItemInfo.getTargetComponent().getPackageName(),
+ mSpaceUser);
+ mTarget.startActivitySafely(view, intent, mItemInfo);
+ AbstractFloatingView.closeAllOpenViews(mTarget);
+ mTarget.getStatsLogManager()
+ .logger()
+ .withItemInfo(mItemInfo)
+ .log(LAUNCHER_PRIVATE_SPACE_INSTALL_SYSTEM_SHORTCUT_TAP);
+ }
+ }
+
public static final Factory<BaseDraggingActivity> INSTALL =
(activity, itemInfo, originalView) -> {
boolean supportsWebUI = (itemInfo instanceof WorkspaceItemInfo)
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index a969c8f..9750d25 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -18,7 +18,7 @@
import static android.os.Process.myUserHandle;
-import static com.android.launcher3.Flags.enableLauncherBrMetrics;
+import static com.android.launcher3.Flags.enableLauncherBrMetricsFixed;
import static com.android.launcher3.InvariantDeviceProfile.TYPE_MULTI_DISPLAY;
import static com.android.launcher3.LauncherPrefs.APP_WIDGET_IDS;
import static com.android.launcher3.LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE;
@@ -30,7 +30,6 @@
import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_PROFILE_NOT_RESTORED;
import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_WIDGETS_DISABLED;
import static com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RESTORE_ERROR_WIDGET_REMOVED;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_LAUNCHER_BR_METRICS;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import static com.android.launcher3.widget.LauncherWidgetHolder.APPWIDGET_HOST_ID;
@@ -199,7 +198,7 @@
Arrays.fill(args, "?");
final String where = "profileId NOT IN (" + TextUtils.join(", ", Arrays.asList(args)) + ")";
logFavoritesTable(db, "items to delete from unrestored profiles:", where, profileIds);
- if (enableLauncherBrMetrics() || ENABLE_LAUNCHER_BR_METRICS.get()) {
+ if (enableLauncherBrMetricsFixed()) {
reportUnrestoredProfiles(db, where, profileIds, restoreEventLogger);
}
int itemsDeletedCount = db.delete(Favorites.TABLE_NAME, where, profileIds);
@@ -361,7 +360,7 @@
DeviceGridState deviceGridState = new DeviceGridState(context);
FileLog.d(TAG, "restore initiated from backup: DeviceGridState=" + deviceGridState);
LauncherPrefs.get(context).putSync(RESTORE_DEVICE.to(deviceGridState.getDeviceType()));
- if (enableLauncherBrMetrics() || ENABLE_LAUNCHER_BR_METRICS.get()) {
+ if (enableLauncherBrMetricsFixed()) {
LauncherPrefs.get(context).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(true));
}
}
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 7b192dc..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);
}
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/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
index 6ad913e..25979c2 100644
--- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
@@ -88,8 +88,8 @@
private Layout mSetupTextLayout;
public PendingAppWidgetHostView(Context context, LauncherAppWidgetInfo info,
- @Nullable LauncherAppWidgetProviderInfo appWidget, boolean disabledForSafeMode) {
- this(context, info, disabledForSafeMode, appWidget,
+ @Nullable LauncherAppWidgetProviderInfo appWidget) {
+ this(context, info, appWidget,
context.getResources().getText(R.string.gadget_complete_setup_text));
super.updateAppWidget(null);
@@ -107,7 +107,7 @@
public PendingAppWidgetHostView(
Context context, int appWidgetId, @NonNull LauncherAppWidgetProviderInfo appWidget) {
- this(context, new LauncherAppWidgetInfo(appWidgetId, appWidget.provider), false,
+ this(context, new LauncherAppWidgetInfo(appWidgetId, appWidget.provider),
appWidget, appWidget.label);
getBackground().mutate().setAlpha(DEFERRED_ALPHA);
@@ -117,14 +117,13 @@
}
private PendingAppWidgetHostView(Context context, LauncherAppWidgetInfo info,
- boolean disabledForSafeMode, LauncherAppWidgetProviderInfo appwidget,
- 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();
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/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
index c3ab08c..54c9324 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker;
import android.content.Context;
+import android.content.res.Configuration;
import android.graphics.Outline;
import android.os.Process;
import android.util.AttributeSet;
@@ -124,6 +125,9 @@
}
@Override
+ protected void onConfigurationChanged(Configuration newConfig) {}
+
+ @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (changed && mDeviceProfile.isTwoPanels && enableUnfoldedTwoPanePicker()) {
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index ccbe382..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";
diff --git a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
index bc4c16e..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",
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/model/LoaderTaskTest.kt b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
index def27b8..dbca9d1 100644
--- a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
@@ -1,6 +1,5 @@
package com.android.launcher3.model
-import android.content.Context
import android.os.UserHandle
import android.platform.test.flag.junit.SetFlagsRule
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -11,16 +10,20 @@
import com.android.launcher3.LauncherAppState
import com.android.launcher3.LauncherModel
import com.android.launcher3.LauncherModel.LoaderTransaction
+import com.android.launcher3.LauncherPrefs
import com.android.launcher3.icons.IconCache
import com.android.launcher3.icons.cache.CachingLogic
import com.android.launcher3.icons.cache.IconCacheUpdateHandler
+import com.android.launcher3.pm.InstallSessionHelper
import com.android.launcher3.pm.UserCache
+import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper
import com.android.launcher3.util.Executors.MODEL_EXECUTOR
import com.android.launcher3.util.LooperIdleLock
+import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext
import com.android.launcher3.util.UserIconInfo
-import com.android.launcher3.util.rule.StaticMockitoRule
import com.google.common.truth.Truth
import java.util.concurrent.CountDownLatch
+import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -39,6 +42,7 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
class LoaderTaskTest {
+ private lateinit var context: SandboxContext
@Mock private lateinit var app: LauncherAppState
@Mock private lateinit var bgAllAppsList: AllAppsList
@Mock private lateinit var modelDelegate: ModelDelegate
@@ -52,21 +56,28 @@
@Spy private var userManagerState: UserManagerState? = UserManagerState()
- @get:Rule(order = 0) val staticMockitoRule = StaticMockitoRule(UserCache::class.java)
- @get:Rule(order = 1)
- val setFlagsRule = SetFlagsRule().apply { initAllFlagsToReleaseConfigDefault() }
+ @get:Rule val setFlagsRule = SetFlagsRule().apply { initAllFlagsToReleaseConfigDefault() }
@Before
fun setup() {
- val context = InstrumentationRegistry.getInstrumentation().targetContext
+ MockitoAnnotations.initMocks(this)
+
+ context =
+ SandboxContext(
+ InstrumentationRegistry.getInstrumentation().targetContext,
+ InstallSessionHelper.INSTANCE,
+ LauncherPrefs.INSTANCE,
+ ItemInstallQueue.INSTANCE,
+ PluginManagerWrapper.INSTANCE
+ )
val idp =
- InvariantDeviceProfile.INSTANCE[context].apply {
+ InvariantDeviceProfile().apply {
numRows = 5
numColumns = 6
numDatabaseHotseatIcons = 5
}
+ context.putObject(InvariantDeviceProfile.INSTANCE, idp)
- MockitoAnnotations.initMocks(this)
`when`(app.context).thenReturn(context)
`when`(app.model).thenReturn(launcherModel)
`when`(launcherModel.beginLoader(any(LoaderTask::class.java))).thenReturn(transaction)
@@ -77,7 +88,12 @@
`when`(launcherBinder.newIdleLock(any(LoaderTask::class.java))).thenReturn(idleLock)
`when`(idleLock.awaitLocked(1000)).thenReturn(false)
`when`(iconCache.updateHandler).thenReturn(iconCacheUpdateHandler)
- `when`(UserCache.getInstance(any(Context::class.java))).thenReturn(userCache)
+ context.putObject(UserCache.INSTANCE, userCache)
+ }
+
+ @After
+ fun tearDown() {
+ context.onDestroy()
}
@Test
diff --git a/tests/src/com/android/launcher3/model/ModelMultiCallbacksTest.java b/tests/src/com/android/launcher3/model/ModelMultiCallbacksTest.java
index 3dfd6b4..25a4c4e 100644
--- a/tests/src/com/android/launcher3/model/ModelMultiCallbacksTest.java
+++ b/tests/src/com/android/launcher3/model/ModelMultiCallbacksTest.java
@@ -73,6 +73,10 @@
TestUtil.uninstallDummyApp();
}
+ private ModelLauncherCallbacks getCallbacks() {
+ return mModelHelper.getModel().newModelCallbacks();
+ }
+
@Test
public void testTwoCallbacks_loadedTogether() throws Exception {
setupWorkspacePages(3);
@@ -127,14 +131,14 @@
// Install package 1
TestUtil.installDummyApp();
- mModelHelper.getModel().onPackageAdded(TestUtil.DUMMY_PACKAGE, Process.myUserHandle());
+ getCallbacks().onPackageAdded(TestUtil.DUMMY_PACKAGE, Process.myUserHandle());
waitForLoaderAndTempMainThread();
assertTrue(cb1.allApps().contains(TestUtil.DUMMY_PACKAGE));
assertTrue(cb2.allApps().contains(TestUtil.DUMMY_PACKAGE));
// Uninstall package 2
TestUtil.uninstallDummyApp();
- mModelHelper.getModel().onPackageRemoved(TestUtil.DUMMY_PACKAGE, Process.myUserHandle());
+ getCallbacks().onPackageRemoved(TestUtil.DUMMY_PACKAGE, Process.myUserHandle());
waitForLoaderAndTempMainThread();
assertFalse(cb1.allApps().contains(TestUtil.DUMMY_PACKAGE));
assertFalse(cb2.allApps().contains(TestUtil.DUMMY_PACKAGE));
@@ -142,7 +146,7 @@
// Unregister a callback and verify updates no longer received
Executors.MAIN_EXECUTOR.execute(() -> mModelHelper.getModel().removeCallbacks(cb2));
TestUtil.installDummyApp();
- mModelHelper.getModel().onPackageAdded(TestUtil.DUMMY_PACKAGE, Process.myUserHandle());
+ getCallbacks().onPackageAdded(TestUtil.DUMMY_PACKAGE, Process.myUserHandle());
waitForLoaderAndTempMainThread();
// cb2 didn't get the update
diff --git a/tests/src/com/android/launcher3/util/rule/StaticMockitoRule.java b/tests/src/com/android/launcher3/util/rule/StaticMockitoRule.java
deleted file mode 100644
index 6b91474..0000000
--- a/tests/src/com/android/launcher3/util/rule/StaticMockitoRule.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.util.rule;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-
-import com.android.dx.mockito.inline.extended.StaticMockitoSession;
-import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
-
-import org.junit.rules.MethodRule;
-import org.junit.runners.model.FrameworkMethod;
-import org.junit.runners.model.Statement;
-import org.mockito.junit.MockitoRule;
-import org.mockito.quality.Strictness;
-
-/**
- * Similar to {@link MockitoRule}, but uses {@link StaticMockitoSession}, which allows mocking
- * static methods.
- */
-public class StaticMockitoRule implements MethodRule {
- private Class<?>[] mClasses;
-
- public StaticMockitoRule(Class<?>... classes) {
- mClasses = classes;
- }
-
- @Override
- public Statement apply(Statement base, FrameworkMethod method, Object target) {
- return new Statement() {
- public void evaluate() throws Throwable {
- StaticMockitoSessionBuilder builder =
- mockitoSession()
- .name(target.getClass().getSimpleName() + "." + method.getName())
- .initMocks(target)
- .strictness(Strictness.STRICT_STUBS);
-
- for (Class<?> clazz : mClasses) {
- builder.mockStatic(clazz);
- }
-
- StaticMockitoSession session = builder.startMocking();
- Throwable testFailure = evaluateSafely(base);
- session.finishMocking(testFailure);
- if (testFailure != null) {
- throw testFailure;
- }
- }
-
- private Throwable evaluateSafely(Statement base) {
- try {
- base.evaluate();
- return null;
- } catch (Throwable throwable) {
- return throwable;
- }
- }
- };
- }
-}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index f057f56..2dbc29d 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -363,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) {
@@ -391,7 +392,7 @@
/** 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();
@@ -399,6 +400,10 @@
}
}
+ 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()) {
@@ -419,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 1a219a5..1bc489c 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -173,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);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
index 11a0cfb..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
@@ -139,4 +139,12 @@
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/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 68bf298..f68e12c 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);
}
@@ -1749,32 +1749,38 @@
final long downTime = SystemClock.uptimeMillis();
final Point start = new Point(startX, startY);
final Point end = new Point(endX, endY);
+ long endTime = downTime;
sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, start, gestureScope);
- if (mTrackpadGestureType != TrackpadGestureType.NONE) {
- sendPointer(downTime, downTime, getPointerAction(MotionEvent.ACTION_POINTER_DOWN, 1),
- start, gestureScope);
- if (mTrackpadGestureType == TrackpadGestureType.THREE_FINGER
- || mTrackpadGestureType == TrackpadGestureType.FOUR_FINGER) {
+ try {
+
+ if (mTrackpadGestureType != TrackpadGestureType.NONE) {
sendPointer(downTime, downTime,
- getPointerAction(MotionEvent.ACTION_POINTER_DOWN, 2),
+ getPointerAction(MotionEvent.ACTION_POINTER_DOWN, 1),
start, gestureScope);
- if (mTrackpadGestureType == TrackpadGestureType.FOUR_FINGER) {
+ if (mTrackpadGestureType == TrackpadGestureType.THREE_FINGER
+ || mTrackpadGestureType == TrackpadGestureType.FOUR_FINGER) {
sendPointer(downTime, downTime,
- getPointerAction(MotionEvent.ACTION_POINTER_DOWN, 3),
+ getPointerAction(MotionEvent.ACTION_POINTER_DOWN, 2),
+ start, gestureScope);
+ if (mTrackpadGestureType == TrackpadGestureType.FOUR_FINGER) {
+ sendPointer(downTime, downTime,
+ getPointerAction(MotionEvent.ACTION_POINTER_DOWN, 3),
+ start, gestureScope);
+ }
+ }
+ }
+ endTime = movePointer(
+ start, end, steps, false, downTime, downTime, slowDown, gestureScope);
+ if (mTrackpadGestureType != TrackpadGestureType.NONE) {
+ for (int i = mPointerCount; i >= 2; i--) {
+ sendPointer(downTime, downTime,
+ getPointerAction(MotionEvent.ACTION_POINTER_UP, i - 1),
start, gestureScope);
}
}
+ } finally {
+ sendPointer(downTime, endTime, MotionEvent.ACTION_UP, end, gestureScope);
}
- final long endTime = movePointer(
- start, end, steps, false, downTime, downTime, slowDown, gestureScope);
- if (mTrackpadGestureType != TrackpadGestureType.NONE) {
- for (int i = mPointerCount; i >= 2; i--) {
- sendPointer(downTime, downTime,
- getPointerAction(MotionEvent.ACTION_POINTER_UP, i - 1),
- start, gestureScope);
- }
- }
- sendPointer(downTime, endTime, MotionEvent.ACTION_UP, end, gestureScope);
}
private static int getPointerAction(int action, int index) {
@@ -2366,12 +2372,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/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/Taskbar.java b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
index a202c53..e6315f3 100644
--- a/tests/tapl/com/android/launcher3/tapl/Taskbar.java
+++ b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
@@ -153,7 +153,7 @@
return By.clazz(TextView.class).text("");
}
- private Rect getVisibleBounds() {
+ public Rect getVisibleBounds() {
return mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID).getVisibleBounds();
}