Merge "Allow translation cts can add itself into allowlist for content capture" into sc-dev
diff --git a/Android.bp b/Android.bp
index 7099291..72fc103 100644
--- a/Android.bp
+++ b/Android.bp
@@ -344,8 +344,8 @@
genrule {
name: "statslog-telephony-common-java-gen",
tools: ["stats-log-api-gen"],
- cmd: "$(location stats-log-api-gen) --java $(out) --module telephony_common"
- + " --javaPackage com.android.internal.telephony --javaClass TelephonyCommonStatsLog",
+ cmd: "$(location stats-log-api-gen) --java $(out) --module telephony_common" +
+ " --javaPackage com.android.internal.telephony --javaClass TelephonyCommonStatsLog",
out: ["com/android/internal/telephony/TelephonyCommonStatsLog.java"],
}
@@ -581,6 +581,7 @@
"android.hardware.vibrator-V1.1-java",
"android.hardware.vibrator-V1.2-java",
"android.hardware.vibrator-V1.3-java",
+ "android.hardware.vibrator-V2-java",
"android.security.apc-java",
"android.security.authorization-java",
"android.security.usermanager-java",
@@ -751,8 +752,8 @@
}
platform_compat_config {
- name: "framework-platform-compat-config",
- src: ":framework-minus-apex",
+ name: "framework-platform-compat-config",
+ src: ":framework-minus-apex",
}
// A temporary build target that is conditionally included on the bootclasspath if
@@ -773,7 +774,7 @@
name: "statslog-framework-java-gen",
tools: ["stats-log-api-gen"],
cmd: "$(location stats-log-api-gen) --java $(out) --module framework" +
- " --javaPackage com.android.internal.util --javaClass FrameworkStatsLog --worksource",
+ " --javaPackage com.android.internal.util --javaClass FrameworkStatsLog --worksource",
out: ["com/android/internal/util/FrameworkStatsLog.java"],
}
@@ -882,7 +883,7 @@
java_library {
name: "framework-annotations-lib",
- srcs: [ ":framework-annotations" ],
+ srcs: [":framework-annotations"],
sdk_version: "core_current",
}
@@ -1160,7 +1161,6 @@
},
}
-
// This is the full proto version of libplatformprotos. It may only
// be used by test code that is not shipped on the device.
cc_library {
@@ -1226,68 +1226,57 @@
path: "core/java",
}
-aidl_interface {
- name: "libincremental_aidl",
- unstable: true,
+cc_defaults {
+ name: "incremental_default",
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Wextra-semi",
+ "-Werror",
+ "-Wzero-as-null-pointer-constant",
+ "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+ aidl: {
+ include_dirs: [
+ "frameworks/native/aidl/binder",
+ ],
+ export_aidl_headers: true,
+ },
+}
+
+cc_library {
+ name: "libincremental_aidl-cpp",
srcs: [
":incremental_aidl",
],
- backend: {
- java: {
- sdk_version: "28",
- },
- cpp: {
- enabled: true,
- },
- ndk: {
- enabled: true,
- },
- },
+ defaults: ["incremental_default"],
}
-aidl_interface {
- name: "libdataloader_aidl",
- unstable: true,
+cc_library {
+ name: "libdataloader_aidl-cpp",
srcs: [
":dataloader_aidl",
],
- imports: [
- "libincremental_aidl",
+ defaults: ["incremental_default"],
+ shared_libs: [
+ "libincremental_aidl-cpp",
],
- backend: {
- java: {
- sdk_version: "28",
- },
- cpp: {
- enabled: true,
- },
- ndk: {
- enabled: false,
- },
- },
}
-aidl_interface {
- name: "libincremental_manager_aidl",
- unstable: true,
+cc_library {
+ name: "libincremental_manager_aidl-cpp",
srcs: [
":incremental_manager_aidl",
],
- imports: [
- "libincremental_aidl",
- "libdataloader_aidl",
+ defaults: ["incremental_default"],
+ shared_libs: [
+ "libincremental_aidl-cpp",
+ "libdataloader_aidl-cpp",
],
- backend: {
- java: {
- sdk_version: "28",
- },
- cpp: {
- enabled: true,
- },
- ndk: {
- enabled: false,
- },
- },
}
// TODO(b/77285514): remove this once the last few hidl interfaces have been
@@ -1316,7 +1305,7 @@
"core/java/android/os/RemoteException.java",
"core/java/android/util/AndroidException.java",
],
- libs: [ "unsupportedappusage" ],
+ libs: ["unsupportedappusage"],
dxflags: ["--core-library"],
installable: false,
@@ -1535,4 +1524,5 @@
":protolog-common-src",
],
}
+
// protolog end
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 30ed7de..175fb38 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,5 +1,6 @@
[Builtin Hooks]
clang_format = true
+bpfmt = true
[Builtin Hooks Options]
# Only turn on clang-format check for the following subfolders.
@@ -15,7 +16,7 @@
services/incremental/
tests/
tools/
-
+bpfmt = -d
[Hook Scripts]
checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
diff --git a/apex/appsearch/framework/api/current.txt b/apex/appsearch/framework/api/current.txt
index 168c7c2..5ded446 100644
--- a/apex/appsearch/framework/api/current.txt
+++ b/apex/appsearch/framework/api/current.txt
@@ -207,7 +207,6 @@
public static final class GetByUriRequest.Builder {
ctor public GetByUriRequest.Builder();
- method @NonNull public android.app.appsearch.GetByUriRequest.Builder addProjection(@NonNull String, @NonNull java.lang.String...);
method @NonNull public android.app.appsearch.GetByUriRequest.Builder addProjection(@NonNull String, @NonNull java.util.Collection<java.lang.String>);
method @NonNull public android.app.appsearch.GetByUriRequest.Builder addUris(@NonNull java.lang.String...);
method @NonNull public android.app.appsearch.GetByUriRequest.Builder addUris(@NonNull java.util.Collection<java.lang.String>);
@@ -323,7 +322,6 @@
method @NonNull public android.app.appsearch.SearchSpec.Builder addFilterPackageNames(@NonNull java.util.Collection<java.lang.String>);
method @NonNull public android.app.appsearch.SearchSpec.Builder addFilterSchemas(@NonNull java.lang.String...);
method @NonNull public android.app.appsearch.SearchSpec.Builder addFilterSchemas(@NonNull java.util.Collection<java.lang.String>);
- method @NonNull public android.app.appsearch.SearchSpec.Builder addProjection(@NonNull String, @NonNull java.lang.String...);
method @NonNull public android.app.appsearch.SearchSpec.Builder addProjection(@NonNull String, @NonNull java.util.Collection<java.lang.String>);
method @NonNull public android.app.appsearch.SearchSpec build();
method @NonNull public android.app.appsearch.SearchSpec.Builder setMaxSnippetSize(@IntRange(from=0, to=android.app.appsearch.SearchSpec.MAX_SNIPPET_SIZE_LIMIT) int);
@@ -338,7 +336,8 @@
public final class SetSchemaRequest {
method @NonNull public java.util.Map<java.lang.String,android.app.appsearch.AppSearchSchema.Migrator> getMigrators();
method @NonNull public java.util.Set<android.app.appsearch.AppSearchSchema> getSchemas();
- method @NonNull public java.util.Set<java.lang.String> getSchemasNotVisibleToSystemUi();
+ method @NonNull public java.util.Set<java.lang.String> getSchemasNotDisplayedBySystem();
+ method @Deprecated @NonNull public java.util.Set<java.lang.String> getSchemasNotVisibleToSystemUi();
method @NonNull public java.util.Map<java.lang.String,java.util.Set<android.app.appsearch.PackageIdentifier>> getSchemasVisibleToPackages();
method public boolean isForceOverride();
}
@@ -350,8 +349,9 @@
method @NonNull public android.app.appsearch.SetSchemaRequest build();
method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setForceOverride(boolean);
method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setMigrator(@NonNull String, @NonNull android.app.appsearch.AppSearchSchema.Migrator);
+ method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setSchemaTypeDisplayedBySystem(@NonNull String, boolean);
method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setSchemaTypeVisibilityForPackage(@NonNull String, boolean, @NonNull android.app.appsearch.PackageIdentifier);
- method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setSchemaTypeVisibilityForSystemUi(@NonNull String, boolean);
+ method @Deprecated @NonNull public android.app.appsearch.SetSchemaRequest.Builder setSchemaTypeVisibilityForSystemUi(@NonNull String, boolean);
}
public class SetSchemaResponse {
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
index 6a5975e..da446bf 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
@@ -317,7 +317,7 @@
getPackageName(),
DEFAULT_DATABASE_NAME,
schemaBundles,
- new ArrayList<>(request.getSchemasNotVisibleToSystemUi()),
+ new ArrayList<>(request.getSchemasNotDisplayedBySystem()),
/*schemasPackageAccessible=*/ Collections.emptyMap(),
request.isForceOverride(),
mContext.getUserId(),
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
index 24cc60e..f379739 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
@@ -146,7 +146,7 @@
mPackageName,
mDatabaseName,
schemaBundles,
- new ArrayList<>(request.getSchemasNotVisibleToSystemUi()),
+ new ArrayList<>(request.getSchemasNotDisplayedBySystem()),
schemasPackageAccessibleBundles,
request.isForceOverride(),
mUserId,
diff --git a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
index 8dd9dc1..fb63e16 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
@@ -96,7 +96,7 @@
* SetSchemaRequest.Builder#setSchemaTypeVisibilityForPackage} when building a schema.
*
* <p>Document access can also be granted to system UIs by specifying {@link
- * SetSchemaRequest.Builder#setSchemaTypeVisibilityForSystemUi} when building a schema.
+ * SetSchemaRequest.Builder#setSchemaTypeDisplayedBySystem} when building a schema.
*
* <p>See {@link AppSearchSession#search} for a detailed explanation on forming a query string.
*
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
index 68ae23f..ba27762 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
@@ -33,7 +33,7 @@
* @param packageName The name of the package that owns this schema.
* @param databaseName The name of the database where this schema lives.
* @param schemaBundles List of {@link AppSearchSchema} bundles.
- * @param schemasNotPlatformSurfaceable Schema types that should not be surfaced on platform
+ * @param schemasNotDisplayedBySystem Schema types that should not be surfaced on platform
* surfaces.
* @param schemasPackageAccessibleBundles Schema types that are visible to the specified
* packages. The value List contains PackageIdentifier Bundles.
@@ -47,7 +47,7 @@
in String packageName,
in String databaseName,
in List<Bundle> schemaBundles,
- in List<String> schemasNotPlatformSurfaceable,
+ in List<String> schemasNotDisplayedBySystem,
in Map<String, List<Bundle>> schemasPackageAccessibleBundles,
boolean forceOverride,
in int userId,
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java
index c927e34..17266f8 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java
@@ -166,29 +166,7 @@
* all results, excepting any types that have their own, specific property paths set.
*
* @throws IllegalStateException if the builder has already been used.
- * <p>{@see SearchSpec.Builder#addProjection(String, String...)}
- */
- @NonNull
- public Builder addProjection(@NonNull String schemaType, @NonNull String... propertyPaths) {
- Preconditions.checkNotNull(propertyPaths);
- return addProjection(schemaType, Arrays.asList(propertyPaths));
- }
-
- /**
- * Adds property paths for the specified type to be used for projection. If property paths
- * are added for a type, then only the properties referred to will be retrieved for results
- * of that type. If a property path that is specified isn't present in a result, it will be
- * ignored for that result. Property paths cannot be null.
- *
- * <p>If no property paths are added for a particular type, then all properties of results
- * of that type will be retrieved.
- *
- * <p>If property path is added for the {@link
- * GetByUriRequest#PROJECTION_SCHEMA_TYPE_WILDCARD}, then those property paths will apply to
- * all results, excepting any types that have their own, specific property paths set.
- *
- * @throws IllegalStateException if the builder has already been used.
- * <p>{@see SearchSpec.Builder#addProjection(String, String...)}
+ * @see SearchSpec.Builder#addProjection
*/
@NonNull
public Builder addProjection(
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
index d792f45..f34034b 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
@@ -202,14 +202,6 @@
*/
public static final String PROPERTY_PATH_FIELD = "propertyPath";
- /**
- * The index of matching value in its property. A property may have multiple values. This
- * index indicates which value is the match.
- *
- * @hide
- */
- public static final String VALUES_INDEX_FIELD = "valuesIndex";
-
/** @hide */
public static final String EXACT_MATCH_POSITION_LOWER_FIELD = "exactMatchPositionLower";
@@ -232,8 +224,7 @@
mBundle = Preconditions.checkNotNull(bundle);
Preconditions.checkNotNull(document);
mPropertyPath = Preconditions.checkNotNull(bundle.getString(PROPERTY_PATH_FIELD));
- mFullText =
- getPropertyValues(document, mPropertyPath, mBundle.getInt(VALUES_INDEX_FIELD));
+ mFullText = getPropertyValues(document, mPropertyPath);
}
/**
@@ -326,8 +317,7 @@
}
/** Extracts the matching string from the document. */
- private static String getPropertyValues(
- GenericDocument document, String propertyName, int valueIndex) {
+ private static String getPropertyValues(GenericDocument document, String propertyName) {
// In IcingLib snippeting is available for only 3 data types i.e String, double and
// long, so we need to check which of these three are requested.
// TODO (tytytyww): getPropertyStringArray takes property name, handle for property
@@ -337,7 +327,9 @@
if (values == null) {
throw new IllegalStateException("No content found for requested property path!");
}
- return values[valueIndex];
+
+ // TODO(b/175146044): Return the proper match based on the index in the propertyName.
+ return values[0];
}
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
index f72f8e1..7888c8d 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
@@ -535,28 +535,6 @@
*/
@NonNull
public SearchSpec.Builder addProjection(
- @NonNull String schema, @NonNull String... propertyPaths) {
- Preconditions.checkNotNull(propertyPaths);
- return addProjection(schema, Arrays.asList(propertyPaths));
- }
-
- /**
- * Adds property paths for the specified type to be used for projection. If property paths
- * are added for a type, then only the properties referred to will be retrieved for results
- * of that type. If a property path that is specified isn't present in a result, it will be
- * ignored for that result. Property paths cannot be null.
- *
- * <p>If no property paths are added for a particular type, then all properties of results
- * of that type will be retrieved.
- *
- * <p>If property path is added for the {@link SearchSpec#PROJECTION_SCHEMA_TYPE_WILDCARD},
- * then those property paths will apply to all results, excepting any types that have their
- * own, specific property paths set.
- *
- * <p>{@see SearchSpec.Builder#addProjection(String, String...)}
- */
- @NonNull
- public SearchSpec.Builder addProjection(
@NonNull String schema, @NonNull Collection<String> propertyPaths) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Preconditions.checkNotNull(schema);
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
index 426a903..c054063 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
@@ -71,19 +71,19 @@
*/
public final class SetSchemaRequest {
private final Set<AppSearchSchema> mSchemas;
- private final Set<String> mSchemasNotVisibleToSystemUi;
+ private final Set<String> mSchemasNotDisplayedBySystem;
private final Map<String, Set<PackageIdentifier>> mSchemasVisibleToPackages;
private final Map<String, AppSearchSchema.Migrator> mMigrators;
private final boolean mForceOverride;
SetSchemaRequest(
@NonNull Set<AppSearchSchema> schemas,
- @NonNull Set<String> schemasNotVisibleToSystemUi,
+ @NonNull Set<String> schemasNotDisplayedBySystem,
@NonNull Map<String, Set<PackageIdentifier>> schemasVisibleToPackages,
@NonNull Map<String, AppSearchSchema.Migrator> migrators,
boolean forceOverride) {
mSchemas = Preconditions.checkNotNull(schemas);
- mSchemasNotVisibleToSystemUi = Preconditions.checkNotNull(schemasNotVisibleToSystemUi);
+ mSchemasNotDisplayedBySystem = Preconditions.checkNotNull(schemasNotDisplayedBySystem);
mSchemasVisibleToPackages = Preconditions.checkNotNull(schemasVisibleToPackages);
mMigrators = Preconditions.checkNotNull(migrators);
mForceOverride = forceOverride;
@@ -96,12 +96,22 @@
}
/**
+ * TODO(b/181887768): This method exists only for dogfooder transition and must be removed.
+ * @deprecated This method exists only for dogfooder transition and must be removed.
+ */
+ @Deprecated
+ @NonNull
+ public Set<String> getSchemasNotVisibleToSystemUi() {
+ return getSchemasNotDisplayedBySystem();
+ }
+
+ /**
* Returns all the schema types that are opted out of being displayed and visible on any system
* UI surface.
*/
@NonNull
- public Set<String> getSchemasNotVisibleToSystemUi() {
- return Collections.unmodifiableSet(mSchemasNotVisibleToSystemUi);
+ public Set<String> getSchemasNotDisplayedBySystem() {
+ return Collections.unmodifiableSet(mSchemasNotDisplayedBySystem);
}
/**
@@ -151,7 +161,7 @@
*/
public static final class Builder {
private final Set<AppSearchSchema> mSchemas = new ArraySet<>();
- private final Set<String> mSchemasNotVisibleToSystemUi = new ArraySet<>();
+ private final Set<String> mSchemasNotDisplayedBySystem = new ArraySet<>();
private final Map<String, Set<PackageIdentifier>> mSchemasVisibleToPackages =
new ArrayMap<>();
private final Map<String, AppSearchSchema.Migrator> mMigrators = new ArrayMap<>();
@@ -163,6 +173,8 @@
*
* <p>An {@link AppSearchSchema} object represents one type of structured data.
*
+ * <p>Any documents of these types will be displayed on system UI surfaces by default.
+ *
* @throws IllegalStateException if the builder has already been used.
*/
@NonNull
@@ -187,30 +199,43 @@
}
/**
+ * TODO(b/181887768): This method exists only for dogfooder transition and must be removed.
+ * @deprecated This method exists only for dogfooder transition and must be removed.
+ */
+ @Deprecated
+ @NonNull
+ public Builder setSchemaTypeVisibilityForSystemUi(
+ @NonNull String schemaType, boolean displayed) {
+ return setSchemaTypeDisplayedBySystem(schemaType, displayed);
+ }
+
+ /**
* Sets whether or not documents from the provided {@code schemaType} will be displayed and
* visible on any system UI surface.
*
* <p>This setting applies to the provided {@code schemaType} only, and does not persist
* across {@link AppSearchSession#setSchema} calls.
*
- * <p>By default, documents are displayed and visible on system UI surfaces.
+ * <p>The default behavior, if this method is not called, is to allow types to be displayed
+ * on system UI surfaces.
*
- * @param schemaType The schema type to set visibility on.
- * @param visible Whether the {@code schemaType} will be visible or not.
+ * @param schemaType The name of an {@link AppSearchSchema} within the same {@link
+ * SetSchemaRequest}, which will be configured.
+ * @param displayed Whether documents of this type will be displayed on system UI surfaces.
* @throws IllegalStateException if the builder has already been used.
*/
- // Merged list available from getSchemasNotVisibleToSystemUi
+ // Merged list available from getSchemasNotDisplayedBySystem
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
- public Builder setSchemaTypeVisibilityForSystemUi(
- @NonNull String schemaType, boolean visible) {
+ public Builder setSchemaTypeDisplayedBySystem(
+ @NonNull String schemaType, boolean displayed) {
Preconditions.checkNotNull(schemaType);
Preconditions.checkState(!mBuilt, "Builder has already been used");
- if (visible) {
- mSchemasNotVisibleToSystemUi.remove(schemaType);
+ if (displayed) {
+ mSchemasNotDisplayedBySystem.remove(schemaType);
} else {
- mSchemasNotVisibleToSystemUi.add(schemaType);
+ mSchemasNotDisplayedBySystem.add(schemaType);
}
return this;
}
@@ -315,9 +340,10 @@
Preconditions.checkState(!mBuilt, "Builder has already been used");
mBuilt = true;
- // Verify that any schema types with visibility settings refer to a real schema.
+ // Verify that any schema types with display or visibility settings refer to a real
+ // schema.
// Create a copy because we're going to remove from the set for verification purposes.
- Set<String> referencedSchemas = new ArraySet<>(mSchemasNotVisibleToSystemUi);
+ Set<String> referencedSchemas = new ArraySet<>(mSchemasNotDisplayedBySystem);
referencedSchemas.addAll(mSchemasVisibleToPackages.keySet());
for (AppSearchSchema schema : mSchemas) {
@@ -332,7 +358,7 @@
return new SetSchemaRequest(
mSchemas,
- mSchemasNotVisibleToSystemUi,
+ mSchemasNotDisplayedBySystem,
mSchemasVisibleToPackages,
mMigrators,
mForceOverride);
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index a45fa39..27c9ccb 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -89,7 +89,7 @@
@NonNull String packageName,
@NonNull String databaseName,
@NonNull List<Bundle> schemaBundles,
- @NonNull List<String> schemasNotPlatformSurfaceable,
+ @NonNull List<String> schemasNotDisplayedBySystem,
@NonNull Map<String, List<Bundle>> schemasPackageAccessibleBundles,
boolean forceOverride,
@UserIdInt int userId,
@@ -119,13 +119,12 @@
}
schemasPackageAccessible.put(entry.getKey(), packageIdentifiers);
}
- AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+ AppSearchImpl impl = mImplInstanceManager.getAppSearchImpl(callingUserId);
impl.setSchema(
packageName,
databaseName,
schemas,
- schemasNotPlatformSurfaceable,
+ schemasNotDisplayedBySystem,
schemasPackageAccessible,
forceOverride);
invokeCallbackOnResult(
@@ -153,7 +152,7 @@
verifyUserUnlocked(callingUserId);
verifyCallingPackage(callingUid, packageName);
AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
List<AppSearchSchema> schemas = impl.getSchema(packageName, databaseName);
List<Bundle> schemaBundles = new ArrayList<>(schemas.size());
for (int i = 0; i < schemas.size(); i++) {
@@ -188,7 +187,7 @@
AppSearchBatchResult.Builder<String, Void> resultBuilder =
new AppSearchBatchResult.Builder<>();
AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
for (int i = 0; i < documentBundles.size(); i++) {
GenericDocument document = new GenericDocument(documentBundles.get(i));
try {
@@ -231,7 +230,7 @@
AppSearchBatchResult.Builder<String, Bundle> resultBuilder =
new AppSearchBatchResult.Builder<>();
AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
for (int i = 0; i < uris.size(); i++) {
String uri = uris.get(i);
try {
@@ -276,7 +275,7 @@
verifyUserUnlocked(callingUserId);
verifyCallingPackage(callingUid, packageName);
AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
SearchResultPage searchResultPage =
impl.query(
packageName,
@@ -311,7 +310,7 @@
verifyUserUnlocked(callingUserId);
verifyCallingPackage(callingUid, packageName);
AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
SearchResultPage searchResultPage =
impl.globalQuery(
queryExpression,
@@ -342,7 +341,7 @@
try {
verifyUserUnlocked(callingUserId);
AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
SearchResultPage searchResultPage = impl.getNextPage(nextPageToken);
invokeCallbackOnResult(
callback,
@@ -362,7 +361,7 @@
try {
verifyUserUnlocked(callingUserId);
AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
impl.invalidateNextPageToken(nextPageToken);
} catch (Throwable t) {
Log.e(TAG, "Unable to invalidate the query page token", t);
@@ -390,7 +389,7 @@
try {
verifyUserUnlocked(callingUserId);
AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
impl.reportUsage(packageName, databaseName, namespace, uri, usageTimeMillis);
invokeCallbackOnResult(
callback, AppSearchResult.newSuccessfulResult(/*result=*/ null));
@@ -422,7 +421,7 @@
AppSearchBatchResult.Builder<String, Void> resultBuilder =
new AppSearchBatchResult.Builder<>();
AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
for (int i = 0; i < uris.size(); i++) {
String uri = uris.get(i);
try {
@@ -460,7 +459,7 @@
verifyUserUnlocked(callingUserId);
verifyCallingPackage(callingUid, packageName);
AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
impl.removeByQuery(
packageName,
databaseName,
@@ -482,7 +481,7 @@
try {
verifyUserUnlocked(callingUserId);
AppSearchImpl impl =
- mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+ mImplInstanceManager.getAppSearchImpl(callingUserId);
impl.persistToDisk();
} catch (Throwable t) {
Log.e(TAG, "Unable to persist the data to disk", t);
@@ -499,7 +498,7 @@
final long callingIdentity = Binder.clearCallingIdentity();
try {
verifyUserUnlocked(callingUserId);
- mImplInstanceManager.getAppSearchImpl(getContext(), callingUserId);
+ mImplInstanceManager.getOrCreateAppSearchImpl(getContext(), callingUserId);
invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
} catch (Throwable t) {
invokeCallbackOnError(callback, t);
@@ -571,6 +570,7 @@
private void invokeCallbackOnError(
IAppSearchBatchResultCallback callback, Throwable throwable) {
try {
+ //TODO(b/175067650) verify ParcelableException could propagate throwable correctly.
callback.onSystemError(new ParcelableException(throwable));
} catch (RemoteException e) {
Log.e(TAG, "Unable to send error to the callback", e);
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
index 82319d4..8c953d1 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
@@ -74,7 +74,7 @@
}
/**
- * Gets an instance of AppSearchImpl for the given user.
+ * Gets an instance of AppSearchImpl for the given user, or creates one if none exists.
*
* <p>If no AppSearchImpl instance exists for the unlocked user, Icing will be initialized and
* one will be created.
@@ -84,7 +84,7 @@
* @return An initialized {@link AppSearchImpl} for this user
*/
@NonNull
- public AppSearchImpl getAppSearchImpl(
+ public AppSearchImpl getOrCreateAppSearchImpl(
@NonNull Context context, @UserIdInt int userId) throws AppSearchException {
synchronized (mInstancesLocked) {
AppSearchImpl instance = mInstancesLocked.get(userId);
@@ -96,6 +96,32 @@
}
}
+
+ /**
+ * Gets an instance of AppSearchImpl for the given user.
+ *
+ * <p>This method should only be called by an initialized SearchSession, which has been already
+ * created the AppSearchImpl instance for the given user.
+ *
+ * @param userId The multi-user userId of the device user calling AppSearch
+ * @return An initialized {@link AppSearchImpl} for this user
+ * @throws IllegalStateException if {@link AppSearchImpl} haven't created for the given user.
+ */
+ @NonNull
+ public AppSearchImpl getAppSearchImpl(@UserIdInt int userId) {
+ synchronized (mInstancesLocked) {
+ AppSearchImpl instance = mInstancesLocked.get(userId);
+ if (instance == null) {
+ // Impossible scenario, user cannot call an uninitialized SearchSession,
+ // getInstance should always find the instance for the given user and never try to
+ // create an instance for this user again.
+ throw new IllegalStateException(
+ "AppSearchImpl has never been created for this user: " + userId);
+ }
+ return instance;
+ }
+ }
+
private AppSearchImpl createImpl(@NonNull Context context, @UserIdInt int userId)
throws AppSearchException {
File appSearchDir = getAppSearchDir(context, userId);
@@ -104,6 +130,7 @@
private static File getAppSearchDir(@NonNull Context context, @UserIdInt int userId) {
// See com.android.internal.app.ChooserActivity::getPinnedSharedPrefs
+ //TODO(b/177685938):Switch from getDataUserCePackageDirectory to getDataSystemCeDirectory
File userCeDir =
Environment.getDataUserCePackageDirectory(
StorageManager.UUID_PRIVATE_INTERNAL, userId, context.getPackageName());
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
index f422ebc..e9852aa 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
@@ -113,8 +113,6 @@
Bundle bundle = new Bundle();
bundle.putString(SearchResult.MatchInfo.PROPERTY_PATH_FIELD, propertyPath);
bundle.putInt(
- SearchResult.MatchInfo.VALUES_INDEX_FIELD, snippetMatchProto.getValuesIndex());
- bundle.putInt(
SearchResult.MatchInfo.EXACT_MATCH_POSITION_LOWER_FIELD,
snippetMatchProto.getExactMatchPosition());
bundle.putInt(
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index 2c9477a..41c70f0 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-I593dfd22279739e5f578e07d36a55cf02ee942c5
+I42b89416968565ceb6483b400894f5b49524208c
diff --git a/apex/appsearch/testing/Android.bp b/apex/appsearch/testing/Android.bp
index eb072af..3c5082e 100644
--- a/apex/appsearch/testing/Android.bp
+++ b/apex/appsearch/testing/Android.bp
@@ -30,5 +30,8 @@
"guava",
"truth-prebuilt",
],
- visibility: ["//cts/tests/appsearch"],
+ visibility: [
+ "//cts/tests/appsearch",
+ "//vendor:__subpackages__",
+ ],
}
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java
index d912c08..440050f 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/GlobalSearchSessionShim.java
@@ -34,8 +34,8 @@
* SetSchemaRequest.Builder#setDocumentClassVisibilityForPackage} when building a schema.
*
* <p>Document access can also be granted to system UIs by specifying {@link
- * SetSchemaRequest.Builder#setSchemaTypeVisibilityForSystemUi}, or {@link
- * SetSchemaRequest.Builder#setDocumentClassVisibilityForSystemUi} when building a schema.
+ * SetSchemaRequest.Builder#setSchemaTypeDisplayedBySystem}, or {@link
+ * SetSchemaRequest.Builder#setDocumentClassDisplayedBySystem} when building a schema.
*
* <p>See {@link AppSearchSessionShim#search} for a detailed explanation on forming a query
* string.
diff --git a/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java b/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java
index 5e5717d11..0dde546 100644
--- a/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java
@@ -32,12 +32,8 @@
void exitIdle(String reason);
- // duration in milliseconds
void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
- long duration, int userId, boolean sync, String reason);
-
- void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
- long duration, int userId, boolean sync, @ReasonCode int reasonCode,
+ long durationMs, int userId, boolean sync, @ReasonCode int reasonCode,
@Nullable String reason);
/**
@@ -49,10 +45,11 @@
* @param sync
* @param reasonCode one of {@link ReasonCode}
* @param reason
+ * @param callingUid UID of app who added this temp-allowlist.
*/
void addPowerSaveTempWhitelistAppDirect(int uid, long duration,
@TempAllowListType int type, boolean sync, @ReasonCode int reasonCode,
- @Nullable String reason);
+ @Nullable String reason, int callingUid);
// duration in milliseconds
long getNotificationAllowlistDuration();
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index ac28e82..84fb39b 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -1943,19 +1943,11 @@
}
// duration in milliseconds
- @Deprecated
@Override
public void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
- long duration, int userId, boolean sync, @Nullable String reason) {
- addPowerSaveTempAllowlistAppInternal(callingUid, packageName, duration,
- userId, sync, REASON_UNKNOWN, reason);
- }
-
- @Override
- public void addPowerSaveTempWhitelistApp(int callingUid, String packageName,
- long duration, int userId, boolean sync, @ReasonCode int reasonCode,
+ long durationMs, int userId, boolean sync, @ReasonCode int reasonCode,
@Nullable String reason) {
- addPowerSaveTempAllowlistAppInternal(callingUid, packageName, duration,
+ addPowerSaveTempAllowlistAppInternal(callingUid, packageName, durationMs,
userId, sync, reasonCode, reason);
}
@@ -1963,8 +1955,8 @@
@Override
public void addPowerSaveTempWhitelistAppDirect(int uid, long duration,
@TempAllowListType int type, boolean sync, @ReasonCode int reasonCode,
- @Nullable String reason) {
- addPowerSaveTempWhitelistAppDirectInternal(0, uid, duration, type, sync,
+ @Nullable String reason, int callingUid) {
+ addPowerSaveTempWhitelistAppDirectInternal(callingUid, uid, duration, type, sync,
reasonCode, reason);
}
@@ -2741,6 +2733,16 @@
void addPowerSaveTempAllowlistAppInternal(int callingUid, String packageName,
long duration, int userId, boolean sync, @ReasonCode int reasonCode,
@Nullable String reason) {
+ synchronized (this) {
+ int callingAppId = UserHandle.getAppId(callingUid);
+ if (callingAppId >= Process.FIRST_APPLICATION_UID) {
+ if (!mPowerSaveWhitelistSystemAppIds.get(callingAppId)) {
+ throw new SecurityException(
+ "Calling app " + UserHandle.formatUid(callingUid)
+ + " is not on whitelist");
+ }
+ }
+ }
try {
int uid = getContext().getPackageManager().getPackageUidAsUser(packageName, userId);
addPowerSaveTempWhitelistAppDirectInternal(callingUid, uid, duration,
@@ -2760,13 +2762,6 @@
boolean informWhitelistChanged = false;
int appId = UserHandle.getAppId(uid);
synchronized (this) {
- int callingAppId = UserHandle.getAppId(callingUid);
- if (callingAppId >= Process.FIRST_APPLICATION_UID) {
- if (!mPowerSaveWhitelistSystemAppIds.get(callingAppId)) {
- throw new SecurityException("Calling app " + UserHandle.formatUid(callingUid)
- + " is not on whitelist");
- }
- }
duration = Math.min(duration, mConstants.MAX_TEMP_APP_ALLOWLIST_DURATION_MS);
Pair<MutableLong, String> entry = mTempWhitelistAppIdEndTimes.get(appId);
final boolean newEntry = entry == null;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobCompletedListener.java b/apex/jobscheduler/service/java/com/android/server/job/JobCompletedListener.java
index 34ba753b3..862d8b7 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobCompletedListener.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobCompletedListener.java
@@ -25,7 +25,9 @@
public interface JobCompletedListener {
/**
* Callback for when a job is completed.
+ *
+ * @param stopReason The stop reason provided to JobParameters.
* @param needsReschedule Whether the implementing class should reschedule this job.
*/
- void onJobCompletedLocked(JobStatus jobStatus, boolean needsReschedule);
+ void onJobCompletedLocked(JobStatus jobStatus, int stopReason, boolean needsReschedule);
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index 0308d68..b958c3f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -25,6 +25,7 @@
import android.app.ActivityManagerInternal;
import android.app.UserSwitchObserver;
import android.app.job.JobInfo;
+import android.app.job.JobParameters;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -102,13 +103,18 @@
*/
static final int WORK_TYPE_BG = 1 << 3;
/**
+ * The job is for an app in a {@link ActivityManager#PROCESS_STATE_FOREGROUND_SERVICE} or higher
+ * state, or is allowed to run as an expedited job, but is for a completely background user.
+ */
+ static final int WORK_TYPE_BGUSER_IMPORTANT = 1 << 4;
+ /**
* The job does not satisfy any of the conditions for {@link #WORK_TYPE_TOP},
* {@link #WORK_TYPE_FGS}, or {@link #WORK_TYPE_EJ}, but is for a completely background user,
* so can run as a background user job.
*/
- static final int WORK_TYPE_BGUSER = 1 << 4;
+ static final int WORK_TYPE_BGUSER = 1 << 5;
@VisibleForTesting
- static final int NUM_WORK_TYPES = 5;
+ static final int NUM_WORK_TYPES = 6;
private static final int ALL_WORK_TYPES = (1 << NUM_WORK_TYPES) - 1;
@IntDef(prefix = {"WORK_TYPE_"}, flag = true, value = {
@@ -117,6 +123,7 @@
WORK_TYPE_FGS,
WORK_TYPE_EJ,
WORK_TYPE_BG,
+ WORK_TYPE_BGUSER_IMPORTANT,
WORK_TYPE_BGUSER
})
@Retention(RetentionPolicy.SOURCE)
@@ -138,6 +145,8 @@
return "BG";
case WORK_TYPE_BGUSER:
return "BGUSER";
+ case WORK_TYPE_BGUSER_IMPORTANT:
+ return "BGUSER_IMPORTANT";
default:
return "WORK(" + workType + ")";
}
@@ -163,30 +172,40 @@
new WorkTypeConfig("screen_on_normal", 11,
// defaultMin
List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_FGS, 1),
- Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2)),
+ Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 6), Pair.create(WORK_TYPE_BGUSER, 4))
+ List.of(Pair.create(WORK_TYPE_BG, 6),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 2),
+ Pair.create(WORK_TYPE_BGUSER, 3))
),
new WorkTypeConfig("screen_on_moderate", 9,
// defaultMin
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
- Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2)),
+ Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 1),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2))
+ List.of(Pair.create(WORK_TYPE_BG, 4),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1),
+ Pair.create(WORK_TYPE_BGUSER, 1))
),
new WorkTypeConfig("screen_on_low", 6,
// defaultMin
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
Pair.create(WORK_TYPE_EJ, 1)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
+ List.of(Pair.create(WORK_TYPE_BG, 1),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1),
+ Pair.create(WORK_TYPE_BGUSER, 1))
),
new WorkTypeConfig("screen_on_critical", 6,
// defaultMin
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
Pair.create(WORK_TYPE_EJ, 1)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
+ List.of(Pair.create(WORK_TYPE_BG, 1),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1),
+ Pair.create(WORK_TYPE_BGUSER, 1))
)
);
private static final WorkConfigLimitsPerMemoryTrimLevel CONFIG_LIMITS_SCREEN_OFF =
@@ -194,30 +213,40 @@
new WorkTypeConfig("screen_off_normal", 15,
// defaultMin
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 2),
- Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2)),
+ Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 6), Pair.create(WORK_TYPE_BGUSER, 4))
+ List.of(Pair.create(WORK_TYPE_BG, 6),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 2),
+ Pair.create(WORK_TYPE_BGUSER, 3))
),
new WorkTypeConfig("screen_off_moderate", 15,
// defaultMin
List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_FGS, 2),
- Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2)),
+ Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2))
+ List.of(Pair.create(WORK_TYPE_BG, 4),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1),
+ Pair.create(WORK_TYPE_BGUSER, 1))
),
new WorkTypeConfig("screen_off_low", 9,
// defaultMin
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 1)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
+ List.of(Pair.create(WORK_TYPE_BG, 1),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1),
+ Pair.create(WORK_TYPE_BGUSER, 1))
),
new WorkTypeConfig("screen_off_critical", 6,
// defaultMin
List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1),
Pair.create(WORK_TYPE_EJ, 1)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
+ List.of(Pair.create(WORK_TYPE_BG, 1),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1),
+ Pair.create(WORK_TYPE_BGUSER, 1))
)
);
@@ -288,6 +317,8 @@
final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
+ filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
+ filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
mContext.registerReceiver(mReceiver, filter);
try {
ActivityManager.getService().registerUserSwitchObserver(mGracePeriodObserver, TAG);
@@ -311,6 +342,20 @@
case Intent.ACTION_SCREEN_OFF:
onInteractiveStateChanged(false);
break;
+ case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED:
+ if (mPowerManager != null && mPowerManager.isDeviceIdleMode()) {
+ synchronized (mLock) {
+ stopLongRunningJobsLocked("deep doze");
+ }
+ }
+ break;
+ case PowerManager.ACTION_POWER_SAVE_MODE_CHANGED:
+ if (mPowerManager != null && mPowerManager.isPowerSaveMode()) {
+ synchronized (mLock) {
+ stopLongRunningJobsLocked("battery saver");
+ }
+ }
+ break;
}
}
};
@@ -469,7 +514,7 @@
// Update the priorities of jobs that aren't running, and also count the pending work types.
// Do this before the following loop to hopefully reduce the cost of
// shouldStopRunningJobLocked().
- updateNonRunningPriorities(pendingJobs, true);
+ updateNonRunningPrioritiesLocked(pendingJobs, true);
for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
final JobServiceContext js = activeServices.get(i);
@@ -585,7 +630,8 @@
+ activeServices.get(i).getRunningJobLocked());
}
// preferredUid will be set to uid of currently running job.
- activeServices.get(i).preemptExecutingJobLocked(preemptReasonForContext[i]);
+ activeServices.get(i).cancelExecutingJobLocked(
+ JobParameters.REASON_PREEMPT, preemptReasonForContext[i]);
preservePreferredUid = true;
} else {
final JobStatus pendingJob = contextIdToJobMap[i];
@@ -604,13 +650,26 @@
noteConcurrency();
}
+ @GuardedBy("mLock")
+ private void stopLongRunningJobsLocked(@NonNull String debugReason) {
+ for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; ++i) {
+ final JobServiceContext jsc = mService.mActiveServices.get(i);
+ final JobStatus jobStatus = jsc.getRunningJobLocked();
+
+ if (jobStatus != null && !jsc.isWithinExecutionGuaranteeTime()) {
+ jsc.cancelExecutingJobLocked(JobParameters.REASON_TIMEOUT, debugReason);
+ }
+ }
+ }
+
private void noteConcurrency() {
mService.mJobPackageTracker.noteConcurrency(mRunningJobs.size(),
// TODO: log per type instead of only TOP
mWorkCountTracker.getRunningJobCount(WORK_TYPE_TOP));
}
- private void updateNonRunningPriorities(@NonNull final List<JobStatus> pendingJobs,
+ @GuardedBy("mLock")
+ private void updateNonRunningPrioritiesLocked(@NonNull final List<JobStatus> pendingJobs,
boolean updateCounter) {
for (int i = 0; i < pendingJobs.size(); i++) {
final JobStatus pending = pendingJobs.get(i);
@@ -628,6 +687,7 @@
}
}
+ @GuardedBy("mLock")
private void startJobLocked(@NonNull JobServiceContext worker, @NonNull JobStatus jobStatus,
@WorkType final int workType) {
final List<StateController> controllers = mService.mControllers;
@@ -647,6 +707,7 @@
}
}
+ @GuardedBy("mLock")
void onJobCompletedLocked(@NonNull JobServiceContext worker, @NonNull JobStatus jobStatus,
@WorkType final int workType) {
mWorkCountTracker.onJobFinished(workType);
@@ -655,7 +716,7 @@
if (worker.getPreferredUid() != JobServiceContext.NO_PREFERRED_UID) {
updateCounterConfigLocked();
// Preemption case needs special care.
- updateNonRunningPriorities(pendingJobs, false);
+ updateNonRunningPrioritiesLocked(pendingJobs, false);
JobStatus highestPriorityJob = null;
int highPriWorkType = workType;
@@ -726,7 +787,7 @@
}
} else if (pendingJobs.size() > 0) {
updateCounterConfigLocked();
- updateNonRunningPriorities(pendingJobs, false);
+ updateNonRunningPrioritiesLocked(pendingJobs, false);
// This slot is now free and we have pending jobs. Start the highest priority job we
// find.
@@ -775,6 +836,7 @@
* another job to run, or if system state suggests the job should stop.
*/
@Nullable
+ @GuardedBy("mLock")
String shouldStopRunningJobLocked(@NonNull JobServiceContext context) {
final JobStatus js = context.getRunningJobLocked();
if (js == null) {
@@ -817,17 +879,22 @@
// Only expedited jobs can replace expedited jobs.
if (js.shouldTreatAsExpeditedJob()) {
// Keep fg/bg user distinction.
- if (workType == WORK_TYPE_BGUSER) {
- // For now, let any bg user job replace a bg user expedited job.
- // TODO: limit to ej once we have dedicated bg user ej slots.
- if (mWorkCountTracker.getPendingJobCount(WORK_TYPE_BGUSER) > 0) {
- return "blocking " + workTypeToString(workType) + " queue";
+ if (workType == WORK_TYPE_BGUSER_IMPORTANT || workType == WORK_TYPE_BGUSER) {
+ // Let any important bg user job replace a bg user expedited job.
+ if (mWorkCountTracker.getPendingJobCount(WORK_TYPE_BGUSER_IMPORTANT) > 0) {
+ return "blocking " + workTypeToString(WORK_TYPE_BGUSER_IMPORTANT) + " queue";
}
- } else {
- if (mWorkCountTracker.getPendingJobCount(WORK_TYPE_EJ) > 0) {
- return "blocking " + workTypeToString(workType) + " queue";
+ // Let a fg user EJ preempt a bg user EJ (if able), but not the other way around.
+ if (mWorkCountTracker.getPendingJobCount(WORK_TYPE_EJ) > 0
+ && mWorkCountTracker.canJobStart(WORK_TYPE_EJ, workType)
+ != WORK_TYPE_NONE) {
+ return "blocking " + workTypeToString(WORK_TYPE_EJ) + " queue";
}
+ } else if (mWorkCountTracker.getPendingJobCount(WORK_TYPE_EJ) > 0) {
+ return "blocking " + workTypeToString(WORK_TYPE_EJ) + " queue";
}
+ // No other pending EJs. Return null so we don't let regular jobs preempt an EJ.
+ return null;
}
// Easy check. If there are pending jobs of the same work type, then we know that
@@ -881,6 +948,7 @@
return s.toString();
}
+ @GuardedBy("mLock")
void updateConfigLocked() {
DeviceConfig.Properties properties =
DeviceConfig.getProperties(DeviceConfig.NAMESPACE_JOB_SCHEDULER);
@@ -1010,6 +1078,7 @@
int getJobWorkTypes(@NonNull JobStatus js) {
int classification = 0;
+
if (shouldRunAsFgUserJob(js)) {
if (js.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
classification |= WORK_TYPE_TOP;
@@ -1023,7 +1092,11 @@
classification |= WORK_TYPE_EJ;
}
} else {
- // TODO(171305774): create dedicated slots for EJs of bg user
+ if (js.lastEvaluatedPriority >= JobInfo.PRIORITY_FOREGROUND_SERVICE
+ || js.shouldTreatAsExpeditedJob()) {
+ classification |= WORK_TYPE_BGUSER_IMPORTANT;
+ }
+ // BGUSER_IMPORTANT jobs can also run as BGUSER jobs, so not an 'else' here.
classification |= WORK_TYPE_BGUSER;
}
@@ -1040,12 +1113,16 @@
private static final String KEY_PREFIX_MAX_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "max_bg_";
private static final String KEY_PREFIX_MAX_BGUSER =
CONFIG_KEY_PREFIX_CONCURRENCY + "max_bguser_";
+ private static final String KEY_PREFIX_MAX_BGUSER_IMPORTANT =
+ CONFIG_KEY_PREFIX_CONCURRENCY + "max_bguser_important_";
private static final String KEY_PREFIX_MIN_TOP = CONFIG_KEY_PREFIX_CONCURRENCY + "min_top_";
private static final String KEY_PREFIX_MIN_FGS = CONFIG_KEY_PREFIX_CONCURRENCY + "min_fgs_";
private static final String KEY_PREFIX_MIN_EJ = CONFIG_KEY_PREFIX_CONCURRENCY + "min_ej_";
private static final String KEY_PREFIX_MIN_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "min_bg_";
private static final String KEY_PREFIX_MIN_BGUSER =
CONFIG_KEY_PREFIX_CONCURRENCY + "min_bguser_";
+ private static final String KEY_PREFIX_MIN_BGUSER_IMPORTANT =
+ CONFIG_KEY_PREFIX_CONCURRENCY + "min_bguser_important_";
private final String mConfigIdentifier;
private int mMaxTotal;
@@ -1101,6 +1178,10 @@
properties.getInt(KEY_PREFIX_MAX_BG + mConfigIdentifier,
mDefaultMaxAllowedSlots.get(WORK_TYPE_BG, mMaxTotal))));
mMaxAllowedSlots.put(WORK_TYPE_BG, maxBg);
+ final int maxBgUserImp = Math.max(1, Math.min(mMaxTotal,
+ properties.getInt(KEY_PREFIX_MAX_BGUSER_IMPORTANT + mConfigIdentifier,
+ mDefaultMaxAllowedSlots.get(WORK_TYPE_BGUSER_IMPORTANT, mMaxTotal))));
+ mMaxAllowedSlots.put(WORK_TYPE_BGUSER_IMPORTANT, maxBgUserImp);
final int maxBgUser = Math.max(1, Math.min(mMaxTotal,
properties.getInt(KEY_PREFIX_MAX_BGUSER + mConfigIdentifier,
mDefaultMaxAllowedSlots.get(WORK_TYPE_BGUSER, mMaxTotal))));
@@ -1132,6 +1213,11 @@
mDefaultMinReservedSlots.get(WORK_TYPE_BG))));
mMinReservedSlots.put(WORK_TYPE_BG, minBg);
remaining -= minBg;
+ // Ensure bg user imp is in the range [0, min(maxBgUserImp, remaining)]
+ final int minBgUserImp = Math.max(0, Math.min(Math.min(maxBgUserImp, remaining),
+ properties.getInt(KEY_PREFIX_MIN_BGUSER_IMPORTANT + mConfigIdentifier,
+ mDefaultMinReservedSlots.get(WORK_TYPE_BGUSER_IMPORTANT, 0))));
+ mMinReservedSlots.put(WORK_TYPE_BGUSER_IMPORTANT, minBgUserImp);
// Ensure bg user is in the range [0, min(maxBgUser, remaining)]
final int minBgUser = Math.max(0, Math.min(Math.min(maxBgUser, remaining),
properties.getInt(KEY_PREFIX_MIN_BGUSER + mConfigIdentifier,
@@ -1170,6 +1256,10 @@
pw.print(KEY_PREFIX_MAX_BG + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_BG))
.println();
pw.print(KEY_PREFIX_MIN_BGUSER + mConfigIdentifier,
+ mMinReservedSlots.get(WORK_TYPE_BGUSER_IMPORTANT)).println();
+ pw.print(KEY_PREFIX_MAX_BGUSER + mConfigIdentifier,
+ mMaxAllowedSlots.get(WORK_TYPE_BGUSER_IMPORTANT)).println();
+ pw.print(KEY_PREFIX_MIN_BGUSER + mConfigIdentifier,
mMinReservedSlots.get(WORK_TYPE_BGUSER)).println();
pw.print(KEY_PREFIX_MAX_BGUSER + mConfigIdentifier,
mMaxAllowedSlots.get(WORK_TYPE_BGUSER)).println();
@@ -1269,19 +1359,10 @@
void setConfig(@NonNull WorkTypeConfig workTypeConfig) {
mConfigMaxTotal = workTypeConfig.getMaxTotal();
- mConfigNumReservedSlots.put(WORK_TYPE_TOP,
- workTypeConfig.getMinReserved(WORK_TYPE_TOP));
- mConfigNumReservedSlots.put(WORK_TYPE_FGS,
- workTypeConfig.getMinReserved(WORK_TYPE_FGS));
- mConfigNumReservedSlots.put(WORK_TYPE_EJ, workTypeConfig.getMinReserved(WORK_TYPE_EJ));
- mConfigNumReservedSlots.put(WORK_TYPE_BG, workTypeConfig.getMinReserved(WORK_TYPE_BG));
- mConfigNumReservedSlots.put(WORK_TYPE_BGUSER,
- workTypeConfig.getMinReserved(WORK_TYPE_BGUSER));
- mConfigAbsoluteMaxSlots.put(WORK_TYPE_TOP, workTypeConfig.getMax(WORK_TYPE_TOP));
- mConfigAbsoluteMaxSlots.put(WORK_TYPE_FGS, workTypeConfig.getMax(WORK_TYPE_FGS));
- mConfigAbsoluteMaxSlots.put(WORK_TYPE_EJ, workTypeConfig.getMax(WORK_TYPE_EJ));
- mConfigAbsoluteMaxSlots.put(WORK_TYPE_BG, workTypeConfig.getMax(WORK_TYPE_BG));
- mConfigAbsoluteMaxSlots.put(WORK_TYPE_BGUSER, workTypeConfig.getMax(WORK_TYPE_BGUSER));
+ for (int workType = 1; workType < ALL_WORK_TYPES; workType <<= 1) {
+ mConfigNumReservedSlots.put(workType, workTypeConfig.getMinReserved(workType));
+ mConfigAbsoluteMaxSlots.put(workType, workTypeConfig.getMax(workType));
+ }
mNumUnspecializedRemaining = mConfigMaxTotal;
for (int i = mNumRunningJobs.size() - 1; i >= 0; --i) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 8bb03e9..515cb74 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1745,11 +1745,12 @@
* A job just finished executing. We fetch the
* {@link com.android.server.job.controllers.JobStatus} from the store and depending on
* whether we want to reschedule we re-add it to the controllers.
- * @param jobStatus Completed job.
+ *
+ * @param jobStatus Completed job.
* @param needsReschedule Whether the implementing class should reschedule this job.
*/
@Override
- public void onJobCompletedLocked(JobStatus jobStatus, boolean needsReschedule) {
+ public void onJobCompletedLocked(JobStatus jobStatus, int stopReason, boolean needsReschedule) {
if (DEBUG) {
Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule);
}
@@ -1767,6 +1768,11 @@
// we stop it.
final JobStatus rescheduledJob = needsReschedule
? getRescheduleJobForFailureLocked(jobStatus) : null;
+ if (rescheduledJob != null
+ && (stopReason == JobParameters.REASON_TIMEOUT
+ || stopReason == JobParameters.REASON_PREEMPT)) {
+ rescheduledJob.disallowRunInBatterySaverAndDoze();
+ }
// Do not write back immediately if this is a periodic job. The job may get lost if system
// shuts down before it is added back.
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index 2a23d60..6802b6b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -269,14 +269,14 @@
try {
final int bindFlags;
if (job.shouldTreatAsExpeditedJob()) {
- // TODO(171305774): The job should run on the little cores. We'll probably need
- // another binding flag for that.
bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
| Context.BIND_ALMOST_PERCEPTIBLE
- | Context.BIND_ALLOW_NETWORK_ACCESS;
+ | Context.BIND_ALLOW_NETWORK_ACCESS
+ | Context.BIND_NOT_APP_COMPONENT_USAGE;
} else {
bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
- | Context.BIND_NOT_PERCEPTIBLE;
+ | Context.BIND_NOT_PERCEPTIBLE
+ | Context.BIND_NOT_APP_COMPONENT_USAGE;
}
binding = mContext.bindServiceAsUser(intent, this, bindFlags,
UserHandle.of(job.getUserId()));
@@ -353,15 +353,10 @@
/** Called externally when a job that was scheduled for execution should be cancelled. */
@GuardedBy("mLock")
- void cancelExecutingJobLocked(int reason, String debugReason) {
+ void cancelExecutingJobLocked(int reason, @NonNull String debugReason) {
doCancelLocked(reason, debugReason);
}
- @GuardedBy("mLock")
- void preemptExecutingJobLocked(@NonNull String reason) {
- doCancelLocked(JobParameters.REASON_PREEMPT, reason);
- }
-
int getPreferredUid() {
return mPreferredUid;
}
@@ -379,8 +374,8 @@
}
boolean isWithinExecutionGuaranteeTime() {
- return mExecutionStartTimeElapsed + mMinExecutionGuaranteeMillis
- < sElapsedRealtimeClock.millis();
+ return sElapsedRealtimeClock.millis()
+ < mExecutionStartTimeElapsed + mMinExecutionGuaranteeMillis;
}
@GuardedBy("mLock")
@@ -618,7 +613,7 @@
}
@GuardedBy("mLock")
- private void doCancelLocked(int stopReasonCode, String debugReason) {
+ private void doCancelLocked(int stopReasonCode, @Nullable String debugReason) {
if (mVerb == VERB_FINISHED) {
if (DEBUG) {
Slog.d(TAG,
@@ -731,7 +726,7 @@
* _ENDING -> No point in doing anything here, so we ignore.
*/
@GuardedBy("mLock")
- private void handleCancelLocked(String reason) {
+ private void handleCancelLocked(@Nullable String reason) {
if (JobSchedulerService.DEBUG) {
Slog.d(TAG, "Handling cancel for: " + mRunningJob.getJobId() + " "
+ VERB_STRINGS[mVerb]);
@@ -815,7 +810,7 @@
* VERB_STOPPING.
*/
@GuardedBy("mLock")
- private void sendStopMessageLocked(String reason) {
+ private void sendStopMessageLocked(@Nullable String reason) {
removeOpTimeOutLocked();
if (mVerb != VERB_EXECUTING) {
Slog.e(TAG, "Sending onStopJob for a job that isn't started. " + mRunningJob);
@@ -841,18 +836,19 @@
* we want to clean up internally.
*/
@GuardedBy("mLock")
- private void closeAndCleanupJobLocked(boolean reschedule, String reason) {
+ private void closeAndCleanupJobLocked(boolean reschedule, @Nullable String reason) {
final JobStatus completedJob;
if (mVerb == VERB_FINISHED) {
return;
}
applyStoppedReasonLocked(reason);
completedJob = mRunningJob;
- mJobPackageTracker.noteInactive(completedJob, mParams.getStopReason(), reason);
+ final int stopReason = mParams.getStopReason();
+ mJobPackageTracker.noteInactive(completedJob, stopReason, reason);
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
completedJob.getSourceUid(), null, completedJob.getBatteryName(),
FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__FINISHED,
- mParams.getStopReason(), completedJob.getStandbyBucket(), completedJob.getJobId(),
+ stopReason, completedJob.getStandbyBucket(), completedJob.getJobId(),
completedJob.hasChargingConstraint(),
completedJob.hasBatteryNotLowConstraint(),
completedJob.hasStorageNotLowConstraint(),
@@ -863,7 +859,7 @@
completedJob.hasContentTriggerConstraint());
try {
mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(), mRunningJob.getSourceUid(),
- mParams.getStopReason());
+ stopReason);
} catch (RemoteException e) {
// Whatever.
}
@@ -882,11 +878,11 @@
service = null;
mAvailable = true;
removeOpTimeOutLocked();
- mCompletedListener.onJobCompletedLocked(completedJob, reschedule);
+ mCompletedListener.onJobCompletedLocked(completedJob, stopReason, reschedule);
mJobConcurrencyManager.onJobCompletedLocked(this, completedJob, workType);
}
- private void applyStoppedReasonLocked(String reason) {
+ private void applyStoppedReasonLocked(@Nullable String reason) {
if (reason != null && mStoppedReason == null) {
mStoppedReason = reason;
mStoppedTime = sElapsedRealtimeClock.millis();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index eaf8f4d..aa8d98c 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -954,7 +954,7 @@
appBucket, sourceTag,
elapsedRuntimes.first, elapsedRuntimes.second,
lastSuccessfulRunTime, lastFailedRunTime,
- (rtcIsGood) ? null : rtcRuntimes, internalFlags);
+ (rtcIsGood) ? null : rtcRuntimes, internalFlags, /* dynamicConstraints */ 0);
return js;
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index 192f5e6..79ef321 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -64,7 +64,7 @@
* when the app is temp whitelisted or in the foreground.
*/
private final ArraySet<JobStatus> mAllowInIdleJobs;
- private final SparseBooleanArray mForegroundUids;
+ private final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
private final DeviceIdleUpdateFunctor mDeviceIdleUpdateFunctor;
private final DeviceIdleJobsDelayHandler mHandler;
private final PowerManager mPowerManager;
@@ -77,7 +77,6 @@
private int[] mDeviceIdleWhitelistAppIds;
private int[] mPowerSaveTempWhitelistAppIds;
- // onReceive
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -120,6 +119,10 @@
}
};
+ /** Criteria for whether or not we should a job's rush evaluation when the device exits Doze. */
+ private final Predicate<JobStatus> mShouldRushEvaluation = (jobStatus) ->
+ jobStatus.isRequestedExpeditedJob() || mForegroundUids.get(jobStatus.getSourceUid());
+
public DeviceIdleJobsController(JobSchedulerService service) {
super(service);
@@ -133,7 +136,6 @@
mLocalDeviceIdleController.getPowerSaveTempWhitelistAppIds();
mDeviceIdleUpdateFunctor = new DeviceIdleUpdateFunctor();
mAllowInIdleJobs = new ArraySet<>();
- mForegroundUids = new SparseBooleanArray();
final IntentFilter filter = new IntentFilter();
filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
filter.addAction(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);
@@ -156,14 +158,9 @@
mHandler.removeMessages(PROCESS_BACKGROUND_JOBS);
mService.getJobStore().forEachJob(mDeviceIdleUpdateFunctor);
} else {
- // When coming out of doze, process all foreground uids immediately, while others
- // will be processed after a delay of 3 seconds.
- for (int i = 0; i < mForegroundUids.size(); i++) {
- if (mForegroundUids.valueAt(i)) {
- mService.getJobStore().forEachJobForSourceUid(
- mForegroundUids.keyAt(i), mDeviceIdleUpdateFunctor);
- }
- }
+ // When coming out of doze, process all foreground uids and EJs immediately,
+ // while others will be processed after a delay of 3 seconds.
+ mService.getJobStore().forEachJob(mShouldRushEvaluation, mDeviceIdleUpdateFunctor);
mHandler.sendEmptyMessageDelayed(PROCESS_BACKGROUND_JOBS, BACKGROUND_JOBS_DELAY);
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index 5bdeb38..bad8dc1 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -91,6 +91,12 @@
static final int CONSTRAINT_WITHIN_EXPEDITED_QUOTA = 1 << 23; // Implicit constraint
static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1 << 22; // Implicit constraint
+ // The following set of dynamic constraints are for specific use cases (as explained in their
+ // relative naming and comments). Right now, they apply different constraints, which is fine,
+ // but if in the future, we have overlapping dynamic constraint sets, removing one constraint
+ // set may accidentally remove a constraint applied by another dynamic set.
+ // TODO: properly handle overlapping dynamic constraint sets
+
/**
* The additional set of dynamic constraints that must be met if the job's effective bucket is
* {@link JobSchedulerService#RESTRICTED_INDEX}. Connectivity can be ignored if the job doesn't
@@ -103,6 +109,13 @@
| CONSTRAINT_IDLE;
/**
+ * The additional set of dynamic constraints that must be met if this is an expedited job that
+ * had a long enough run while the device was Dozing or in battery saver.
+ */
+ private static final int DYNAMIC_EXPEDITED_DEFERRAL_CONSTRAINTS =
+ CONSTRAINT_DEVICE_NOT_DOZING | CONSTRAINT_BACKGROUND_NOT_RESTRICTED;
+
+ /**
* Standard media URIs that contain the media files that might be important to the user.
* @see #mHasMediaBackupExemption
*/
@@ -426,7 +439,8 @@
private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
int sourceUserId, int standbyBucket, String tag, int numFailures,
long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
- long lastSuccessfulRunTime, long lastFailedRunTime, int internalFlags) {
+ long lastSuccessfulRunTime, long lastFailedRunTime, int internalFlags,
+ int dynamicConstraints) {
this.job = job;
this.callingUid = callingUid;
this.standbyBucket = standbyBucket;
@@ -487,6 +501,7 @@
}
this.requiredConstraints = requiredConstraints;
mRequiredConstraintsOfInterest = requiredConstraints & CONSTRAINTS_OF_INTEREST;
+ addDynamicConstraints(dynamicConstraints);
mReadyNotDozing = canRunInDoze();
if (standbyBucket == RESTRICTED_INDEX) {
addDynamicConstraints(DYNAMIC_RESTRICTED_CONSTRAINTS);
@@ -521,7 +536,7 @@
jobStatus.getSourceTag(), jobStatus.getNumFailures(),
jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(),
jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime(),
- jobStatus.getInternalFlags());
+ jobStatus.getInternalFlags(), jobStatus.mDynamicConstraints);
mPersistedUtcTimes = jobStatus.mPersistedUtcTimes;
if (jobStatus.mPersistedUtcTimes != null) {
if (DEBUG) {
@@ -543,12 +558,12 @@
long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
long lastSuccessfulRunTime, long lastFailedRunTime,
Pair<Long, Long> persistedExecutionTimesUTC,
- int innerFlags) {
+ int innerFlags, int dynamicConstraints) {
this(job, callingUid, sourcePkgName, sourceUserId,
standbyBucket,
sourceTag, 0,
earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
- lastSuccessfulRunTime, lastFailedRunTime, innerFlags);
+ lastSuccessfulRunTime, lastFailedRunTime, innerFlags, dynamicConstraints);
// Only during initial inflation do we record the UTC-timebase execution bounds
// read from the persistent store. If we ever have to recreate the JobStatus on
@@ -572,7 +587,8 @@
rescheduling.getStandbyBucket(),
rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
newLatestRuntimeElapsedMillis,
- lastSuccessfulRunTime, lastFailedRunTime, rescheduling.getInternalFlags());
+ lastSuccessfulRunTime, lastFailedRunTime, rescheduling.getInternalFlags(),
+ rescheduling.mDynamicConstraints);
}
/**
@@ -609,7 +625,7 @@
standbyBucket, tag, 0,
earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */,
- /*innerFlags=*/ 0);
+ /*innerFlags=*/ 0, /* dynamicConstraints */ 0);
}
public void enqueueWorkLocked(JobWorkItem work) {
@@ -1083,12 +1099,15 @@
* in Doze.
*/
public boolean canRunInDoze() {
- return (getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0 || shouldTreatAsExpeditedJob();
+ return (getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0
+ || (shouldTreatAsExpeditedJob()
+ && (mDynamicConstraints & CONSTRAINT_DEVICE_NOT_DOZING) == 0);
}
boolean canRunInBatterySaver() {
return (getInternalFlags() & INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION) != 0
- || shouldTreatAsExpeditedJob();
+ || (shouldTreatAsExpeditedJob()
+ && (mDynamicConstraints & CONSTRAINT_BACKGROUND_NOT_RESTRICTED) == 0);
}
boolean shouldIgnoreNetworkBlocking() {
@@ -1245,6 +1264,14 @@
}
/**
+ * Add additional constraints to prevent this job from running when doze or battery saver are
+ * active.
+ */
+ public void disallowRunInBatterySaverAndDoze() {
+ addDynamicConstraints(DYNAMIC_EXPEDITED_DEFERRAL_CONSTRAINTS);
+ }
+
+ /**
* Indicates that this job cannot run without the specified constraints. This is evaluated
* separately from the job's explicitly requested constraints and MUST be satisfied before
* the job can run if the app doesn't have quota.
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index b18a22b..1d6f20d 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -47,6 +47,7 @@
static_libs: [
"exoplayer2-extractor",
"mediatranscoding_aidl_interface-java",
+ "modules-annotation-minsdk",
"modules-utils-build",
],
jarjar_rules: "jarjar_rules.txt",
@@ -108,7 +109,7 @@
filegroup {
name: "mediaparser-srcs",
srcs: [
- "java/android/media/MediaParser.java"
+ "java/android/media/MediaParser.java",
],
path: "java",
}
diff --git a/apex/media/framework/jarjar_rules.txt b/apex/media/framework/jarjar_rules.txt
index eb71fdd..91489dc 100644
--- a/apex/media/framework/jarjar_rules.txt
+++ b/apex/media/framework/jarjar_rules.txt
@@ -1,2 +1,2 @@
-rule com.android.modules.utils.** android.media.internal.utils.@1
+rule com.android.modules.** android.media.internal.@1
rule com.google.android.exoplayer2.** android.media.internal.exo.@1
diff --git a/apex/media/framework/java/android/media/MediaCommunicationManager.java b/apex/media/framework/java/android/media/MediaCommunicationManager.java
index 9ec25fe..f39bcfb 100644
--- a/apex/media/framework/java/android/media/MediaCommunicationManager.java
+++ b/apex/media/framework/java/android/media/MediaCommunicationManager.java
@@ -27,12 +27,14 @@
import android.content.Context;
import android.media.session.MediaSession;
import android.media.session.MediaSessionManager;
+import android.os.Build;
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.media.MediaBrowserService;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import com.android.modules.annotation.MinSdk;
import com.android.modules.utils.build.SdkLevel;
import java.util.Collections;
@@ -45,6 +47,7 @@
* Provides support for interacting with {@link android.media.MediaSession2 MediaSession2s}
* that applications have published to express their ongoing media playback state.
*/
+@MinSdk(Build.VERSION_CODES.S)
@SystemService(Context.MEDIA_COMMUNICATION_SERVICE)
public class MediaCommunicationManager {
private static final String TAG = "MediaCommunicationManager";
diff --git a/apex/media/framework/java/android/media/MediaSession2.java b/apex/media/framework/java/android/media/MediaSession2.java
index 6397ba3..7697359 100644
--- a/apex/media/framework/java/android/media/MediaSession2.java
+++ b/apex/media/framework/java/android/media/MediaSession2.java
@@ -32,6 +32,7 @@
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.media.session.MediaSessionManager;
import android.media.session.MediaSessionManager.RemoteUserInfo;
import android.os.BadParcelableException;
import android.os.Bundle;
@@ -43,6 +44,8 @@
import android.util.ArraySet;
import android.util.Log;
+import com.android.modules.utils.build.SdkLevel;
+
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -86,6 +89,7 @@
private final String mSessionId;
private final PendingIntent mSessionActivity;
private final Session2Token mSessionToken;
+ private final MediaSessionManager mMediaSessionManager;
private final MediaCommunicationManager mCommunicationManager;
private final Handler mResultHandler;
@@ -114,7 +118,13 @@
mSessionStub = new Session2Link(this);
mSessionToken = new Session2Token(Process.myUid(), TYPE_SESSION, context.getPackageName(),
mSessionStub, tokenExtras);
- mCommunicationManager = mContext.getSystemService(MediaCommunicationManager.class);
+ if (SdkLevel.isAtLeastS()) {
+ mCommunicationManager = mContext.getSystemService(MediaCommunicationManager.class);
+ mMediaSessionManager = null;
+ } else {
+ mMediaSessionManager = mContext.getSystemService(MediaSessionManager.class);
+ mCommunicationManager = null;
+ }
// NOTE: mResultHandler uses main looper, so this MUST NOT be blocked.
mResultHandler = new Handler(context.getMainLooper());
mClosed = false;
@@ -315,6 +325,14 @@
return mCallback;
}
+ boolean isTrustedForMediaControl(RemoteUserInfo remoteUserInfo) {
+ if (SdkLevel.isAtLeastS()) {
+ return mCommunicationManager.isTrustedForMediaControl(remoteUserInfo);
+ } else {
+ return mMediaSessionManager.isTrustedForMediaControl(remoteUserInfo);
+ }
+ }
+
void setForegroundServiceEventCallback(ForegroundServiceEventCallback callback) {
synchronized (mLock) {
if (mForegroundServiceEventCallback == callback) {
@@ -350,7 +368,7 @@
final ControllerInfo controllerInfo = new ControllerInfo(
remoteUserInfo,
- mCommunicationManager.isTrustedForMediaControl(remoteUserInfo),
+ isTrustedForMediaControl(remoteUserInfo),
controller,
connectionHints);
mCallbackExecutor.execute(() -> {
@@ -606,9 +624,15 @@
// Notify framework about the newly create session after the constructor is finished.
// Otherwise, framework may access the session before the initialization is finished.
try {
- MediaCommunicationManager manager =
- mContext.getSystemService(MediaCommunicationManager.class);
- manager.notifySession2Created(session2.getToken());
+ if (SdkLevel.isAtLeastS()) {
+ MediaCommunicationManager manager =
+ mContext.getSystemService(MediaCommunicationManager.class);
+ manager.notifySession2Created(session2.getToken());
+ } else {
+ MediaSessionManager manager =
+ mContext.getSystemService(MediaSessionManager.class);
+ manager.notifySession2Created(session2.getToken());
+ }
} catch (Exception e) {
session2.close();
throw e;
diff --git a/core/api/current.txt b/core/api/current.txt
index c6588a0..b1e8645 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1072,6 +1072,7 @@
field public static final int panelTextAppearance = 16842850; // 0x1010062
field public static final int parentActivityName = 16843687; // 0x10103a7
field @Deprecated public static final int password = 16843100; // 0x101015c
+ field public static final int passwordsActivity = 16844351; // 0x101063f
field public static final int path = 16842794; // 0x101002a
field public static final int pathAdvancedPattern = 16844320; // 0x1010620
field public static final int pathData = 16843781; // 0x1010405
@@ -5311,6 +5312,14 @@
field @Deprecated public static final int TRANSIT_UNSET = -1; // 0xffffffff
}
+ public final class GameManager {
+ method public int getGameMode();
+ field public static final int GAME_MODE_BATTERY = 3; // 0x3
+ field public static final int GAME_MODE_PERFORMANCE = 2; // 0x2
+ field public static final int GAME_MODE_STANDARD = 1; // 0x1
+ field public static final int GAME_MODE_UNSUPPORTED = 0; // 0x0
+ }
+
public class Instrumentation {
ctor public Instrumentation();
method public android.os.TestLooperManager acquireLooperManager(android.os.Looper);
@@ -7112,6 +7121,7 @@
method @NonNull public android.os.Bundle getUserRestrictions(@NonNull android.content.ComponentName);
method @Nullable public String getWifiMacAddress(@NonNull android.content.ComponentName);
method public boolean grantKeyPairToApp(@Nullable android.content.ComponentName, @NonNull String, @NonNull String);
+ method public boolean grantKeyPairToWifiAuth(@NonNull String);
method public boolean hasCaCertInstalled(@Nullable android.content.ComponentName, byte[]);
method public boolean hasGrantedPolicy(@NonNull android.content.ComponentName, int);
method public boolean hasKeyPair(@NonNull String);
@@ -7134,6 +7144,7 @@
method public boolean isDeviceIdAttestationSupported();
method public boolean isDeviceOwnerApp(String);
method public boolean isEphemeralUser(@NonNull android.content.ComponentName);
+ method public boolean isKeyPairGrantedToWifiAuth(@NonNull String);
method public boolean isLockTaskPermitted(String);
method public boolean isLogoutEnabled();
method public boolean isManagedProfile(@NonNull android.content.ComponentName);
@@ -7169,6 +7180,7 @@
method @Nullable public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(@NonNull android.content.ComponentName);
method @Nullable public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(@NonNull android.content.ComponentName);
method public boolean revokeKeyPairFromApp(@Nullable android.content.ComponentName, @NonNull String, @NonNull String);
+ method public boolean revokeKeyPairFromWifiAuth(@NonNull String);
method public void setAccountManagementDisabled(@NonNull android.content.ComponentName, String, boolean);
method public void setAffiliationIds(@NonNull android.content.ComponentName, @NonNull java.util.Set<java.lang.String>);
method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -8371,7 +8383,6 @@
public class AppWidgetHostView extends android.widget.FrameLayout {
ctor public AppWidgetHostView(android.content.Context);
ctor public AppWidgetHostView(android.content.Context, int, int);
- method public void clearCurrentSize();
method public int getAppWidgetId();
method public android.appwidget.AppWidgetProviderInfo getAppWidgetInfo();
method public static android.graphics.Rect getDefaultPaddingForWidget(android.content.Context, android.content.ComponentName, android.graphics.Rect);
@@ -8381,13 +8392,12 @@
method public void resetColorResources();
method public void setAppWidget(int, android.appwidget.AppWidgetProviderInfo);
method public void setColorResources(@NonNull android.util.SparseIntArray);
- method public void setCurrentSize(@NonNull android.graphics.PointF);
method public void setExecutor(java.util.concurrent.Executor);
method public void setOnLightBackground(boolean);
method public void updateAppWidget(android.widget.RemoteViews);
method public void updateAppWidgetOptions(android.os.Bundle);
method @Deprecated public void updateAppWidgetSize(android.os.Bundle, int, int, int, int);
- method public void updateAppWidgetSize(@NonNull android.os.Bundle, @NonNull java.util.List<android.graphics.PointF>);
+ method public void updateAppWidgetSize(@NonNull android.os.Bundle, @NonNull java.util.List<android.util.SizeF>);
}
public class AppWidgetManager {
@@ -9716,7 +9726,7 @@
}
public final class CompanionDeviceManager {
- method public void associate(@NonNull android.companion.AssociationRequest, @NonNull android.companion.CompanionDeviceManager.Callback, @Nullable android.os.Handler);
+ method @RequiresPermission(value=android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH, conditional=true) public void associate(@NonNull android.companion.AssociationRequest, @NonNull android.companion.CompanionDeviceManager.Callback, @Nullable android.os.Handler);
method public void disassociate(@NonNull String);
method @NonNull public java.util.List<java.lang.String> getAssociations();
method public boolean hasNotificationAccess(android.content.ComponentName);
@@ -10326,6 +10336,7 @@
method @Deprecated public abstract void clearWallpaper() throws java.io.IOException;
method @NonNull public android.content.Context createAttributionContext(@Nullable String);
method public abstract android.content.Context createConfigurationContext(@NonNull android.content.res.Configuration);
+ method @NonNull public android.content.Context createContext(@NonNull android.content.ContextParams);
method public abstract android.content.Context createContextForSplit(String) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.Context createDeviceProtectedStorageContext();
method public abstract android.content.Context createDisplayContext(@NonNull android.view.Display);
@@ -10376,6 +10387,7 @@
method public abstract android.content.pm.PackageManager getPackageManager();
method public abstract String getPackageName();
method public abstract String getPackageResourcePath();
+ method @Nullable public android.content.ContextParams getParams();
method public abstract android.content.res.Resources getResources();
method public abstract android.content.SharedPreferences getSharedPreferences(String, int);
method @NonNull public final String getString(@StringRes int);
@@ -10487,6 +10499,7 @@
field public static final String EUICC_SERVICE = "euicc";
field public static final String FILE_INTEGRITY_SERVICE = "file_integrity";
field public static final String FINGERPRINT_SERVICE = "fingerprint";
+ field public static final String GAME_SERVICE = "game";
field public static final String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
field public static final String INPUT_METHOD_SERVICE = "input_method";
field public static final String INPUT_SERVICE = "input";
@@ -10547,6 +10560,19 @@
field public static final String WINDOW_SERVICE = "window";
}
+ public final class ContextParams {
+ method @Nullable public String getAttributionTag();
+ method @Nullable public String getReceiverAttributionTag();
+ method @Nullable public String getReceiverPackage();
+ }
+
+ public static final class ContextParams.Builder {
+ ctor public ContextParams.Builder();
+ method @NonNull public android.content.ContextParams build();
+ method @NonNull public android.content.ContextParams.Builder setAttributionTag(@NonNull String);
+ method @NonNull public android.content.ContextParams.Builder setReceiverPackage(@NonNull String, @Nullable String);
+ }
+
public class ContextWrapper extends android.content.Context {
ctor public ContextWrapper(android.content.Context);
method protected void attachBaseContext(android.content.Context);
@@ -12882,18 +12908,18 @@
}
public class ShortcutManager {
- method public boolean addDynamicShortcuts(@NonNull java.util.List<android.content.pm.ShortcutInfo>);
- method public android.content.Intent createShortcutResultIntent(@NonNull android.content.pm.ShortcutInfo);
+ method @WorkerThread public boolean addDynamicShortcuts(@NonNull java.util.List<android.content.pm.ShortcutInfo>);
+ method @WorkerThread public android.content.Intent createShortcutResultIntent(@NonNull android.content.pm.ShortcutInfo);
method public void disableShortcuts(@NonNull java.util.List<java.lang.String>);
method public void disableShortcuts(@NonNull java.util.List<java.lang.String>, CharSequence);
method public void enableShortcuts(@NonNull java.util.List<java.lang.String>);
- method @NonNull public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
+ method @NonNull @WorkerThread public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
method public int getIconMaxHeight();
method public int getIconMaxWidth();
- method @NonNull public java.util.List<android.content.pm.ShortcutInfo> getManifestShortcuts();
+ method @NonNull @WorkerThread public java.util.List<android.content.pm.ShortcutInfo> getManifestShortcuts();
method public int getMaxShortcutCountPerActivity();
- method @NonNull public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
- method @NonNull public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(int);
+ method @NonNull @WorkerThread public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
+ method @NonNull @WorkerThread public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(int);
method public boolean isRateLimitingActive();
method public boolean isRequestPinShortcutSupported();
method public void pushDynamicShortcut(@NonNull android.content.pm.ShortcutInfo);
@@ -12901,10 +12927,10 @@
method public void removeDynamicShortcuts(@NonNull java.util.List<java.lang.String>);
method public void removeLongLivedShortcuts(@NonNull java.util.List<java.lang.String>);
method public void reportShortcutUsed(String);
- method public boolean requestPinShortcut(@NonNull android.content.pm.ShortcutInfo, @Nullable android.content.IntentSender);
- method public boolean setDynamicShortcuts(@NonNull java.util.List<android.content.pm.ShortcutInfo>);
+ method @WorkerThread public boolean requestPinShortcut(@NonNull android.content.pm.ShortcutInfo, @Nullable android.content.IntentSender);
+ method @WorkerThread public boolean setDynamicShortcuts(@NonNull java.util.List<android.content.pm.ShortcutInfo>);
method public void updateShortcutVisibility(@NonNull String, @Nullable byte[], boolean);
- method public boolean updateShortcuts(@NonNull java.util.List<android.content.pm.ShortcutInfo>);
+ method @WorkerThread public boolean updateShortcuts(@NonNull java.util.List<android.content.pm.ShortcutInfo>);
field public static final int FLAG_MATCH_CACHED = 8; // 0x8
field public static final int FLAG_MATCH_DYNAMIC = 2; // 0x2
field public static final int FLAG_MATCH_MANIFEST = 1; // 0x1
@@ -12948,6 +12974,27 @@
}
+package android.content.pm.verify.domain {
+
+ public final class DomainVerificationManager {
+ method @Nullable public android.content.pm.verify.domain.DomainVerificationUserState getDomainVerificationUserState(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
+ }
+
+ public final class DomainVerificationUserState implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getHostToStateMap();
+ method @NonNull public String getPackageName();
+ method @NonNull public android.os.UserHandle getUser();
+ method @NonNull public boolean isLinkHandlingAllowed();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.domain.DomainVerificationUserState> CREATOR;
+ field public static final int DOMAIN_STATE_NONE = 0; // 0x0
+ field public static final int DOMAIN_STATE_SELECTED = 1; // 0x1
+ field public static final int DOMAIN_STATE_VERIFIED = 2; // 0x2
+ }
+
+}
+
package android.content.res {
public class AssetFileDescriptor implements java.io.Closeable android.os.Parcelable {
@@ -17536,6 +17583,9 @@
public class BiometricManager {
method @Deprecated @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public int canAuthenticate();
method @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public int canAuthenticate(int);
+ method @Nullable @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public CharSequence getButtonLabel(int);
+ method @Nullable @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public CharSequence getPromptMessage(int);
+ method @Nullable @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public CharSequence getSettingName(int);
field public static final int BIOMETRIC_ERROR_HW_UNAVAILABLE = 1; // 0x1
field public static final int BIOMETRIC_ERROR_NONE_ENROLLED = 11; // 0xb
field public static final int BIOMETRIC_ERROR_NO_HARDWARE = 12; // 0xc
@@ -17747,6 +17797,7 @@
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size> SCALER_DEFAULT_SECURE_IMAGE_SIZE;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_STREAM_COMBINATIONS;
+ field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MultiResolutionStreamConfigurationMap> SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.StreamConfigurationMap> SCALER_STREAM_CONFIGURATION_MAP;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SENSOR_AVAILABLE_TEST_PATTERN_MODES;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.BlackLevelPattern> SENSOR_BLACK_LEVEL_PATTERN;
@@ -18351,9 +18402,20 @@
field public static final int MAX_THUMBNAIL_DIMENSION = 256; // 0x100
}
+ public class MultiResolutionImageReader implements java.lang.AutoCloseable {
+ method public void close();
+ method protected void finalize();
+ method public void flush();
+ method @NonNull public android.hardware.camera2.params.MultiResolutionStreamInfo getStreamInfoForImageReader(@NonNull android.media.ImageReader);
+ method @NonNull public android.view.Surface getSurface();
+ method @NonNull public static android.hardware.camera2.MultiResolutionImageReader newInstance(@NonNull java.util.Collection<android.hardware.camera2.params.MultiResolutionStreamInfo>, int, @IntRange(from=1) int);
+ method public void setOnImageAvailableListener(@Nullable android.media.ImageReader.OnImageAvailableListener, @Nullable java.util.concurrent.Executor);
+ }
+
public final class TotalCaptureResult extends android.hardware.camera2.CaptureResult {
method @NonNull public java.util.List<android.hardware.camera2.CaptureResult> getPartialResults();
- method public java.util.Map<java.lang.String,android.hardware.camera2.CaptureResult> getPhysicalCameraResults();
+ method @Deprecated public java.util.Map<java.lang.String,android.hardware.camera2.CaptureResult> getPhysicalCameraResults();
+ method @NonNull public java.util.Map<java.lang.String,android.hardware.camera2.TotalCaptureResult> getPhysicalCameraTotalResults();
}
}
@@ -18402,9 +18464,11 @@
public final class InputConfiguration {
ctor public InputConfiguration(int, int, int);
+ ctor public InputConfiguration(@NonNull java.util.Collection<android.hardware.camera2.params.MultiResolutionStreamInfo>, int);
method public int getFormat();
method public int getHeight();
method public int getWidth();
+ method public boolean isMultiResolution();
}
public final class LensShadingMap {
@@ -18447,6 +18511,20 @@
field public static final int METERING_WEIGHT_MIN = 0; // 0x0
}
+ public final class MultiResolutionStreamConfigurationMap {
+ method @NonNull public int[] getInputFormats();
+ method @NonNull public java.util.Collection<android.hardware.camera2.params.MultiResolutionStreamInfo> getInputInfo(int);
+ method @NonNull public int[] getOutputFormats();
+ method @NonNull public java.util.Collection<android.hardware.camera2.params.MultiResolutionStreamInfo> getOutputInfo(int);
+ }
+
+ public class MultiResolutionStreamInfo {
+ ctor public MultiResolutionStreamInfo(int, int, @NonNull String);
+ method public int getHeight();
+ method @NonNull public String getPhysicalCameraId();
+ method public int getWidth();
+ }
+
public final class OisSample {
ctor public OisSample(long, float, float);
method public long getTimestamp();
@@ -18459,6 +18537,7 @@
ctor public OutputConfiguration(int, @NonNull android.view.Surface);
ctor public OutputConfiguration(@NonNull android.util.Size, @NonNull Class<T>);
method public void addSurface(@NonNull android.view.Surface);
+ method @NonNull public static java.util.Collection<android.hardware.camera2.params.OutputConfiguration> createInstancesForMultiResolutionOutput(@NonNull android.hardware.camera2.MultiResolutionImageReader);
method public int describeContents();
method public void enableSurfaceSharing();
method public int getMaxSharedSurfaceCount();
@@ -21884,16 +21963,17 @@
field public static final int ERROR_PROVISIONING_CERTIFICATE = 24; // 0x18
field public static final int ERROR_PROVISIONING_CONFIG = 25; // 0x19
field public static final int ERROR_PROVISIONING_PARSE = 26; // 0x1a
- field public static final int ERROR_PROVISIONING_RETRY = 27; // 0x1b
+ field public static final int ERROR_PROVISIONING_REQUEST_REJECTED = 27; // 0x1b
+ field public static final int ERROR_PROVISIONING_RETRY = 28; // 0x1c
field public static final int ERROR_RESOURCE_BUSY = 3; // 0x3
- field public static final int ERROR_RESOURCE_CONTENTION = 28; // 0x1c
- field public static final int ERROR_SECURE_STOP_RELEASE = 29; // 0x1d
+ field public static final int ERROR_RESOURCE_CONTENTION = 29; // 0x1d
+ field public static final int ERROR_SECURE_STOP_RELEASE = 30; // 0x1e
field public static final int ERROR_SESSION_NOT_OPENED = 5; // 0x5
- field public static final int ERROR_STORAGE_READ = 30; // 0x1e
- field public static final int ERROR_STORAGE_WRITE = 31; // 0x1f
+ field public static final int ERROR_STORAGE_READ = 31; // 0x1f
+ field public static final int ERROR_STORAGE_WRITE = 32; // 0x20
field public static final int ERROR_UNKNOWN = 0; // 0x0
field public static final int ERROR_UNSUPPORTED_OPERATION = 6; // 0x6
- field public static final int ERROR_ZERO_SUBSAMPLES = 32; // 0x20
+ field public static final int ERROR_ZERO_SUBSAMPLES = 33; // 0x21
}
@Deprecated @IntDef({android.media.MediaDrm.HDCP_LEVEL_UNKNOWN, android.media.MediaDrm.HDCP_NONE, android.media.MediaDrm.HDCP_V1, android.media.MediaDrm.HDCP_V2, android.media.MediaDrm.HDCP_V2_1, android.media.MediaDrm.HDCP_V2_2, android.media.MediaDrm.HDCP_V2_3, android.media.MediaDrm.HDCP_NO_DIGITAL_OUTPUT}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface MediaDrm.HdcpLevel {
@@ -26724,7 +26804,22 @@
public class VcnManager {
method @RequiresPermission("carrier privileges") public void clearVcnConfig(@NonNull android.os.ParcelUuid) throws java.io.IOException;
+ method public void registerVcnStatusCallback(@NonNull android.os.ParcelUuid, @NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnStatusCallback);
method @RequiresPermission("carrier privileges") public void setVcnConfig(@NonNull android.os.ParcelUuid, @NonNull android.net.vcn.VcnConfig) throws java.io.IOException;
+ method public void unregisterVcnStatusCallback(@NonNull android.net.vcn.VcnManager.VcnStatusCallback);
+ field public static final int VCN_ERROR_CODE_CONFIG_ERROR = 1; // 0x1
+ field public static final int VCN_ERROR_CODE_INTERNAL_ERROR = 0; // 0x0
+ field public static final int VCN_ERROR_CODE_NETWORK_ERROR = 2; // 0x2
+ field public static final int VCN_STATUS_CODE_ACTIVE = 2; // 0x2
+ field public static final int VCN_STATUS_CODE_INACTIVE = 1; // 0x1
+ field public static final int VCN_STATUS_CODE_NOT_CONFIGURED = 0; // 0x0
+ field public static final int VCN_STATUS_CODE_SAFE_MODE = 3; // 0x3
+ }
+
+ public abstract static class VcnManager.VcnStatusCallback {
+ ctor public VcnManager.VcnStatusCallback();
+ method public abstract void onGatewayConnectionError(@NonNull int[], int, @Nullable Throwable);
+ method public abstract void onVcnStatusChanged(int);
}
}
@@ -30274,6 +30369,7 @@
field public static final String HARDWARE;
field public static final String HOST;
field public static final String ID;
+ field public static final boolean IS_DEBUGGABLE;
field public static final String MANUFACTURER;
field public static final String MODEL;
field @NonNull public static final String ODM_SKU;
@@ -41472,29 +41568,29 @@
field public static final char WILD = 78; // 0x004e 'N'
}
- public class PhoneStateListener {
- ctor public PhoneStateListener();
+ @Deprecated public class PhoneStateListener {
+ ctor @Deprecated public PhoneStateListener();
ctor @Deprecated public PhoneStateListener(@NonNull java.util.concurrent.Executor);
- method public void onActiveDataSubscriptionIdChanged(int);
- method public void onBarringInfoChanged(@NonNull android.telephony.BarringInfo);
- method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallDisconnectCauseChanged(int, int);
- method public void onCallForwardingIndicatorChanged(boolean);
- method public void onCallStateChanged(int, String);
- method public void onCellInfoChanged(java.util.List<android.telephony.CellInfo>);
- method public void onCellLocationChanged(android.telephony.CellLocation);
- method public void onDataActivity(int);
- method public void onDataConnectionStateChanged(int);
- method public void onDataConnectionStateChanged(int, int);
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo);
- method public void onEmergencyNumberListChanged(@NonNull java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>);
- method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
- method public void onMessageWaitingIndicatorChanged(boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
- method public void onRegistrationFailed(@NonNull android.telephony.CellIdentity, @NonNull String, int, int, int);
- method public void onServiceStateChanged(android.telephony.ServiceState);
+ method @Deprecated public void onActiveDataSubscriptionIdChanged(int);
+ method @Deprecated public void onBarringInfoChanged(@NonNull android.telephony.BarringInfo);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallDisconnectCauseChanged(int, int);
+ method @Deprecated public void onCallForwardingIndicatorChanged(boolean);
+ method @Deprecated public void onCallStateChanged(int, String);
+ method @Deprecated public void onCellInfoChanged(java.util.List<android.telephony.CellInfo>);
+ method @Deprecated public void onCellLocationChanged(android.telephony.CellLocation);
+ method @Deprecated public void onDataActivity(int);
+ method @Deprecated public void onDataConnectionStateChanged(int);
+ method @Deprecated public void onDataConnectionStateChanged(int, int);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo);
+ method @Deprecated public void onEmergencyNumberListChanged(@NonNull java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
+ method @Deprecated public void onMessageWaitingIndicatorChanged(boolean);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
+ method @Deprecated public void onRegistrationFailed(@NonNull android.telephony.CellIdentity, @NonNull String, int, int, int);
+ method @Deprecated public void onServiceStateChanged(android.telephony.ServiceState);
method @Deprecated public void onSignalStrengthChanged(int);
- method public void onSignalStrengthsChanged(android.telephony.SignalStrength);
- method public void onUserMobileDataStateChanged(boolean);
+ method @Deprecated public void onSignalStrengthsChanged(android.telephony.SignalStrength);
+ method @Deprecated public void onUserMobileDataStateChanged(boolean);
field @Deprecated public static final int LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE = 4194304; // 0x400000
field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_BARRING_INFO = -2147483648; // 0x80000000
field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_CALL_DISCONNECT_CAUSES = 33554432; // 0x2000000
@@ -41508,7 +41604,7 @@
field @Deprecated public static final int LISTEN_EMERGENCY_NUMBER_LIST = 16777216; // 0x1000000
field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 134217728; // 0x8000000
field @Deprecated public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 4; // 0x4
- field public static final int LISTEN_NONE = 0; // 0x0
+ field @Deprecated public static final int LISTEN_NONE = 0; // 0x0
field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000
field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_REGISTRATION_FAILURE = 1073741824; // 0x40000000
field @Deprecated public static final int LISTEN_SERVICE_STATE = 1; // 0x1
@@ -41517,90 +41613,6 @@
field @Deprecated public static final int LISTEN_USER_MOBILE_DATA_STATE = 524288; // 0x80000
}
- public static interface PhoneStateListener.ActiveDataSubscriptionIdChangedListener {
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onActiveDataSubscriptionIdChanged(int);
- }
-
- public static interface PhoneStateListener.AlwaysReportedSignalStrengthChangedListener {
- method @RequiresPermission("android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH") public void onSignalStrengthsChanged(@NonNull android.telephony.SignalStrength);
- }
-
- public static interface PhoneStateListener.BarringInfoChangedListener {
- method @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void onBarringInfoChanged(@NonNull android.telephony.BarringInfo);
- }
-
- public static interface PhoneStateListener.CallDisconnectCauseChangedListener {
- method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallDisconnectCauseChanged(int, int);
- }
-
- public static interface PhoneStateListener.CallForwardingIndicatorChangedListener {
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onCallForwardingIndicatorChanged(boolean);
- }
-
- public static interface PhoneStateListener.CallStateChangedListener {
- method @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) public void onCallStateChanged(int, @Nullable String);
- }
-
- public static interface PhoneStateListener.CarrierNetworkChangeListener {
- method public void onCarrierNetworkChange(boolean);
- }
-
- public static interface PhoneStateListener.CellInfoChangedListener {
- method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void onCellInfoChanged(@NonNull java.util.List<android.telephony.CellInfo>);
- }
-
- public static interface PhoneStateListener.CellLocationChangedListener {
- method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void onCellLocationChanged(@NonNull android.telephony.CellLocation);
- }
-
- public static interface PhoneStateListener.DataActivationStateChangedListener {
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataActivationStateChanged(int);
- }
-
- public static interface PhoneStateListener.DataActivityListener {
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataActivity(int);
- }
-
- public static interface PhoneStateListener.DataConnectionStateChangedListener {
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataConnectionStateChanged(int, int);
- }
-
- public static interface PhoneStateListener.DisplayInfoChangedListener {
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo);
- }
-
- public static interface PhoneStateListener.EmergencyNumberListChangedListener {
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onEmergencyNumberListChanged(@NonNull java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>);
- }
-
- public static interface PhoneStateListener.ImsCallDisconnectCauseChangedListener {
- method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
- }
-
- public static interface PhoneStateListener.MessageWaitingIndicatorChangedListener {
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onMessageWaitingIndicatorChanged(boolean);
- }
-
- public static interface PhoneStateListener.PreciseDataConnectionStateChangedListener {
- method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
- }
-
- public static interface PhoneStateListener.RegistrationFailedListener {
- method @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void onRegistrationFailed(@NonNull android.telephony.CellIdentity, @NonNull String, int, int, int);
- }
-
- public static interface PhoneStateListener.ServiceStateChangedListener {
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onServiceStateChanged(@NonNull android.telephony.ServiceState);
- }
-
- public static interface PhoneStateListener.SignalStrengthsChangedListener {
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onSignalStrengthsChanged(@NonNull android.telephony.SignalStrength);
- }
-
- public static interface PhoneStateListener.UserMobileDataStateChangedListener {
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onUserMobileDataStateChanged(boolean);
- }
-
public final class PhysicalChannelConfig implements android.os.Parcelable {
method public int describeContents();
method @IntRange(from=1, to=261) public int getBand();
@@ -42075,6 +42087,94 @@
method public android.telephony.SubscriptionPlan.Builder setTitle(@Nullable CharSequence);
}
+ public class TelephonyCallback {
+ ctor public TelephonyCallback();
+ }
+
+ public static interface TelephonyCallback.ActiveDataSubscriptionIdListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onActiveDataSubscriptionIdChanged(int);
+ }
+
+ public static interface TelephonyCallback.AlwaysReportedSignalStrengthListener {
+ method @RequiresPermission("android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH") public void onSignalStrengthsChanged(@NonNull android.telephony.SignalStrength);
+ }
+
+ public static interface TelephonyCallback.BarringInfoListener {
+ method @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void onBarringInfoChanged(@NonNull android.telephony.BarringInfo);
+ }
+
+ public static interface TelephonyCallback.CallDisconnectCauseListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallDisconnectCauseChanged(int, int);
+ }
+
+ public static interface TelephonyCallback.CallForwardingIndicatorListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onCallForwardingIndicatorChanged(boolean);
+ }
+
+ public static interface TelephonyCallback.CallStateListener {
+ method @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) public void onCallStateChanged(int, @Nullable String);
+ }
+
+ public static interface TelephonyCallback.CarrierNetworkListener {
+ method public void onCarrierNetworkChange(boolean);
+ }
+
+ public static interface TelephonyCallback.CellInfoListener {
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void onCellInfoChanged(@NonNull java.util.List<android.telephony.CellInfo>);
+ }
+
+ public static interface TelephonyCallback.CellLocationListener {
+ method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void onCellLocationChanged(@NonNull android.telephony.CellLocation);
+ }
+
+ public static interface TelephonyCallback.DataActivationStateListener {
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataActivationStateChanged(int);
+ }
+
+ public static interface TelephonyCallback.DataActivityListener {
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataActivity(int);
+ }
+
+ public static interface TelephonyCallback.DataConnectionStateListener {
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataConnectionStateChanged(int, int);
+ }
+
+ public static interface TelephonyCallback.DisplayInfoListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo);
+ }
+
+ public static interface TelephonyCallback.EmergencyNumberListListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onEmergencyNumberListChanged(@NonNull java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>);
+ }
+
+ public static interface TelephonyCallback.ImsCallDisconnectCauseListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
+ }
+
+ public static interface TelephonyCallback.MessageWaitingIndicatorListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onMessageWaitingIndicatorChanged(boolean);
+ }
+
+ public static interface TelephonyCallback.PreciseDataConnectionStateListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
+ }
+
+ public static interface TelephonyCallback.RegistrationFailedListener {
+ method @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void onRegistrationFailed(@NonNull android.telephony.CellIdentity, @NonNull String, int, int, int);
+ }
+
+ public static interface TelephonyCallback.ServiceStateListener {
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onServiceStateChanged(@NonNull android.telephony.ServiceState);
+ }
+
+ public static interface TelephonyCallback.SignalStrengthsListener {
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onSignalStrengthsChanged(@NonNull android.telephony.SignalStrength);
+ }
+
+ public static interface TelephonyCallback.UserMobileDataStateListener {
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onUserMobileDataStateChanged(boolean);
+ }
+
public final class TelephonyDisplayInfo implements android.os.Parcelable {
method public int describeContents();
method public int getNetworkType();
@@ -42187,7 +42287,7 @@
method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle);
method public boolean isWorldPhone();
method @Deprecated public void listen(android.telephony.PhoneStateListener, int);
- method public void registerPhoneStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.PhoneStateListener);
+ method public void registerTelephonyCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyCallback);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void requestCellInfoUpdate(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
method @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback);
method public void sendDialerSpecialCode(String);
@@ -42211,7 +42311,7 @@
method @Deprecated public void setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri);
method @Deprecated public void setVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void switchMultiSimConfig(int);
- method public void unregisterPhoneStateListener(@NonNull android.telephony.PhoneStateListener);
+ method public void unregisterTelephonyCallback(@NonNull android.telephony.TelephonyCallback);
method public void updateAvailableNetworks(@NonNull java.util.List<android.telephony.AvailableNetworkInfo>, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
method public void uploadCallComposerPicture(@NonNull java.nio.file.Path, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.os.ParcelUuid,android.telephony.TelephonyManager.CallComposerException>);
method public void uploadCallComposerPicture(@NonNull java.io.InputStream, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.os.ParcelUuid,android.telephony.TelephonyManager.CallComposerException>);
@@ -45874,11 +45974,14 @@
method public static android.util.Size parseSize(String) throws java.lang.NumberFormatException;
}
- public final class SizeF {
+ public final class SizeF implements android.os.Parcelable {
ctor public SizeF(float, float);
+ method public int describeContents();
method public float getHeight();
method public float getWidth();
method public static android.util.SizeF parseSizeF(String) throws java.lang.NumberFormatException;
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.util.SizeF> CREATOR;
}
public class SparseArray<E> implements java.lang.Cloneable {
@@ -50823,6 +50926,7 @@
field public static final String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
field public static final String EXTRA_AUTHENTICATION_RESULT_EPHEMERAL_DATASET = "android.view.autofill.extra.AUTHENTICATION_RESULT_EPHEMERAL_DATASET";
field public static final String EXTRA_CLIENT_STATE = "android.view.autofill.extra.CLIENT_STATE";
+ field public static final String EXTRA_INLINE_SUGGESTIONS_REQUEST = "android.view.autofill.extra.INLINE_SUGGESTIONS_REQUEST";
}
public abstract static class AutofillManager.AutofillCallback {
@@ -50975,6 +51079,7 @@
method public void onDisplayHashError(int);
method public void onDisplayHashResult(@NonNull android.view.displayhash.DisplayHash);
field public static final int DISPLAY_HASH_ERROR_INVALID_BOUNDS = -2; // 0xfffffffe
+ field public static final int DISPLAY_HASH_ERROR_INVALID_HASH_ALGORITHM = -5; // 0xfffffffb
field public static final int DISPLAY_HASH_ERROR_MISSING_WINDOW = -3; // 0xfffffffd
field public static final int DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN = -4; // 0xfffffffc
field public static final int DISPLAY_HASH_ERROR_UNKNOWN = -1; // 0xffffffff
@@ -54769,7 +54874,7 @@
public class RemoteViews implements android.view.LayoutInflater.Filter android.os.Parcelable {
ctor public RemoteViews(String, int);
ctor public RemoteViews(android.widget.RemoteViews, android.widget.RemoteViews);
- ctor public RemoteViews(@NonNull java.util.Map<android.graphics.PointF,android.widget.RemoteViews>);
+ ctor public RemoteViews(@NonNull java.util.Map<android.util.SizeF,android.widget.RemoteViews>);
ctor public RemoteViews(android.widget.RemoteViews);
ctor public RemoteViews(android.os.Parcel);
method public void addView(@IdRes int, android.widget.RemoteViews);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index d6786f8..f7e6e03 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -35,7 +35,7 @@
}
public final class PendingIntent implements android.os.Parcelable {
- method @Nullable @RequiresPermission(android.Manifest.permission.GET_INTENT_SENDER_INTENT) public java.util.List<android.content.pm.ResolveInfo> queryIntentComponents(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.GET_INTENT_SENDER_INTENT) public java.util.List<android.content.pm.ResolveInfo> queryIntentComponents(int);
}
public class StatusBarManager {
@@ -144,7 +144,6 @@
public final class MediaSessionManager {
method public void addOnActiveSessionsChangedListener(@Nullable android.content.ComponentName, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.OnActiveSessionsChangedListener);
- method public void dispatchMediaKeyEvent(@NonNull android.view.KeyEvent);
method public void dispatchMediaKeyEvent(@NonNull android.view.KeyEvent, boolean);
method public void dispatchMediaKeyEventAsSystemService(@NonNull android.view.KeyEvent);
method public boolean dispatchMediaKeyEventToSessionAsSystemService(@NonNull android.view.KeyEvent, @NonNull android.media.session.MediaSession.Token);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 8f067c2..5d8eade 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -228,6 +228,7 @@
field public static final String REMOTE_DISPLAY_PROVIDER = "android.permission.REMOTE_DISPLAY_PROVIDER";
field public static final String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES";
field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
+ field public static final String RENOUNCE_PERMISSIONS = "android.permission.RENOUNCE_PERMISSIONS";
field public static final String REQUEST_NETWORK_SCORES = "android.permission.REQUEST_NETWORK_SCORES";
field public static final String REQUEST_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE";
field public static final String RESET_PASSWORD = "android.permission.RESET_PASSWORD";
@@ -358,6 +359,7 @@
field public static final int config_systemGallery = 17039399; // 0x1040027
field public static final int config_systemShell = 17039402; // 0x104002a
field public static final int config_systemSpeechRecognizer = 17039406; // 0x104002e
+ field public static final int config_systemWifiCoexManager = 17039407; // 0x104002f
}
public static final class R.style {
@@ -2183,6 +2185,14 @@
field public static final String WIFI_SCANNING_SERVICE = "wifiscanner";
}
+ public final class ContextParams {
+ method @Nullable @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS) public java.util.Set<java.lang.String> getRenouncedPermissions();
+ }
+
+ public static final class ContextParams.Builder {
+ method @NonNull @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS) public android.content.ContextParams.Builder setRenouncedPermissions(@NonNull java.util.Set<java.lang.String>);
+ }
+
public class ContextWrapper extends android.content.Context {
method public android.content.Context createCredentialProtectedStorageContext();
method @Nullable public java.io.File getPreloadsFileCache();
@@ -2702,7 +2712,7 @@
}
public class ShortcutManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_APP_PREDICTIONS) public java.util.List<android.content.pm.ShortcutManager.ShareShortcutInfo> getShareTargets(@NonNull android.content.IntentFilter);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_APP_PREDICTIONS) @WorkerThread public java.util.List<android.content.pm.ShortcutManager.ShareShortcutInfo> getShareTargets(@NonNull android.content.IntentFilter);
method public boolean hasShareTargets(@NonNull String);
}
@@ -2789,13 +2799,12 @@
field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.domain.DomainVerificationInfo> CREATOR;
}
- public interface DomainVerificationManager {
+ public final class DomainVerificationManager {
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.DOMAIN_VERIFICATION_AGENT, android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION}) public android.content.pm.verify.domain.DomainVerificationInfo getDomainVerificationInfo(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
- method @Nullable @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public android.content.pm.verify.domain.DomainVerificationUserSelection getDomainVerificationUserSelection(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public java.util.List<android.content.pm.verify.domain.DomainOwner> getOwnersForDomain(@NonNull String);
- method @NonNull @RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT) public java.util.List<java.lang.String> getValidVerificationPackageNames();
method public static boolean isStateModifiable(int);
method public static boolean isStateVerified(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT) public java.util.List<java.lang.String> queryValidVerificationPackageNames();
method @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public void setDomainVerificationLinkHandlingAllowed(@NonNull String, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
method @RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT) public void setDomainVerificationStatus(@NonNull java.util.UUID, @NonNull java.util.Set<java.lang.String>, int) throws android.content.pm.PackageManager.NameNotFoundException;
method @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION) public void setDomainVerificationUserSelection(@NonNull java.util.UUID, @NonNull java.util.Set<java.lang.String>, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -2812,18 +2821,8 @@
field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.domain.DomainVerificationRequest> CREATOR;
}
- public final class DomainVerificationUserSelection implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getHostToStateMap();
+ public final class DomainVerificationUserState implements android.os.Parcelable {
method @NonNull public java.util.UUID getIdentifier();
- method @NonNull public String getPackageName();
- method @NonNull public android.os.UserHandle getUser();
- method @NonNull public boolean isLinkHandlingAllowed();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.domain.DomainVerificationUserSelection> CREATOR;
- field public static final int DOMAIN_STATE_NONE = 0; // 0x0
- field public static final int DOMAIN_STATE_SELECTED = 1; // 0x1
- field public static final int DOMAIN_STATE_VERIFIED = 2; // 0x2
}
}
@@ -3460,6 +3459,10 @@
field @Deprecated public static final int LIGHT_TYPE_MICROPHONE = 8; // 0x8
}
+ public static final class LightsRequest.Builder {
+ method @Deprecated @NonNull public android.hardware.lights.LightsRequest.Builder setLight(@NonNull android.hardware.lights.Light, @NonNull android.hardware.lights.LightState);
+ }
+
}
package android.hardware.location {
@@ -9204,6 +9207,15 @@
}
+package android.security {
+
+ public final class KeyChain {
+ method @Nullable @WorkerThread public static String getWifiKeyGrantAsUser(@NonNull android.content.Context, @NonNull android.os.UserHandle, @NonNull String);
+ method @WorkerThread public static boolean hasWifiKeyGrantAsUser(@NonNull android.content.Context, @NonNull android.os.UserHandle, @NonNull String);
+ }
+
+}
+
package android.security.keystore {
public class AndroidKeyStoreProvider extends java.security.Provider {
@@ -11083,51 +11095,16 @@
method public static boolean isVoiceMailNumber(@NonNull android.content.Context, int, @Nullable String);
}
- public class PhoneStateListener {
- method public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
+ @Deprecated public class PhoneStateListener {
+ method @Deprecated public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
method @Deprecated public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber);
- method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
+ method @Deprecated public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
method @Deprecated public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber);
- method public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber, int);
- method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
- method public void onRadioPowerStateChanged(int);
- method public void onSrvccStateChanged(int);
- method public void onVoiceActivationStateChanged(int);
- field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED = 23; // 0x17
- field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED = 35; // 0x23
- field @RequiresPermission("android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH") public static final int EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED = 10; // 0xa
- field @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_BARRING_INFO_CHANGED = 32; // 0x20
- field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_CALL_ATTRIBUTES_CHANGED = 27; // 0x1b
- field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_CALL_DISCONNECT_CAUSE_CHANGED = 26; // 0x1a
- field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_CALL_FORWARDING_INDICATOR_CHANGED = 4; // 0x4
- field @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) public static final int EVENT_CALL_STATE_CHANGED = 6; // 0x6
- field public static final int EVENT_CARRIER_NETWORK_CHANGED = 17; // 0x11
- field @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static final int EVENT_CELL_INFO_CHANGED = 11; // 0xb
- field @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static final int EVENT_CELL_LOCATION_CHANGED = 5; // 0x5
- field public static final int EVENT_DATA_ACTIVATION_STATE_CHANGED = 19; // 0x13
- field public static final int EVENT_DATA_ACTIVITY_CHANGED = 8; // 0x8
- field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED = 14; // 0xe
- field public static final int EVENT_DATA_CONNECTION_STATE_CHANGED = 7; // 0x7
- field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_DATA_ENABLED_CHANGED = 34; // 0x22
- field public static final int EVENT_DISPLAY_INFO_CHANGED = 21; // 0x15
- field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_EMERGENCY_NUMBER_LIST_CHANGED = 25; // 0x19
- field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED = 28; // 0x1c
- field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_MESSAGE_WAITING_INDICATOR_CHANGED = 3; // 0x3
- field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_OEM_HOOK_RAW = 15; // 0xf
- field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int EVENT_OUTGOING_EMERGENCY_CALL = 29; // 0x1d
- field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int EVENT_OUTGOING_EMERGENCY_SMS = 30; // 0x1e
- field public static final int EVENT_PHONE_CAPABILITY_CHANGED = 22; // 0x16
- field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 33; // 0x21
- field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PRECISE_CALL_STATE_CHANGED = 12; // 0xc
- field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED = 13; // 0xd
- field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_RADIO_POWER_STATE_CHANGED = 24; // 0x18
- field @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_REGISTRATION_FAILURE = 31; // 0x1f
- field public static final int EVENT_SERVICE_STATE_CHANGED = 1; // 0x1
- field public static final int EVENT_SIGNAL_STRENGTHS_CHANGED = 9; // 0x9
- field public static final int EVENT_SIGNAL_STRENGTH_CHANGED = 2; // 0x2
- field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_SRVCC_STATE_CHANGED = 16; // 0x10
- field public static final int EVENT_USER_MOBILE_DATA_STATE_CHANGED = 20; // 0x14
- field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_VOICE_ACTIVATION_STATE_CHANGED = 18; // 0x12
+ method @Deprecated public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber, int);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
+ method @Deprecated public void onRadioPowerStateChanged(int);
+ method @Deprecated public void onSrvccStateChanged(int);
+ method @Deprecated public void onVoiceActivationStateChanged(int);
field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000
field @Deprecated @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 268435456; // 0x10000000
field @Deprecated @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 536870912; // 0x20000000
@@ -11137,50 +11114,6 @@
field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000
}
- public static interface PhoneStateListener.AllowedNetworkTypesChangedListener {
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onAllowedNetworkTypesChanged(@NonNull java.util.Map<java.lang.Integer,java.lang.Long>);
- }
-
- public static interface PhoneStateListener.CallAttributesChangedListener {
- method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
- }
-
- public static interface PhoneStateListener.DataEnabledChangedListener {
- method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onDataEnabledChanged(boolean, int);
- }
-
- public static interface PhoneStateListener.OutgoingEmergencyCallListener {
- method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
- }
-
- public static interface PhoneStateListener.OutgoingEmergencySmsListener {
- method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber, int);
- }
-
- public static interface PhoneStateListener.PhoneCapabilityChangedListener {
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onPhoneCapabilityChanged(@NonNull android.telephony.PhoneCapability);
- }
-
- public static interface PhoneStateListener.PhysicalChannelConfigChangedListener {
- method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPhysicalChannelConfigChanged(@NonNull java.util.List<android.telephony.PhysicalChannelConfig>);
- }
-
- public static interface PhoneStateListener.PreciseCallStateChangedListener {
- method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
- }
-
- public static interface PhoneStateListener.RadioPowerStateChangedListener {
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onRadioPowerStateChanged(int);
- }
-
- public static interface PhoneStateListener.SrvccStateChangedListener {
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onSrvccStateChanged(int);
- }
-
- public static interface PhoneStateListener.VoiceActivationStateChangedListener {
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onVoiceActivationStateChanged(int);
- }
-
public final class PinResult implements android.os.Parcelable {
method public int describeContents();
method public int getAttemptsRemaining();
@@ -11518,6 +11451,88 @@
method @Deprecated public static android.telephony.SubscriptionPlan.Builder createRecurringWeekly(java.time.ZonedDateTime);
}
+ public class TelephonyCallback {
+ field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED = 23; // 0x17
+ field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED = 35; // 0x23
+ field @RequiresPermission("android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH") public static final int EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED = 10; // 0xa
+ field @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_BARRING_INFO_CHANGED = 32; // 0x20
+ field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_CALL_ATTRIBUTES_CHANGED = 27; // 0x1b
+ field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_CALL_DISCONNECT_CAUSE_CHANGED = 26; // 0x1a
+ field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_CALL_FORWARDING_INDICATOR_CHANGED = 4; // 0x4
+ field @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) public static final int EVENT_CALL_STATE_CHANGED = 6; // 0x6
+ field public static final int EVENT_CARRIER_NETWORK_CHANGED = 17; // 0x11
+ field @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static final int EVENT_CELL_INFO_CHANGED = 11; // 0xb
+ field @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static final int EVENT_CELL_LOCATION_CHANGED = 5; // 0x5
+ field public static final int EVENT_DATA_ACTIVATION_STATE_CHANGED = 19; // 0x13
+ field public static final int EVENT_DATA_ACTIVITY_CHANGED = 8; // 0x8
+ field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED = 14; // 0xe
+ field public static final int EVENT_DATA_CONNECTION_STATE_CHANGED = 7; // 0x7
+ field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_DATA_ENABLED_CHANGED = 34; // 0x22
+ field public static final int EVENT_DISPLAY_INFO_CHANGED = 21; // 0x15
+ field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_EMERGENCY_NUMBER_LIST_CHANGED = 25; // 0x19
+ field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED = 28; // 0x1c
+ field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_MESSAGE_WAITING_INDICATOR_CHANGED = 3; // 0x3
+ field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_OEM_HOOK_RAW = 15; // 0xf
+ field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int EVENT_OUTGOING_EMERGENCY_CALL = 29; // 0x1d
+ field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int EVENT_OUTGOING_EMERGENCY_SMS = 30; // 0x1e
+ field public static final int EVENT_PHONE_CAPABILITY_CHANGED = 22; // 0x16
+ field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 33; // 0x21
+ field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PRECISE_CALL_STATE_CHANGED = 12; // 0xc
+ field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED = 13; // 0xd
+ field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_RADIO_POWER_STATE_CHANGED = 24; // 0x18
+ field @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_REGISTRATION_FAILURE = 31; // 0x1f
+ field public static final int EVENT_SERVICE_STATE_CHANGED = 1; // 0x1
+ field public static final int EVENT_SIGNAL_STRENGTHS_CHANGED = 9; // 0x9
+ field public static final int EVENT_SIGNAL_STRENGTH_CHANGED = 2; // 0x2
+ field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_SRVCC_STATE_CHANGED = 16; // 0x10
+ field public static final int EVENT_USER_MOBILE_DATA_STATE_CHANGED = 20; // 0x14
+ field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_VOICE_ACTIVATION_STATE_CHANGED = 18; // 0x12
+ }
+
+ public static interface TelephonyCallback.AllowedNetworkTypesListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onAllowedNetworkTypesChanged(@NonNull java.util.Map<java.lang.Integer,java.lang.Long>);
+ }
+
+ public static interface TelephonyCallback.CallAttributesListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
+ }
+
+ public static interface TelephonyCallback.DataEnabledListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onDataEnabledChanged(boolean, int);
+ }
+
+ public static interface TelephonyCallback.OutgoingEmergencyCallListener {
+ method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
+ }
+
+ public static interface TelephonyCallback.OutgoingEmergencySmsListener {
+ method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber, int);
+ }
+
+ public static interface TelephonyCallback.PhoneCapabilityListener {
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onPhoneCapabilityChanged(@NonNull android.telephony.PhoneCapability);
+ }
+
+ public static interface TelephonyCallback.PhysicalChannelConfigListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPhysicalChannelConfigChanged(@NonNull java.util.List<android.telephony.PhysicalChannelConfig>);
+ }
+
+ public static interface TelephonyCallback.PreciseCallStateListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
+ }
+
+ public static interface TelephonyCallback.RadioPowerStateListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onRadioPowerStateChanged(int);
+ }
+
+ public static interface TelephonyCallback.SrvccStateListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onSrvccStateChanged(int);
+ }
+
+ public static interface TelephonyCallback.VoiceActivationStateListener {
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onVoiceActivationStateChanged(int);
+ }
+
public final class TelephonyHistogram implements android.os.Parcelable {
ctor public TelephonyHistogram(int, int, int);
ctor public TelephonyHistogram(android.telephony.TelephonyHistogram);
@@ -13307,10 +13322,12 @@
public final class SipMessage implements android.os.Parcelable {
ctor public SipMessage(@NonNull String, @NonNull String, @NonNull byte[]);
method public int describeContents();
+ method @Nullable public String getCallIdParameter();
method @NonNull public byte[] getContent();
method @NonNull public byte[] getEncodedMessage();
method @NonNull public String getHeaderSection();
method @NonNull public String getStartLine();
+ method @Nullable public String getViaBranchParameter();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.SipMessage> CREATOR;
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index e4757e6..a57d824 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -259,6 +259,10 @@
method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void stopDream();
}
+ public final class GameManager {
+ method @RequiresPermission("android.permission.MANAGE_GAME_MODE") public void setGameMode(@NonNull String, int);
+ }
+
public abstract class HomeVisibilityListener {
ctor public HomeVisibilityListener();
method public abstract void onHomeVisibilityChanged(boolean);
@@ -298,7 +302,7 @@
}
public final class PendingIntent implements android.os.Parcelable {
- method @Nullable @RequiresPermission("android.permission.GET_INTENT_SENDER_INTENT") public java.util.List<android.content.pm.ResolveInfo> queryIntentComponents(int);
+ method @NonNull @RequiresPermission("android.permission.GET_INTENT_SENDER_INTENT") public java.util.List<android.content.pm.ResolveInfo> queryIntentComponents(int);
field @Deprecated public static final int FLAG_MUTABLE_UNAUDITED = 33554432; // 0x2000000
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index bc79813..d040938 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -31,6 +31,7 @@
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.ContextParams;
import android.content.ContextWrapper;
import android.content.IContentProvider;
import android.content.IIntentReceiver;
@@ -220,8 +221,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final String mOpPackageName;
- /** Attribution tag of this context */
- private final @Nullable String mAttributionTag;
+ private final @NonNull ContextParams mParams;
private final @NonNull ResourcesManager mResourcesManager;
@UnsupportedAppUsage
@@ -469,7 +469,12 @@
/** @hide */
@Override
public @Nullable String getAttributionTag() {
- return mAttributionTag;
+ return mParams.getAttributionTag();
+ }
+
+ @Override
+ public @Nullable ContextParams getParams() {
+ return mParams;
}
@Override
@@ -2046,6 +2051,11 @@
if (permission == null) {
throw new IllegalArgumentException("permission is null");
}
+ if (mParams.isRenouncedPermission(permission)
+ && pid == android.os.Process.myPid() && uid == android.os.Process.myUid()) {
+ Log.v(TAG, "Treating renounced permission " + permission + " as denied");
+ return PERMISSION_DENIED;
+ }
return PermissionManager.checkPermission(permission, pid, uid);
}
@@ -2055,6 +2065,11 @@
if (permission == null) {
throw new IllegalArgumentException("permission is null");
}
+ if (mParams.isRenouncedPermission(permission)
+ && pid == android.os.Process.myPid() && uid == android.os.Process.myUid()) {
+ Log.v(TAG, "Treating renounced permission " + permission + " as denied");
+ return PERMISSION_DENIED;
+ }
try {
return ActivityManager.getService().checkPermissionWithToken(
@@ -2092,6 +2107,10 @@
if (permission == null) {
throw new IllegalArgumentException("permission is null");
}
+ if (mParams.isRenouncedPermission(permission)) {
+ Log.v(TAG, "Treating renounced permission " + permission + " as denied");
+ return PERMISSION_DENIED;
+ }
return checkPermission(permission, Process.myPid(), Process.myUid());
}
@@ -2392,8 +2411,9 @@
LoadedApk pi = mMainThread.getPackageInfo(application, mResources.getCompatibilityInfo(),
flags | CONTEXT_REGISTER_PACKAGE);
if (pi != null) {
- ContextImpl c = new ContextImpl(this, mMainThread, pi, null, null, mToken,
- new UserHandle(UserHandle.getUserId(application.uid)), flags, null, null);
+ ContextImpl c = new ContextImpl(this, mMainThread, pi, ContextParams.EMPTY, null,
+ mToken, new UserHandle(UserHandle.getUserId(application.uid)),
+ flags, null, null);
final int displayId = getDisplayId();
final Integer overrideDisplayId = mForceDisplayOverrideInResources
@@ -2422,14 +2442,14 @@
if (packageName.equals("system") || packageName.equals("android")) {
// The system resources are loaded in every application, so we can safely copy
// the context without reloading Resources.
- return new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag, null,
+ return new ContextImpl(this, mMainThread, mPackageInfo, mParams, null,
mToken, user, flags, null, null);
}
LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier());
if (pi != null) {
- ContextImpl c = new ContextImpl(this, mMainThread, pi, mAttributionTag, null,
+ ContextImpl c = new ContextImpl(this, mMainThread, pi, mParams, null,
mToken, user, flags, null, null);
final int displayId = getDisplayId();
@@ -2468,7 +2488,7 @@
final String[] paths = mPackageInfo.getSplitPaths(splitName);
final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo,
- mAttributionTag, splitName, mToken, mUser, mFlags, classLoader, null);
+ mParams, splitName, mToken, mUser, mFlags, classLoader, null);
context.setResources(ResourcesManager.getInstance().getResources(
mToken,
@@ -2501,7 +2521,7 @@
overrideConfiguration = displayAdjustedConfig;
}
- ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag,
+ ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mParams,
mSplitName, mToken, mUser, mFlags, mClassLoader, null);
final int displayId = getDisplayId();
@@ -2519,7 +2539,7 @@
throw new IllegalArgumentException("display must not be null");
}
- ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag,
+ ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mParams,
mSplitName, mToken, mUser, mFlags, mClassLoader, null);
final int displayId = display.getDisplayId();
@@ -2577,7 +2597,7 @@
ContextImpl createBaseWindowContext(IBinder token, Display display) {
- ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag,
+ ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mParams,
mSplitName, token, mUser, mFlags, mClassLoader, null);
// Window contexts receive configurations directly from the server and as such do not
// need to override their display in ResourcesManager.
@@ -2606,17 +2626,23 @@
compatInfo, mClassLoader, loaders);
}
+ @NonNull
+ @Override
+ public Context createContext(@NonNull ContextParams params) {
+ return new ContextImpl(this, mMainThread, mPackageInfo, params, mSplitName,
+ mToken, mUser, mFlags, mClassLoader, null);
+ }
+
@Override
public @NonNull Context createAttributionContext(@Nullable String attributionTag) {
- return new ContextImpl(this, mMainThread, mPackageInfo, attributionTag, mSplitName,
- mToken, mUser, mFlags, mClassLoader, null);
+ return createContext(new ContextParams.Builder().setAttributionTag(attributionTag).build());
}
@Override
public Context createDeviceProtectedStorageContext() {
final int flags = (mFlags & ~Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE)
| Context.CONTEXT_DEVICE_PROTECTED_STORAGE;
- return new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag, mSplitName,
+ return new ContextImpl(this, mMainThread, mPackageInfo, mParams, mSplitName,
mToken, mUser, flags, mClassLoader, null);
}
@@ -2624,7 +2650,7 @@
public Context createCredentialProtectedStorageContext() {
final int flags = (mFlags & ~Context.CONTEXT_DEVICE_PROTECTED_STORAGE)
| Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE;
- return new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag, mSplitName,
+ return new ContextImpl(this, mMainThread, mPackageInfo, mParams, mSplitName,
mToken, mUser, flags, mClassLoader, null);
}
@@ -2798,8 +2824,8 @@
@UnsupportedAppUsage
static ContextImpl createSystemContext(ActivityThread mainThread) {
LoadedApk packageInfo = new LoadedApk(mainThread);
- ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, null,
- 0, null, null);
+ ContextImpl context = new ContextImpl(null, mainThread, packageInfo,
+ ContextParams.EMPTY, null, null, null, 0, null, null);
context.setResources(packageInfo.getResources());
context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
context.mResourcesManager.getDisplayMetrics());
@@ -2816,8 +2842,8 @@
*/
static ContextImpl createSystemUiContext(ContextImpl systemContext, int displayId) {
final LoadedApk packageInfo = systemContext.mPackageInfo;
- ContextImpl context = new ContextImpl(null, systemContext.mMainThread, packageInfo, null,
- null, null, null, 0, null, null);
+ ContextImpl context = new ContextImpl(null, systemContext.mMainThread, packageInfo,
+ ContextParams.EMPTY, null, null, null, 0, null, null);
context.setResources(createResources(null, packageInfo, null, displayId, null,
packageInfo.getCompatibilityInfo(), null));
context.updateDisplay(displayId);
@@ -2841,8 +2867,8 @@
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo,
String opPackageName) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
- ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, null,
- 0, null, opPackageName);
+ ContextImpl context = new ContextImpl(null, mainThread, packageInfo,
+ ContextParams.EMPTY, null, null, null, 0, null, opPackageName);
context.setResources(packageInfo.getResources());
context.mContextType = isSystemOrSystemUI(context) ? CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI
: CONTEXT_TYPE_NON_UI;
@@ -2871,7 +2897,7 @@
}
}
- ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null,
+ ContextImpl context = new ContextImpl(null, mainThread, packageInfo, ContextParams.EMPTY,
activityInfo.splitName, activityToken, null, 0, classLoader, null);
context.mContextType = CONTEXT_TYPE_ACTIVITY;
@@ -2904,7 +2930,7 @@
}
private ContextImpl(@Nullable ContextImpl container, @NonNull ActivityThread mainThread,
- @NonNull LoadedApk packageInfo, @Nullable String attributionTag,
+ @NonNull LoadedApk packageInfo, @NonNull ContextParams params,
@Nullable String splitName, @Nullable IBinder token, @Nullable UserHandle user,
int flags, @Nullable ClassLoader classLoader, @Nullable String overrideOpPackageName) {
mOuterContext = this;
@@ -2959,7 +2985,7 @@
}
mOpPackageName = overrideOpPackageName != null ? overrideOpPackageName : opPackageName;
- mAttributionTag = attributionTag;
+ mParams = Objects.requireNonNull(params);
mContentResolver = new ApplicationContentResolver(this, mainThread);
}
diff --git a/core/java/android/app/GameManager.java b/core/java/android/app/GameManager.java
index ac1fa1e..47de040 100644
--- a/core/java/android/app/GameManager.java
+++ b/core/java/android/app/GameManager.java
@@ -18,8 +18,11 @@
import android.Manifest;
import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.annotation.UserHandleAware;
import android.content.Context;
import android.os.Handler;
@@ -27,57 +30,87 @@
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
-import com.android.internal.annotations.VisibleForTesting;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* The GameManager allows system apps to modify and query the game mode of apps.
- *
- * @hide
*/
-@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
@SystemService(Context.GAME_SERVICE)
public final class GameManager {
private static final String TAG = "GameManager";
- private final Context mContext;
+ private final @Nullable Context mContext;
private final IGameManagerService mService;
- @IntDef(flag = false, prefix = { "GAME_MODE_" }, value = {
+ /** @hide */
+ @IntDef(flag = false, prefix = {"GAME_MODE_"}, value = {
GAME_MODE_UNSUPPORTED, // 0
GAME_MODE_STANDARD, // 1
GAME_MODE_PERFORMANCE, // 2
GAME_MODE_BATTERY, // 3
})
@Retention(RetentionPolicy.SOURCE)
- public @interface GameMode {}
+ public @interface GameMode {
+ }
+ /**
+ * Game mode is not supported for this application.
+ */
public static final int GAME_MODE_UNSUPPORTED = 0;
+
+ /**
+ * Standard game mode means the platform will use the game's default
+ * performance characteristics.
+ */
public static final int GAME_MODE_STANDARD = 1;
+
+ /**
+ * Performance game mode maximizes the game's performance.
+ * <p>
+ * This game mode is highly likely to increase battery consumption.
+ */
public static final int GAME_MODE_PERFORMANCE = 2;
+
+ /**
+ * Battery game mode will save battery and give longer game play time.
+ */
public static final int GAME_MODE_BATTERY = 3;
- public GameManager(Context context, Handler handler) throws ServiceNotFoundException {
+ GameManager(Context context, Handler handler) throws ServiceNotFoundException {
mContext = context;
mService = IGameManagerService.Stub.asInterface(
ServiceManager.getServiceOrThrow(Context.GAME_SERVICE));
}
- @VisibleForTesting
- public GameManager(Context context, IGameManagerService gameManagerService) {
- mContext = context;
- mService = gameManagerService;
+ /**
+ * Return the user selected game mode for this application.
+ * <p>
+ * An application can use <code>android:isGame="true"</code> or
+ * <code>android:appCategory="game"</code> to indicate that the application is a game. If an
+ * application is not a game, always return {@link #GAME_MODE_UNSUPPORTED}.
+ * <p>
+ * Developers should call this API every time the application is resumed.
+ */
+ public @GameMode int getGameMode() {
+ try {
+ return mService.getGameMode(mContext.getPackageName(), mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
- * Returns the game mode for the given package.
+ * Gets the game mode for the given package.
+ * <p>
+ * The caller must have {@link android.Manifest.permission#MANAGE_GAME_MODE}.
+ *
+ * @hide
*/
@UserHandleAware
@RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
- public @GameMode int getGameMode(String packageName) {
+ public @GameMode int getGameMode(@NonNull String packageName) {
try {
return mService.getGameMode(packageName, mContext.getUserId());
} catch (RemoteException e) {
@@ -87,10 +120,15 @@
/**
* Sets the game mode for the given package.
+ * <p>
+ * The caller must have {@link android.Manifest.permission#MANAGE_GAME_MODE}.
+ *
+ * @hide
*/
+ @TestApi
@UserHandleAware
@RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
- public void setGameMode(String packageName, @GameMode int gameMode) {
+ public void setGameMode(@NonNull String packageName, @GameMode int gameMode) {
try {
mService.setGameMode(packageName, gameMode, mContext.getUserId());
} catch (RemoteException e) {
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 3a8172e..ef0dcab 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -706,7 +706,7 @@
boolean stopProfile(int userId);
/** Called by PendingIntent.queryIntentComponents() */
- List<ResolveInfo> queryIntentComponentsForIntentSender(in IIntentSender sender, int matchFlags);
+ ParceledListSlice queryIntentComponentsForIntentSender(in IIntentSender sender, int matchFlags);
int getUidProcessCapabilities(int uid, in String callingPackage);
}
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl b/core/java/android/app/IGameManager.aidl
similarity index 67%
copy from core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl
copy to core/java/android/app/IGameManager.aidl
index ddb5ef8..3730de8 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl
+++ b/core/java/android/app/IGameManager.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -14,6 +14,15 @@
* limitations under the License.
*/
-package android.content.pm.verify.domain;
+package android.app;
-parcelable DomainVerificationUserSelection;
+/**
+ * Interface used to control Game Manager modes.
+ * @hide
+ */
+interface IGameManager {
+ /**
+ * Return the current Game Mode for the calling package.
+ */
+ int getGameMode();
+}
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 549bd4b..009c936 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -26,7 +26,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemApi.Client;
import android.annotation.TestApi;
@@ -41,6 +40,7 @@
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager.ResolveInfoFlags;
+import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.os.Build;
import android.os.Bundle;
@@ -60,6 +60,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -1239,14 +1240,17 @@
* @param flags MATCH_* flags from {@link android.content.pm.PackageManager}.
* @hide
*/
- @SuppressLint("NullableCollection")
@RequiresPermission(permission.GET_INTENT_SENDER_INTENT)
@SystemApi(client = Client.MODULE_LIBRARIES)
@TestApi
- public @Nullable List<ResolveInfo> queryIntentComponents(@ResolveInfoFlags int flags) {
+ public @NonNull List<ResolveInfo> queryIntentComponents(@ResolveInfoFlags int flags) {
try {
- return ActivityManager.getService()
+ ParceledListSlice<ResolveInfo> parceledList = ActivityManager.getService()
.queryIntentComponentsForIntentSender(mTarget, flags);
+ if (parceledList == null) {
+ return Collections.emptyList();
+ }
+ return parceledList.getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index e16e40b..43c14a9 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -71,7 +71,6 @@
import android.content.pm.PackageManager;
import android.content.pm.ShortcutManager;
import android.content.pm.verify.domain.DomainVerificationManager;
-import android.content.pm.verify.domain.DomainVerificationManagerImpl;
import android.content.pm.verify.domain.IDomainVerificationManager;
import android.content.res.Resources;
import android.content.rollback.RollbackManagerFrameworkInitializer;
@@ -1422,7 +1421,6 @@
}
});
- // TODO(b/159952358): Only register this service for the domain verification agent?
registerService(Context.DOMAIN_VERIFICATION_SERVICE, DomainVerificationManager.class,
new CachedServiceFetcher<DomainVerificationManager>() {
@Override
@@ -1432,7 +1430,7 @@
Context.DOMAIN_VERIFICATION_SERVICE);
IDomainVerificationManager service =
IDomainVerificationManager.Stub.asInterface(binder);
- return new DomainVerificationManagerImpl(context, service);
+ return new DomainVerificationManager(context, service);
}
});
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index b919bfc..ccf41e5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2997,6 +2997,7 @@
*/
// TODO(b/173541467): should it throw SecurityException if caller is not admin?
public boolean isSafeOperation(@OperationSafetyReason int reason) {
+ throwIfParentInstance("isSafeOperation");
if (mService == null) return false;
try {
@@ -6437,6 +6438,74 @@
}
/**
+ * Called by a device or profile owner, or delegated certificate chooser (an app that has been
+ * delegated the {@link #DELEGATION_CERT_SELECTION} privilege), to allow using a KeyChain key
+ * pair for authentication to Wifi networks. The key can then be used in configurations passed
+ * to {@link android.net.wifi.WifiManager#addNetwork}.
+ *
+ * @param alias The alias of the key pair.
+ * @return {@code true} if the operation was set successfully, {@code false} otherwise.
+ *
+ * @throws SecurityException if the caller is not a device owner, a profile owner or
+ * delegated certificate chooser.
+ * @see #revokeKeyPairFromWifiAuth
+ */
+ public boolean grantKeyPairToWifiAuth(@NonNull String alias) {
+ throwIfParentInstance("grantKeyPairToWifiAuth");
+ try {
+ return mService.setKeyGrantToWifiAuth(mContext.getPackageName(), alias, true);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return false;
+ }
+
+ /**
+ * Called by a device or profile owner, or delegated certificate chooser (an app that has been
+ * delegated the {@link #DELEGATION_CERT_SELECTION} privilege), to deny using a KeyChain key
+ * pair for authentication to Wifi networks. Configured networks using this key won't be able to
+ * authenticate.
+ *
+ * @param alias The alias of the key pair.
+ * @return {@code true} if the operation was set successfully, {@code false} otherwise.
+ *
+ * @throws SecurityException if the caller is not a device owner, a profile owner or
+ * delegated certificate chooser.
+ * @see #grantKeyPairToWifiAuth
+ */
+ public boolean revokeKeyPairFromWifiAuth(@NonNull String alias) {
+ throwIfParentInstance("revokeKeyPairFromWifiAuth");
+ try {
+ return mService.setKeyGrantToWifiAuth(mContext.getPackageName(), alias, false);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return false;
+ }
+
+ /**
+ * Called by a device or profile owner, or delegated certificate chooser (an app that has been
+ * delegated the {@link #DELEGATION_CERT_SELECTION} privilege), to query whether a KeyChain key
+ * pair can be used for authentication to Wifi networks.
+ *
+ * @param alias The alias of the key pair.
+ * @return {@code true} if the key pair can be used, {@code false} otherwise.
+ *
+ * @throws SecurityException if the caller is not a device owner, a profile owner or
+ * delegated certificate chooser.
+ * @see #grantKeyPairToWifiAuth
+ */
+ public boolean isKeyPairGrantedToWifiAuth(@NonNull String alias) {
+ throwIfParentInstance("isKeyPairGrantedToWifiAuth");
+ try {
+ return mService.isKeyPairGrantedToWifiAuth(mContext.getPackageName(), alias);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return false;
+ }
+
+ /**
* Returns {@code true} if the device supports attestation of device identifiers in addition
* to key attestation. See
* {@link #generateKeyPair(ComponentName, String, KeyGenParameterSpec, int)}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index ac1592d..25ca599 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -479,6 +479,8 @@
boolean setKeyGrantForApp(in ComponentName admin, String callerPackage, String alias, String packageName, boolean hasGrant);
List<String> getKeyPairGrants(in String callerPackage, in String alias);
+ boolean setKeyGrantToWifiAuth(String callerPackage, String alias, boolean hasGrant);
+ boolean isKeyPairGrantedToWifiAuth(String callerPackage, String alias);
void setUserControlDisabledPackages(in ComponentName admin, in List<String> packages);
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 22492cc..94a4fde0 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -403,7 +403,7 @@
public void onFullBackup(FullBackupDataOutput data) throws IOException {
FullBackup.BackupScheme backupScheme = FullBackup.getBackupScheme(this,
mOperationType);
- if (!isDeviceToDeviceMigration() && !backupScheme.isFullBackupContentEnabled()) {
+ if (!backupScheme.isFullBackupEnabled(data.getTransportFlags())) {
return;
}
@@ -911,7 +911,7 @@
}
FullBackup.BackupScheme bs = FullBackup.getBackupScheme(this, mOperationType);
- if (!bs.isFullBackupContentEnabled()) {
+ if (!bs.isFullRestoreEnabled()) {
if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
Log.v(FullBackup.TAG_XML_PARSER,
"onRestoreFile \"" + destination.getCanonicalPath()
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index 829b6cd..9b543b5 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -99,6 +99,8 @@
public static final String FLAG_REQUIRED_DEVICE_TO_DEVICE_TRANSFER = "deviceToDeviceTransfer";
public static final String FLAG_REQUIRED_FAKE_CLIENT_SIDE_ENCRYPTION =
"fakeClientSideEncryption";
+ private static final String FLAG_DISABLE_IF_NO_ENCRYPTION_CAPABILITIES
+ = "disableIfNoEncryptionCapabilities";
/**
* When this change is enabled, include / exclude rules specified via
@@ -307,6 +309,10 @@
// lazy initialized, only when needed
private StorageVolume[] mVolumes = null;
+ // Properties the transport must have (e.g. encryption) for the operation to go ahead.
+ @Nullable private Integer mRequiredTransportFlags;
+ @Nullable private Boolean mIsUsingNewScheme;
+
/**
* Parse out the semantic domains into the correct physical location.
*/
@@ -453,6 +459,35 @@
}
}
+ boolean isFullBackupEnabled(int transportFlags) {
+ try {
+ if (isUsingNewScheme()) {
+ int requiredTransportFlags = getRequiredTransportFlags();
+ // All bits that are set in requiredTransportFlags must be set in
+ // transportFlags.
+ return (transportFlags & requiredTransportFlags) == requiredTransportFlags;
+ }
+ } catch (IOException | XmlPullParserException e) {
+ Slog.w(TAG, "Failed to interpret the backup scheme: " + e);
+ return false;
+ }
+
+ return isFullBackupContentEnabled();
+ }
+
+ boolean isFullRestoreEnabled() {
+ try {
+ if (isUsingNewScheme()) {
+ return true;
+ }
+ } catch (IOException | XmlPullParserException e) {
+ Slog.w(TAG, "Failed to interpret the backup scheme: " + e);
+ return false;
+ }
+
+ return isFullBackupContentEnabled();
+ }
+
boolean isFullBackupContentEnabled() {
if (mFullBackupContent < 0) {
// android:fullBackupContent="false", bail.
@@ -491,10 +526,30 @@
return mExcludes;
}
+ private synchronized int getRequiredTransportFlags()
+ throws IOException, XmlPullParserException {
+ if (mRequiredTransportFlags == null) {
+ maybeParseBackupSchemeLocked();
+ }
+
+ return mRequiredTransportFlags;
+ }
+
+ private synchronized boolean isUsingNewScheme()
+ throws IOException, XmlPullParserException {
+ if (mIsUsingNewScheme == null) {
+ maybeParseBackupSchemeLocked();
+ }
+
+ return mIsUsingNewScheme;
+ }
+
private void maybeParseBackupSchemeLocked() throws IOException, XmlPullParserException {
// This not being null is how we know that we've tried to parse the xml already.
mIncludes = new ArrayMap<String, Set<PathWithRequiredFlags>>();
mExcludes = new ArraySet<PathWithRequiredFlags>();
+ mRequiredTransportFlags = 0;
+ mIsUsingNewScheme = false;
if (mFullBackupContent == 0 && mDataExtractionRules == 0) {
// No scheme specified via either new or legacy config, will copy everything.
@@ -535,12 +590,14 @@
}
if (!mExcludes.isEmpty() || !mIncludes.isEmpty()) {
// Found configuration in the new config, we will use it.
+ mIsUsingNewScheme = true;
return;
}
}
if (operationType == OperationType.MIGRATION
&& CompatChanges.isChangeEnabled(IGNORE_FULL_BACKUP_CONTENT_IN_D2D)) {
+ mIsUsingNewScheme = true;
return;
}
@@ -584,13 +641,24 @@
continue;
}
- // TODO(b/180523028): Parse required attributes for rules (e.g. encryption).
+ parseRequiredTransportFlags(parser, configSection);
parseRules(parser, excludes, includes, Optional.of(0), configSection);
}
logParsingResults(excludes, includes);
}
+ private void parseRequiredTransportFlags(XmlPullParser parser,
+ @ConfigSection String configSection) {
+ if (ConfigSection.CLOUD_BACKUP.equals(configSection)) {
+ String encryptionAttribute = parser.getAttributeValue(/* namespace */ null,
+ FLAG_DISABLE_IF_NO_ENCRYPTION_CAPABILITIES);
+ if ("true".equals(encryptionAttribute)) {
+ mRequiredTransportFlags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
+ }
+ }
+ }
+
@VisibleForTesting
public void parseBackupSchemeFromXmlLocked(XmlPullParser parser,
Set<PathWithRequiredFlags> excludes,
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 081f4fd..e6a4656 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -334,10 +334,19 @@
public static final int LOCUS_ID_SET = 30;
/**
+ * An event type denoting that a component in the package has been used (e.g. broadcast
+ * receiver, service, content provider). This generally matches up with usage that would
+ * cause an app to leave force stop. The component itself is not provided as we are only
+ * interested in whether the package is used, not the component itself.
+ * @hide
+ */
+ public static final int APP_COMPONENT_USED = 31;
+
+ /**
* Keep in sync with the greatest event type value.
* @hide
*/
- public static final int MAX_EVENT_TYPE = 30;
+ public static final int MAX_EVENT_TYPE = 31;
/** @hide */
public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index fc54c71..d79fac5 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -39,6 +39,7 @@
import android.util.AttributeSet;
import android.util.Log;
import android.util.Pair;
+import android.util.SizeF;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.Gravity;
@@ -56,7 +57,6 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
import java.util.concurrent.Executor;
/**
@@ -93,7 +93,7 @@
int mLayoutId = -1;
private InteractionHandler mInteractionHandler;
private boolean mOnLightBackground;
- private PointF mCurrentSize = null;
+ private SizeF mCurrentSize = null;
private RemoteViews.ColorResources mColorResources = null;
// Stores the last remote views last inflated.
private RemoteViews mLastInflatedRemoteViews = null;
@@ -253,9 +253,33 @@
}
}
+ private SizeF computeSizeFromLayout(int left, int top, int right, int bottom) {
+ Rect padding = getDefaultPadding();
+ float density = getResources().getDisplayMetrics().density;
+ return new SizeF(
+ (right - left - padding.right - padding.left) / density,
+ (bottom - top - padding.bottom - padding.top) / density
+ );
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
try {
+ SizeF oldSize = mCurrentSize;
+ SizeF newSize = computeSizeFromLayout(left, top, right, bottom);
+ mCurrentSize = newSize;
+ if (mLastInflatedRemoteViews != null) {
+ RemoteViews toApply = mLastInflatedRemoteViews.getRemoteViewsToApplyIfDifferent(
+ oldSize, newSize);
+ if (toApply != null) {
+ applyRemoteViews(toApply, false);
+ measureChildWithMargins(mView,
+ MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
+ 0 /* widthUsed */,
+ MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY),
+ 0 /* heightUsed */);
+ }
+ }
super.onLayout(changed, left, top, right, bottom);
} catch (final RuntimeException e) {
Log.e(TAG, "Remote provider threw runtime exception, using error view instead.", e);
@@ -309,7 +333,7 @@
* again. Typically, this will be size of the widget in landscape and portrait.
* On some foldables, this might include the size on the outer and inner screens.
*/
- public void updateAppWidgetSize(@NonNull Bundle newOptions, @NonNull List<PointF> sizes) {
+ public void updateAppWidgetSize(@NonNull Bundle newOptions, @NonNull List<SizeF> sizes) {
AppWidgetManager widgetManager = AppWidgetManager.getInstance(mContext);
Rect padding = getDefaultPadding();
@@ -318,20 +342,20 @@
float xPaddingDips = (padding.left + padding.right) / density;
float yPaddingDips = (padding.top + padding.bottom) / density;
- ArrayList<PointF> paddedSizes = new ArrayList<>(sizes.size());
+ ArrayList<SizeF> paddedSizes = new ArrayList<>(sizes.size());
float minWidth = Float.MAX_VALUE;
float maxWidth = 0;
float minHeight = Float.MAX_VALUE;
float maxHeight = 0;
for (int i = 0; i < sizes.size(); i++) {
- PointF size = sizes.get(i);
- PointF paddedPoint = new PointF(Math.max(0.f, size.x - xPaddingDips),
- Math.max(0.f, size.y - yPaddingDips));
- paddedSizes.add(paddedPoint);
- minWidth = Math.min(minWidth, paddedPoint.x);
- maxWidth = Math.max(maxWidth, paddedPoint.x);
- minHeight = Math.min(minHeight, paddedPoint.y);
- maxHeight = Math.max(maxHeight, paddedPoint.y);
+ SizeF size = sizes.get(i);
+ SizeF paddedSize = new SizeF(Math.max(0.f, size.getWidth() - xPaddingDips),
+ Math.max(0.f, size.getHeight() - yPaddingDips));
+ paddedSizes.add(paddedSize);
+ minWidth = Math.min(minWidth, paddedSize.getWidth());
+ maxWidth = Math.max(maxWidth, paddedSize.getWidth());
+ minHeight = Math.min(minHeight, paddedSize.getHeight());
+ maxHeight = Math.max(maxHeight, paddedSize.getHeight());
}
if (paddedSizes.equals(
widgetManager.getAppWidgetOptions(mAppWidgetId).<PointF>getParcelableArrayList(
@@ -348,35 +372,6 @@
}
/**
- * Set the current size of the widget. This should be the full area the AppWidgetHostView is
- * given. Padding added by the framework will be accounted for automatically.
- *
- * This size will be used to choose the appropriate layout the next time the {@link RemoteViews}
- * is re-inflated, if it was created with {@link RemoteViews#RemoteViews(Map)} .
- */
- public void setCurrentSize(@NonNull PointF size) {
- Rect padding = getDefaultPadding();
- float density = getResources().getDisplayMetrics().density;
- float xPaddingDips = (padding.left + padding.right) / density;
- float yPaddingDips = (padding.top + padding.bottom) / density;
- PointF newSize = new PointF(size.x - xPaddingDips, size.y - yPaddingDips);
- if (!newSize.equals(mCurrentSize)) {
- mCurrentSize = newSize;
- reapplyLastRemoteViews();
- }
- }
-
- /**
- * Clear the current size, indicating it is not currently known.
- */
- public void clearCurrentSize() {
- if (mCurrentSize != null) {
- mCurrentSize = null;
- reapplyLastRemoteViews();
- }
- }
-
- /**
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -514,23 +509,22 @@
mLayoutId = -1;
mViewMode = VIEW_MODE_DEFAULT;
} else {
+ // Select the remote view we are actually going to apply.
+ RemoteViews rvToApply = remoteViews.getRemoteViewsToApply(mContext, mCurrentSize);
if (mOnLightBackground) {
- remoteViews = remoteViews.getDarkTextViews();
+ rvToApply = rvToApply.getDarkTextViews();
}
if (mAsyncExecutor != null && useAsyncIfPossible) {
- inflateAsync(remoteViews);
+ inflateAsync(rvToApply);
return;
}
- // Prepare a local reference to the remote Context so we're ready to
- // inflate any requested LayoutParams.
- mRemoteContext = getRemoteContext();
- int layoutId = remoteViews.getLayoutId();
+ int layoutId = rvToApply.getLayoutId();
// If our stale view has been prepared to match active, and the new
// layout matches, try recycling it
if (content == null && layoutId == mLayoutId) {
try {
- remoteViews.reapply(mContext, mView, mInteractionHandler, mCurrentSize,
+ rvToApply.reapply(mContext, mView, mInteractionHandler, mCurrentSize,
mColorResources);
content = mView;
recycled = true;
@@ -543,7 +537,7 @@
// Try normal RemoteView inflation
if (content == null) {
try {
- content = remoteViews.apply(mContext, this, mInteractionHandler,
+ content = rvToApply.apply(mContext, this, mInteractionHandler,
mCurrentSize, mColorResources);
if (LOGD) Log.d(TAG, "had to inflate new layout");
} catch (RuntimeException e) {
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 38919f6..a88aed7 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -219,7 +219,7 @@
public static final String OPTION_APPWIDGET_MAX_HEIGHT = "appWidgetMaxHeight";
/**
- * A bundle extra ({@code List<PointF>}) that contains the list of possible sizes, in dips, a
+ * A bundle extra ({@code List<SizeF>}) that contains the list of possible sizes, in dips, a
* widget instance can take.
*/
public static final String OPTION_APPWIDGET_SIZES = "appWidgetSizes";
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
index 102c98f..b07d6d5 100644
--- a/core/java/android/companion/AssociationRequest.java
+++ b/core/java/android/companion/AssociationRequest.java
@@ -60,10 +60,16 @@
/**
* Device profile: watch.
*
+ * If specified, the current request may have a modified UI to highlight that the device being
+ * set up is a specific kind of device, and some extra permissions may be granted to the app
+ * as a result.
+ *
+ * Using it requires declaring uses-permission
+ * {@link android.Manifest.permission#REQUEST_COMPANION_PROFILE_WATCH} in the manifest.
+ *
* @see AssociationRequest.Builder#setDeviceProfile
*/
- public static final String DEVICE_PROFILE_WATCH =
- "android.app.role.COMPANION_DEVICE_WATCH";
+ public static final String DEVICE_PROFILE_WATCH = "android.app.role.COMPANION_DEVICE_WATCH";
/** @hide */
@StringDef(value = { DEVICE_PROFILE_WATCH })
@@ -107,6 +113,17 @@
*/
private @Nullable String mDeviceProfilePrivilegesDescription = null;
+ /**
+ * The time at which his request was created
+ *
+ * @hide
+ */
+ private long mCreationTime;
+
+ private void onConstructed() {
+ mCreationTime = System.currentTimeMillis();
+ }
+
/** @hide */
public void setCallingPackage(@NonNull String pkg) {
mCallingPackage = pkg;
@@ -187,7 +204,7 @@
markUsed();
return new AssociationRequest(
mSingleDevice, emptyIfNull(mDeviceFilters),
- mDeviceProfile, null, null);
+ mDeviceProfile, null, null, -1L);
}
}
@@ -228,6 +245,8 @@
* The user-readable description of the device profile's privileges.
*
* Populated by the system.
+ * @param creationTime
+ * The time at which his request was created
* @hide
*/
@DataClass.Generated.Member
@@ -236,7 +255,8 @@
@NonNull List<DeviceFilter<?>> deviceFilters,
@Nullable @DeviceProfile String deviceProfile,
@Nullable String callingPackage,
- @Nullable String deviceProfilePrivilegesDescription) {
+ @Nullable String deviceProfilePrivilegesDescription,
+ long creationTime) {
this.mSingleDevice = singleDevice;
this.mDeviceFilters = deviceFilters;
com.android.internal.util.AnnotationValidations.validate(
@@ -246,8 +266,9 @@
DeviceProfile.class, null, mDeviceProfile);
this.mCallingPackage = callingPackage;
this.mDeviceProfilePrivilegesDescription = deviceProfilePrivilegesDescription;
+ this.mCreationTime = creationTime;
- // onConstructed(); // You can define this method to get a callback
+ onConstructed();
}
/**
@@ -284,6 +305,16 @@
return mDeviceProfilePrivilegesDescription;
}
+ /**
+ * The time at which his request was created
+ *
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public long getCreationTime() {
+ return mCreationTime;
+ }
+
@Override
@DataClass.Generated.Member
public String toString() {
@@ -295,7 +326,8 @@
"deviceFilters = " + mDeviceFilters + ", " +
"deviceProfile = " + mDeviceProfile + ", " +
"callingPackage = " + mCallingPackage + ", " +
- "deviceProfilePrivilegesDescription = " + mDeviceProfilePrivilegesDescription +
+ "deviceProfilePrivilegesDescription = " + mDeviceProfilePrivilegesDescription + ", " +
+ "creationTime = " + mCreationTime +
" }";
}
@@ -316,7 +348,8 @@
&& Objects.equals(mDeviceFilters, that.mDeviceFilters)
&& Objects.equals(mDeviceProfile, that.mDeviceProfile)
&& Objects.equals(mCallingPackage, that.mCallingPackage)
- && Objects.equals(mDeviceProfilePrivilegesDescription, that.mDeviceProfilePrivilegesDescription);
+ && Objects.equals(mDeviceProfilePrivilegesDescription, that.mDeviceProfilePrivilegesDescription)
+ && mCreationTime == that.mCreationTime;
}
@Override
@@ -331,6 +364,7 @@
_hash = 31 * _hash + Objects.hashCode(mDeviceProfile);
_hash = 31 * _hash + Objects.hashCode(mCallingPackage);
_hash = 31 * _hash + Objects.hashCode(mDeviceProfilePrivilegesDescription);
+ _hash = 31 * _hash + Long.hashCode(mCreationTime);
return _hash;
}
@@ -350,6 +384,7 @@
if (mDeviceProfile != null) dest.writeString(mDeviceProfile);
if (mCallingPackage != null) dest.writeString(mCallingPackage);
if (mDeviceProfilePrivilegesDescription != null) dest.writeString(mDeviceProfilePrivilegesDescription);
+ dest.writeLong(mCreationTime);
}
@Override
@@ -370,6 +405,7 @@
String deviceProfile = (flg & 0x4) == 0 ? null : in.readString();
String callingPackage = (flg & 0x8) == 0 ? null : in.readString();
String deviceProfilePrivilegesDescription = (flg & 0x10) == 0 ? null : in.readString();
+ long creationTime = in.readLong();
this.mSingleDevice = singleDevice;
this.mDeviceFilters = deviceFilters;
@@ -380,8 +416,9 @@
DeviceProfile.class, null, mDeviceProfile);
this.mCallingPackage = callingPackage;
this.mDeviceProfilePrivilegesDescription = deviceProfilePrivilegesDescription;
+ this.mCreationTime = creationTime;
- // onConstructed(); // You can define this method to get a callback
+ onConstructed();
}
@DataClass.Generated.Member
@@ -399,10 +436,10 @@
};
@DataClass.Generated(
- time = 1611692924843L,
+ time = 1614976943652L,
codegenVersion = "1.0.22",
sourceFile = "frameworks/base/core/java/android/companion/AssociationRequest.java",
- inputSignatures = "private static final java.lang.String LOG_TAG\npublic static final java.lang.String DEVICE_PROFILE_WATCH\nprivate boolean mSingleDevice\nprivate @com.android.internal.util.DataClass.PluralOf(\"deviceFilter\") @android.annotation.NonNull java.util.List<android.companion.DeviceFilter<?>> mDeviceFilters\nprivate @android.annotation.Nullable @android.companion.AssociationRequest.DeviceProfile java.lang.String mDeviceProfile\nprivate @android.annotation.Nullable java.lang.String mCallingPackage\nprivate @android.annotation.Nullable java.lang.String mDeviceProfilePrivilegesDescription\npublic void setCallingPackage(java.lang.String)\npublic void setDeviceProfilePrivilegesDescription(java.lang.String)\npublic @android.compat.annotation.UnsupportedAppUsage boolean isSingleDevice()\npublic @android.annotation.NonNull @android.compat.annotation.UnsupportedAppUsage java.util.List<android.companion.DeviceFilter<?>> getDeviceFilters()\nclass AssociationRequest extends java.lang.Object implements [android.os.Parcelable]\nprivate boolean mSingleDevice\nprivate @android.annotation.Nullable java.util.ArrayList<android.companion.DeviceFilter<?>> mDeviceFilters\nprivate @android.annotation.Nullable java.lang.String mDeviceProfile\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder setSingleDevice(boolean)\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder addDeviceFilter(android.companion.DeviceFilter<?>)\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder setDeviceProfile(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override android.companion.AssociationRequest build()\nclass Builder extends android.provider.OneTimeUseBuilder<android.companion.AssociationRequest> implements []\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true, genHiddenGetters=true, genParcelable=true, genHiddenConstructor=true, genBuilder=false)")
+ inputSignatures = "private static final java.lang.String LOG_TAG\npublic static final java.lang.String DEVICE_PROFILE_WATCH\nprivate boolean mSingleDevice\nprivate @com.android.internal.util.DataClass.PluralOf(\"deviceFilter\") @android.annotation.NonNull java.util.List<android.companion.DeviceFilter<?>> mDeviceFilters\nprivate @android.annotation.Nullable @android.companion.AssociationRequest.DeviceProfile java.lang.String mDeviceProfile\nprivate @android.annotation.Nullable java.lang.String mCallingPackage\nprivate @android.annotation.Nullable java.lang.String mDeviceProfilePrivilegesDescription\nprivate long mCreationTime\nprivate void onConstructed()\npublic void setCallingPackage(java.lang.String)\npublic void setDeviceProfilePrivilegesDescription(java.lang.String)\npublic @android.compat.annotation.UnsupportedAppUsage boolean isSingleDevice()\npublic @android.annotation.NonNull @android.compat.annotation.UnsupportedAppUsage java.util.List<android.companion.DeviceFilter<?>> getDeviceFilters()\nclass AssociationRequest extends java.lang.Object implements [android.os.Parcelable]\nprivate boolean mSingleDevice\nprivate @android.annotation.Nullable java.util.ArrayList<android.companion.DeviceFilter<?>> mDeviceFilters\nprivate @android.annotation.Nullable java.lang.String mDeviceProfile\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder setSingleDevice(boolean)\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder addDeviceFilter(android.companion.DeviceFilter<?>)\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder setDeviceProfile(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override android.companion.AssociationRequest build()\nclass Builder extends android.provider.OneTimeUseBuilder<android.companion.AssociationRequest> implements []\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true, genHiddenGetters=true, genParcelable=true, genHiddenConstructor=true, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 59646f10..b441b36 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -16,6 +16,7 @@
package android.companion;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -141,6 +142,10 @@
* <p>Calling this API requires a uses-feature
* {@link PackageManager#FEATURE_COMPANION_DEVICE_SETUP} declaration in the manifest</p>
*
+ * <p>When using {@link AssociationRequest#DEVICE_PROFILE_WATCH watch}
+ * {@link AssociationRequest.Builder#setDeviceProfile profile}, caller must also hold
+ * {@link Manifest.permission#REQUEST_COMPANION_PROFILE_WATCH}</p>
+ *
* @param request specific details about this request
* @param callback will be called once there's at least one device found for user to choose from
* @param handler A handler to control which thread the callback will be delivered on, or null,
@@ -148,6 +153,9 @@
*
* @see AssociationRequest
*/
+ @RequiresPermission(
+ value = Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH,
+ conditional = true)
public void associate(
@NonNull AssociationRequest request,
@NonNull Callback callback,
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index f3a4e1f..df5c58c 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -370,6 +370,15 @@
/*********** Hidden flags below this line ***********/
/**
+ * Flag for {@link #bindService}: This flag is only intended to be used by the system to
+ * indicate that a service binding is not considered as real package component usage and should
+ * not generate a {@link android.app.usage.UsageEvents.Event#APP_COMPONENT_USED} event in usage
+ * stats.
+ * @hide
+ */
+ public static final int BIND_NOT_APP_COMPONENT_USAGE = 0x00008000;
+
+ /**
* Flag for {@link #bindService}: allow the process hosting the target service to be treated
* as if it's as important as a perceptible app to the user and avoid the oom killer killing
* this process in low memory situations until there aren't any other processes left but the
@@ -879,6 +888,14 @@
return getAttributionTag();
}
+ /**
+ * Return the set of parameters which this Context was created with, if it
+ * was created via {@link #createContext(ContextParams)}.
+ */
+ public @Nullable ContextParams getParams() {
+ return null;
+ }
+
/** Return the full application info for this context's package. */
public abstract ApplicationInfo getApplicationInfo();
@@ -5514,8 +5531,6 @@
* {@link GameManager}.
*
* @see #getSystemService(String)
- *
- * @hide
*/
public static final String GAME_SERVICE = "game";
@@ -6368,6 +6383,19 @@
}
/**
+ * Creates a context with specific properties and behaviors.
+ *
+ * @param contextParams Parameters for how the new context should behave.
+ * @return A context with the specified behaviors.
+ *
+ * @see ContextParams
+ */
+ @NonNull
+ public Context createContext(@NonNull ContextParams contextParams) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* Return a new Context object for the current Context but attribute to a different tag.
* In complex apps attribution tagging can be used to distinguish between separate logical
* parts.
diff --git a/core/java/android/content/ContextParams.java b/core/java/android/content/ContextParams.java
new file mode 100644
index 0000000..17ec2a8
--- /dev/null
+++ b/core/java/android/content/ContextParams.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2021 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 android.content;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * This class represents rules around how a context being created via
+ * {@link Context#createContext} should behave.
+ *
+ * <p>One of the dimensions to customize is how permissions should behave.
+ * For example, you can specify how permission accesses from a context should
+ * be attributed in the platform's permission tracking system.
+ *
+ * <p>The two main types of attribution are: against an attribution tag which
+ * is an arbitrary string your app specifies for the purposes of tracking permission
+ * accesses from a given portion of your app; against another package and optionally
+ * its attribution tag if you are accessing the data on behalf of another app and
+ * you will be passing that data to this app. Both attributions are not mutually
+ * exclusive.
+ *
+ * <p>For example if you have a feature "foo" in your app which accesses
+ * permissions on behalf of app "foo.bar.baz" with feature "bar" you need to
+ * create a context like this:
+ *
+ * <pre class="prettyprint">
+ * context.createContext(new ContextParams.Builder()
+ * .setAttributionTag("foo")
+ * .setReceiverPackage("foo.bar.baz", "bar")
+ * .build())
+ * </pre>
+ *
+ * @see Context#createContext(ContextParams)
+ */
+public final class ContextParams {
+ private final String mAttributionTag;
+ private final String mReceiverPackage;
+ private final String mReceiverAttributionTag;
+ private final Set<String> mRenouncedPermissions;
+
+ /** {@hide} */
+ public static final ContextParams EMPTY = new ContextParams.Builder().build();
+
+ private ContextParams(@NonNull ContextParams.Builder builder) {
+ mAttributionTag = builder.mAttributionTag;
+ mReceiverPackage = builder.mReceiverPackage;
+ mReceiverAttributionTag = builder.mReceiverAttributionTag;
+ mRenouncedPermissions = builder.mRenouncedPermissions;
+ }
+
+ /**
+ * @return The attribution tag.
+ */
+ @Nullable
+ public String getAttributionTag() {
+ return mAttributionTag;
+ }
+
+ /**
+ * @return The receiving package.
+ */
+ @Nullable
+ public String getReceiverPackage() {
+ return mReceiverPackage;
+ }
+
+ /**
+ * @return The receiving package's attribution tag.
+ */
+ @Nullable
+ public String getReceiverAttributionTag() {
+ return mReceiverAttributionTag;
+ }
+
+ /**
+ * @return The set of permissions to treat as renounced.
+ * @hide
+ */
+ @SystemApi
+ @SuppressLint("NullableCollection")
+ @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS)
+ public @Nullable Set<String> getRenouncedPermissions() {
+ return mRenouncedPermissions;
+ }
+
+ /** @hide */
+ public boolean isRenouncedPermission(@NonNull String permission) {
+ return mRenouncedPermissions != null && mRenouncedPermissions.contains(permission);
+ }
+
+ /**
+ * Builder for creating a {@link ContextParams}.
+ */
+ public static final class Builder {
+ private String mAttributionTag;
+ private String mReceiverPackage;
+ private String mReceiverAttributionTag;
+ private Set<String> mRenouncedPermissions;
+
+ /**
+ * Sets an attribution tag against which to track permission accesses.
+ *
+ * @param attributionTag The attribution tag.
+ * @return This builder.
+ */
+ @NonNull
+ public Builder setAttributionTag(@NonNull String attributionTag) {
+ mAttributionTag = Objects.requireNonNull(attributionTag);
+ return this;
+ }
+
+ /**
+ * Sets the package and its optional attribution tag that would be receiving
+ * the permission protected data.
+ *
+ * @param packageName The package name receiving the permission protected data.
+ * @param attributionTag An attribution tag of the receiving package.
+ * @return This builder.
+ */
+ @NonNull
+ public Builder setReceiverPackage(@NonNull String packageName,
+ @Nullable String attributionTag) {
+ mReceiverPackage = Objects.requireNonNull(packageName);
+ mReceiverAttributionTag = attributionTag;
+ return this;
+ }
+
+ /**
+ * Sets permissions which have been voluntarily "renounced" by the
+ * calling app.
+ * <p>
+ * Interactions performed through the created Context will ideally be
+ * treated as if these "renounced" permissions have not actually been
+ * granted to the app, regardless of their actual grant status.
+ * <p>
+ * This is designed for use by separate logical components within an app
+ * which have no intention of interacting with data or services that are
+ * protected by the renounced permissions.
+ * <p>
+ * Note that only {@link PermissionInfo#PROTECTION_DANGEROUS}
+ * permissions are supported by this mechanism.
+ *
+ * @param renouncedPermissions The set of permissions to treat as
+ * renounced.
+ * @return This builder.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.RENOUNCE_PERMISSIONS)
+ public @NonNull Builder setRenouncedPermissions(@NonNull Set<String> renouncedPermissions) {
+ mRenouncedPermissions = Collections.unmodifiableSet(renouncedPermissions);
+ return this;
+ }
+
+ /**
+ * Creates a new instance.
+ *
+ * @return The new instance.
+ */
+ @NonNull
+ public ContextParams build() {
+ return new ContextParams(this);
+ }
+ }
+}
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index b71fb27..609f417 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -172,6 +172,11 @@
}
@Override
+ public @Nullable ContextParams getParams() {
+ return mBase.getParams();
+ }
+
+ @Override
public ApplicationInfo getApplicationInfo() {
return mBase.getApplicationInfo();
}
@@ -1045,6 +1050,12 @@
}
@Override
+ @NonNull
+ public Context createContext(@NonNull ContextParams contextParams) {
+ return mBase.createContext(contextParams);
+ }
+
+ @Override
public @NonNull Context createAttributionContext(@Nullable String attributionTag) {
return mBase.createAttributionContext(attributionTag);
}
diff --git a/core/java/android/content/OWNERS b/core/java/android/content/OWNERS
index 144856b..d0d406a 100644
--- a/core/java/android/content/OWNERS
+++ b/core/java/android/content/OWNERS
@@ -4,4 +4,7 @@
per-file IntentFilter.java = toddke@google.com
per-file IntentFilter.java = patb@google.com
per-file Intent.java = toddke@google.com
-per-file Intent.java = patb@google.com
\ No newline at end of file
+per-file Intent.java = patb@google.com
+per-file AutofillOptions* = file:/core/java/android/service/autofill/OWNERS
+per-file ContentCaptureOptions* = file:/core/java/android/service/contentcapture/OWNERS
+per-file LocusId* = file:/core/java/android/service/contentcapture/OWNERS
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
index b345748..c91334a 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -21,32 +21,34 @@
import android.content.pm.ParceledListSlice;
import android.content.pm.ShortcutInfo;
-/**
- * {@hide}
- */
+import com.android.internal.infra.AndroidFuture;
+
+/** {@hide} */
interface IShortcutService {
- boolean setDynamicShortcuts(String packageName, in ParceledListSlice shortcutInfoList,
- int userId);
+ oneway void setDynamicShortcuts(String packageName, in ParceledListSlice shortcutInfoList,
+ int userId, in AndroidFuture callback);
- boolean addDynamicShortcuts(String packageName, in ParceledListSlice shortcutInfoList,
- int userId);
+ oneway void addDynamicShortcuts(String packageName, in ParceledListSlice shortcutInfoList,
+ int userId, in AndroidFuture callback);
- void removeDynamicShortcuts(String packageName, in List shortcutIds, int userId);
+ oneway void removeDynamicShortcuts(String packageName, in List shortcutIds, int userId);
- void removeAllDynamicShortcuts(String packageName, int userId);
+ oneway void removeAllDynamicShortcuts(String packageName, int userId);
- boolean updateShortcuts(String packageName, in ParceledListSlice shortcuts, int userId);
+ oneway void updateShortcuts(String packageName, in ParceledListSlice shortcuts, int userId,
+ in AndroidFuture callback);
- boolean requestPinShortcut(String packageName, in ShortcutInfo shortcut,
- in IntentSender resultIntent, int userId);
+ oneway void requestPinShortcut(String packageName, in ShortcutInfo shortcut,
+ in IntentSender resultIntent, int userId, in AndroidFuture callback);
- Intent createShortcutResultIntent(String packageName, in ShortcutInfo shortcut, int userId);
+ oneway void createShortcutResultIntent(String packageName, in ShortcutInfo shortcut,
+ int userId, in AndroidFuture callback);
- void disableShortcuts(String packageName, in List shortcutIds, CharSequence disabledMessage,
- int disabledMessageResId, int userId);
+ oneway void disableShortcuts(String packageName, in List shortcutIds,
+ CharSequence disabledMessage, int disabledMessageResId, int userId);
- void enableShortcuts(String packageName, in List shortcutIds, int userId);
+ oneway void enableShortcuts(String packageName, in List shortcutIds, int userId);
int getMaxShortcutCountPerActivity(String packageName, int userId);
@@ -56,29 +58,31 @@
int getIconMaxDimensions(String packageName, int userId);
- void reportShortcutUsed(String packageName, String shortcutId, int userId);
+ oneway void reportShortcutUsed(String packageName, String shortcutId, int userId);
- void resetThrottling(); // system only API for developer opsions
+ oneway void resetThrottling(); // system only API for developer opsions
- void onApplicationActive(String packageName, int userId); // system only API for sysUI
+ oneway void onApplicationActive(String packageName, int userId); // system only API for sysUI
byte[] getBackupPayload(int user);
- void applyRestore(in byte[] payload, int user);
+ oneway void applyRestore(in byte[] payload, int user);
boolean isRequestPinItemSupported(int user, int requestType);
// System API used by framework's ShareSheet (ChooserActivity)
- ParceledListSlice getShareTargets(String packageName, in IntentFilter filter, int userId);
+ oneway void getShareTargets(String packageName, in IntentFilter filter, int userId,
+ in AndroidFuture<ParceledListSlice> callback);
boolean hasShareTargets(String packageName, String packageToCheck, int userId);
- void removeLongLivedShortcuts(String packageName, in List shortcutIds, int userId);
+ oneway void removeLongLivedShortcuts(String packageName, in List shortcutIds, int userId);
- ParceledListSlice getShortcuts(String packageName, int matchFlags, int userId);
+ oneway void getShortcuts(String packageName, int matchFlags, int userId,
+ in AndroidFuture<ParceledListSlice<ShortcutInfo>> callback);
- void pushDynamicShortcut(String packageName, in ShortcutInfo shortcut, int userId);
+ oneway void pushDynamicShortcut(String packageName, in ShortcutInfo shortcut, int userId);
- void updateShortcutVisibility(String callingPkg, String packageName, in byte[] certificate,
- in boolean visible, int userId);
-}
\ No newline at end of file
+ oneway void updateShortcutVisibility(String callingPkg, String packageName,
+ in byte[] certificate, in boolean visible, int userId);
+}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 7b62f3b..d79b66c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -7017,7 +7017,7 @@
* domain to an application, use
* {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)},
* passing in all of the domains returned inside
- * {@link DomainVerificationManager#getDomainVerificationUserSelection(String)}.
+ * {@link DomainVerificationManager#getDomainVerificationUserState(String)}.
*
* @hide
*/
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index d3bac79..f584ff3 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -24,6 +24,7 @@
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
+import android.annotation.WorkerThread;
import android.app.Notification;
import android.app.usage.UsageStatsManager;
import android.compat.annotation.UnsupportedAppUsage;
@@ -42,10 +43,12 @@
import android.os.UserHandle;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.infra.AndroidFuture;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
+import java.util.concurrent.ExecutionException;
/**
* <p><code>ShortcutManager</code> executes operations on an app's set of <i>shortcuts</i>, which
@@ -140,13 +143,16 @@
*
* @throws IllegalStateException when the user is locked.
*/
+ @WorkerThread
public boolean setDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) {
+ final AndroidFuture<Boolean> future = new AndroidFuture<>();
try {
- return mService.setDynamicShortcuts(mContext.getPackageName(),
- new ParceledListSlice(shortcutInfoList), injectMyUserId());
+ mService.setDynamicShortcuts(mContext.getPackageName(),
+ new ParceledListSlice(shortcutInfoList), injectMyUserId(), future);
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ future.completeExceptionally(e);
}
+ return getFutureOrThrow(future);
}
/**
@@ -158,14 +164,17 @@
*
* @throws IllegalStateException when the user is locked.
*/
+ @WorkerThread
@NonNull
public List<ShortcutInfo> getDynamicShortcuts() {
+ final AndroidFuture<ParceledListSlice<ShortcutInfo>> future = new AndroidFuture<>();
try {
- return mService.getShortcuts(mContext.getPackageName(), FLAG_MATCH_DYNAMIC,
- injectMyUserId()).getList();
+ mService.getShortcuts(mContext.getPackageName(), FLAG_MATCH_DYNAMIC, injectMyUserId(),
+ future);
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ future.completeExceptionally(e);
}
+ return getFutureOrThrow(future).getList();
}
/**
@@ -177,14 +186,17 @@
*
* @throws IllegalStateException when the user is locked.
*/
+ @WorkerThread
@NonNull
public List<ShortcutInfo> getManifestShortcuts() {
+ final AndroidFuture<ParceledListSlice<ShortcutInfo>> future = new AndroidFuture<>();
try {
- return mService.getShortcuts(mContext.getPackageName(), FLAG_MATCH_MANIFEST,
- injectMyUserId()).getList();
+ mService.getShortcuts(mContext.getPackageName(), FLAG_MATCH_MANIFEST, injectMyUserId(),
+ future);
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ future.completeExceptionally(e);
}
+ return getFutureOrThrow(future).getList();
}
/**
@@ -205,14 +217,16 @@
*
* @throws IllegalStateException when the user is locked.
*/
+ @WorkerThread
@NonNull
public List<ShortcutInfo> getShortcuts(@ShortcutMatchFlags int matchFlags) {
+ final AndroidFuture<ParceledListSlice<ShortcutInfo>> future = new AndroidFuture<>();
try {
- return mService.getShortcuts(mContext.getPackageName(), matchFlags, injectMyUserId())
- .getList();
+ mService.getShortcuts(mContext.getPackageName(), matchFlags, injectMyUserId(), future);
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ future.completeExceptionally(e);
}
+ return getFutureOrThrow(future).getList();
}
/**
@@ -228,13 +242,16 @@
*
* @throws IllegalStateException when the user is locked.
*/
+ @WorkerThread
public boolean addDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) {
+ final AndroidFuture<Boolean> future = new AndroidFuture<>();
try {
- return mService.addDynamicShortcuts(mContext.getPackageName(),
- new ParceledListSlice(shortcutInfoList), injectMyUserId());
+ mService.addDynamicShortcuts(mContext.getPackageName(),
+ new ParceledListSlice(shortcutInfoList), injectMyUserId(), future);
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ future.completeExceptionally(e);
}
+ return getFutureOrThrow(future);
}
/**
@@ -287,14 +304,17 @@
*
* @throws IllegalStateException when the user is locked.
*/
+ @WorkerThread
@NonNull
public List<ShortcutInfo> getPinnedShortcuts() {
+ final AndroidFuture<ParceledListSlice<ShortcutInfo>> future = new AndroidFuture<>();
try {
- return mService.getShortcuts(mContext.getPackageName(), FLAG_MATCH_PINNED,
- injectMyUserId()).getList();
+ mService.getShortcuts(mContext.getPackageName(), FLAG_MATCH_PINNED, injectMyUserId(),
+ future);
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ future.completeExceptionally(e);
}
+ return getFutureOrThrow(future).getList();
}
/**
@@ -309,13 +329,16 @@
*
* @throws IllegalStateException when the user is locked.
*/
+ @WorkerThread
public boolean updateShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) {
+ final AndroidFuture<Boolean> future = new AndroidFuture<>();
try {
- return mService.updateShortcuts(mContext.getPackageName(),
- new ParceledListSlice(shortcutInfoList), injectMyUserId());
+ mService.updateShortcuts(mContext.getPackageName(),
+ new ParceledListSlice(shortcutInfoList), injectMyUserId(), future);
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ future.completeExceptionally(e);
}
+ return getFutureOrThrow(future);
}
/**
@@ -584,14 +607,17 @@
* @throws IllegalStateException The caller doesn't have a foreground activity or a foreground
* service, or the device is locked.
*/
+ @WorkerThread
public boolean requestPinShortcut(@NonNull ShortcutInfo shortcut,
@Nullable IntentSender resultIntent) {
+ final AndroidFuture<Boolean> future = new AndroidFuture<>();
try {
- return mService.requestPinShortcut(mContext.getPackageName(), shortcut,
- resultIntent, injectMyUserId());
+ mService.requestPinShortcut(mContext.getPackageName(), shortcut,
+ resultIntent, injectMyUserId(), future);
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ future.completeExceptionally(e);
}
+ return getFutureOrThrow(future);
}
/**
@@ -611,13 +637,16 @@
*
* @throws IllegalArgumentException if a shortcut with the same ID exists and is disabled.
*/
+ @WorkerThread
public Intent createShortcutResultIntent(@NonNull ShortcutInfo shortcut) {
+ final AndroidFuture<Intent> future = new AndroidFuture<>();
try {
- return mService.createShortcutResultIntent(mContext.getPackageName(), shortcut,
- injectMyUserId());
+ mService.createShortcutResultIntent(mContext.getPackageName(), shortcut,
+ injectMyUserId(), future);
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ future.completeExceptionally(e);
}
+ return getFutureOrThrow(future);
}
/**
@@ -650,16 +679,18 @@
* @return List of {@link ShareShortcutInfo}s that match the given IntentFilter.
* @hide
*/
+ @WorkerThread
@NonNull
@SystemApi
@RequiresPermission(Manifest.permission.MANAGE_APP_PREDICTIONS)
public List<ShareShortcutInfo> getShareTargets(@NonNull IntentFilter filter) {
+ final AndroidFuture<ParceledListSlice> future = new AndroidFuture<>();
try {
- return mService.getShareTargets(mContext.getPackageName(), filter,
- injectMyUserId()).getList();
+ mService.getShareTargets(mContext.getPackageName(), filter, injectMyUserId(), future);
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ future.completeExceptionally(e);
}
+ return getFutureOrThrow(future).getList();
}
/**
@@ -788,4 +819,21 @@
throw e.rethrowFromSystemServer();
}
}
+
+ private static <T> T getFutureOrThrow(@NonNull AndroidFuture<T> future) {
+ try {
+ return future.get();
+ } catch (Throwable e) {
+ if (e instanceof ExecutionException) {
+ e = e.getCause();
+ }
+ if (e instanceof RuntimeException) {
+ throw (RuntimeException) e;
+ }
+ if (e instanceof Error) {
+ throw (Error) e;
+ }
+ throw new RuntimeException(e);
+ }
+ }
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/core/java/android/content/pm/parsing/component/ParsedActivity.java
index 2ea24f7..6f478ac 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivity.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivity.java
@@ -155,6 +155,7 @@
alias.nonLocalizedLabel = target.nonLocalizedLabel;
alias.launchMode = target.launchMode;
alias.lockTaskLaunchMode = target.lockTaskLaunchMode;
+ alias.documentLaunchMode = target.documentLaunchMode;
alias.descriptionRes = target.descriptionRes;
alias.screenOrientation = target.screenOrientation;
alias.taskAffinity = target.taskAffinity;
@@ -179,7 +180,6 @@
// alias.exported = target.exported;
// alias.permission = target.permission;
// alias.splitName = target.splitName;
-// alias.documentLaunchMode = target.documentLaunchMode;
// alias.persistableMode = target.persistableMode;
// alias.rotationAnimation = target.rotationAnimation;
// alias.colorMode = target.colorMode;
diff --git a/core/java/android/content/pm/verify/domain/DomainOwner.java b/core/java/android/content/pm/verify/domain/DomainOwner.java
index b050f5d..5bf2c09 100644
--- a/core/java/android/content/pm/verify/domain/DomainOwner.java
+++ b/core/java/android/content/pm/verify/domain/DomainOwner.java
@@ -66,16 +66,7 @@
* @param packageName
* Package name of that owns the domain.
* @param overrideable
- * Whether or not this owner can be automatically overridden. If all owners for a domain are
- * overrideable, then calling
- * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
- * Set, boolean)} to enable the domain will disable all other owners. On the other hand, if any
- * of the owners are non-overrideable, then
- * {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String,
- * boolean)} must be called with false to disable all of the other owners before this domain can
- * be taken by a new owner through
- * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
- * Set, boolean)}.
+ * Whether or not this owner can be automatically overridden.
*/
@DataClass.Generated.Member
public DomainOwner(
@@ -98,16 +89,9 @@
}
/**
- * Whether or not this owner can be automatically overridden. If all owners for a domain are
- * overrideable, then calling
- * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
- * Set, boolean)} to enable the domain will disable all other owners. On the other hand, if any
- * of the owners are non-overrideable, then
- * {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String,
- * boolean)} must be called with false to disable all of the other owners before this domain can
- * be taken by a new owner through
- * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID,
- * Set, boolean)}.
+ * Whether or not this owner can be automatically overridden.
+ *
+ * @see DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)
*/
@DataClass.Generated.Member
public boolean isOverrideable() {
@@ -205,7 +189,7 @@
};
@DataClass.Generated(
- time = 1614119379978L,
+ time = 1614721802044L,
codegenVersion = "1.0.22",
sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainOwner.java",
inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final boolean mOverrideable\nclass DomainOwner extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genEqualsHashCode=true, genAidl=true, genToString=true)")
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java b/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java
index 8095875..7c335b1 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java
@@ -94,7 +94,7 @@
private Map<String, Integer> unparcelHostToStateMap(Parcel in) {
return DomainVerificationUtils.readHostMap(in, new ArrayMap<>(),
- DomainVerificationUserSelection.class.getClassLoader());
+ DomainVerificationUserState.class.getClassLoader());
}
@@ -105,8 +105,7 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain
- // /DomainVerificationInfo.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -321,7 +320,7 @@
};
@DataClass.Generated(
- time = 1613002530369L,
+ time = 1614721812023L,
codegenVersion = "1.0.22",
sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationInfo.java",
inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForUUID.class) java.util.UUID mIdentifier\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Integer> mHostToStateMap\nprivate void parcelHostToStateMap(android.os.Parcel,int)\nprivate java.util.Map<java.lang.String,java.lang.Integer> unparcelHostToStateMap(android.os.Parcel)\nclass DomainVerificationInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genHiddenConstructor=true, genParcelable=true, genToString=true, genEqualsHashCode=true)")
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationManager.java b/core/java/android/content/pm/verify/domain/DomainVerificationManager.java
index 11402af..f7c81bcf 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationManager.java
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationManager.java
@@ -25,6 +25,8 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.os.UserHandle;
import java.util.List;
@@ -32,55 +34,63 @@
import java.util.UUID;
/**
- * System service to access the domain verification APIs.
+ * System service to access domain verification APIs.
*
- * Allows the approved domain verification
- * agent on the device (the sole holder of
- * {@link android.Manifest.permission#DOMAIN_VERIFICATION_AGENT}) to update the approval status
- * of domains declared by applications in their AndroidManifest.xml, to allow them to open those
- * links inside the app when selected by the user. This is done through querying
- * {@link #getDomainVerificationInfo(String)} and calling
- * {@link #setDomainVerificationStatus(UUID, Set, int)}.
- *
- * Also allows the domain preference settings (holder of
- * {@link android.Manifest.permission#UPDATE_DOMAIN_VERIFICATION_USER_SELECTION}) to update the
- * preferences of the user, when they have chosen to explicitly allow an application to open links.
- * This is done through querying {@link #getDomainVerificationUserSelection(String)} and calling
- * {@link #setDomainVerificationUserSelection(UUID, Set, boolean)} and
- * {@link #setDomainVerificationLinkHandlingAllowed(String, boolean)}.
- *
- * @hide
+ * Applications should use {@link #getDomainVerificationUserState(String)} if necessary to
+ * check if/how they are verified for a domain, which is required starting from platform
+ * {@link android.os.Build.VERSION_CODES#S} in order to open {@link Intent}s which declare
+ * {@link Intent#CATEGORY_BROWSABLE} or no category and also match against
+ * {@link Intent#CATEGORY_DEFAULT} {@link android.content.IntentFilter}s, either through an
+ * explicit declaration of {@link Intent#CATEGORY_DEFAULT} or through the use of
+ * {@link android.content.pm.PackageManager#MATCH_DEFAULT_ONLY}, which is usually added for the
+ * caller when using {@link Context#startActivity(Intent)} and similar.
*/
-@SystemApi
@SystemService(Context.DOMAIN_VERIFICATION_SERVICE)
-public interface DomainVerificationManager {
+public final class DomainVerificationManager {
/**
- * Extra field name for a {@link DomainVerificationRequest} for the requested packages.
- * Passed to an the domain verification agent that handles
+ * Extra field name for a {@link DomainVerificationRequest} for the requested packages. Passed
+ * to an the domain verification agent that handles
* {@link Intent#ACTION_DOMAINS_NEED_VERIFICATION}.
+ *
+ * @hide
*/
- String EXTRA_VERIFICATION_REQUEST =
+ @SystemApi
+ public static final String EXTRA_VERIFICATION_REQUEST =
"android.content.pm.verify.domain.extra.VERIFICATION_REQUEST";
/**
* No response has been recorded by either the system or any verification agent.
+ *
+ * @hide
*/
- int STATE_NO_RESPONSE = DomainVerificationState.STATE_NO_RESPONSE;
-
- /** The verification agent has explicitly verified the domain at some point. */
- int STATE_SUCCESS = DomainVerificationState.STATE_SUCCESS;
+ @SystemApi
+ public static final int STATE_NO_RESPONSE = DomainVerificationState.STATE_NO_RESPONSE;
/**
- * The first available custom response code. This and any greater integer, along with
- * {@link #STATE_SUCCESS} are the only values settable by the verification agent. All values
- * will be treated as if the domain is unverified.
+ * The verification agent has explicitly verified the domain at some point.
+ *
+ * @hide
*/
- int STATE_FIRST_VERIFIER_DEFINED = DomainVerificationState.STATE_FIRST_VERIFIER_DEFINED;
+ @SystemApi
+ public static final int STATE_SUCCESS = DomainVerificationState.STATE_SUCCESS;
- /** @hide */
+ /**
+ * The first available custom response code. This and any greater integer, along with {@link
+ * #STATE_SUCCESS} are the only values settable by the verification agent. All values will be
+ * treated as if the domain is unverified.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int STATE_FIRST_VERIFIER_DEFINED =
+ DomainVerificationState.STATE_FIRST_VERIFIER_DEFINED;
+
+ /**
+ * @hide
+ */
@NonNull
- static String stateToDebugString(@DomainVerificationState.State int state) {
+ public static String stateToDebugString(@DomainVerificationState.State int state) {
switch (state) {
case DomainVerificationState.STATE_NO_RESPONSE:
return "none";
@@ -104,10 +114,13 @@
}
/**
- * Checks if a state considers the corresponding domain to be successfully verified. The
- * domain verification agent may use this to determine whether or not to re-verify a domain.
+ * Checks if a state considers the corresponding domain to be successfully verified. The domain
+ * verification agent may use this to determine whether or not to re-verify a domain.
+ *
+ * @hide
*/
- static boolean isStateVerified(@DomainVerificationState.State int state) {
+ @SystemApi
+ public static boolean isStateVerified(@DomainVerificationState.State int state) {
switch (state) {
case DomainVerificationState.STATE_SUCCESS:
case DomainVerificationState.STATE_APPROVED:
@@ -126,10 +139,13 @@
/**
* Checks if a state is modifiable by the domain verification agent. This is useful as the
* platform may add new state codes in newer versions, and older verification agents can use
- * this method to determine if a state can be changed without having to be aware of what the
- * new state means.
+ * this method to determine if a state can be changed without having to be aware of what the new
+ * state means.
+ *
+ * @hide
*/
- static boolean isStateModifiable(@DomainVerificationState.State int state) {
+ @SystemApi
+ public static boolean isStateModifiable(@DomainVerificationState.State int state) {
switch (state) {
case DomainVerificationState.STATE_NO_RESPONSE:
case DomainVerificationState.STATE_SUCCESS:
@@ -147,11 +163,12 @@
}
/**
- * For determine re-verify policy. This is hidden from the domain verification agent so that
- * no behavior is made based on the result.
+ * For determine re-verify policy. This is hidden from the domain verification agent so that no
+ * behavior is made based on the result.
+ *
* @hide
*/
- static boolean isStateDefault(@DomainVerificationState.State int state) {
+ public static boolean isStateDefault(@DomainVerificationState.State int state) {
switch (state) {
case DomainVerificationState.STATE_NO_RESPONSE:
case DomainVerificationState.STATE_MIGRATED:
@@ -168,14 +185,72 @@
}
/**
+ * @hide
+ */
+ public static final int ERROR_INVALID_DOMAIN_SET = 1;
+ /**
+ * @hide
+ */
+ public static final int ERROR_NAME_NOT_FOUND = 2;
+
+ /**
+ * @hide
+ */
+ @IntDef(prefix = {"ERROR_"}, value = {
+ ERROR_INVALID_DOMAIN_SET,
+ ERROR_NAME_NOT_FOUND,
+ })
+ private @interface Error {
+ }
+
+ private final Context mContext;
+
+ private final IDomainVerificationManager mDomainVerificationManager;
+
+
+ /**
+ * System service to access the domain verification APIs.
+ * <p>
+ * Allows the approved domain verification agent on the device (the sole holder of {@link
+ * android.Manifest.permission#DOMAIN_VERIFICATION_AGENT}) to update the approval status of
+ * domains declared by applications in their AndroidManifest.xml, to allow them to open those
+ * links inside the app when selected by the user. This is done through querying {@link
+ * #getDomainVerificationInfo(String)} and calling {@link #setDomainVerificationStatus(UUID,
+ * Set, int)}.
+ * <p>
+ * Also allows the domain preference settings (holder of
+ * {@link android.Manifest.permission#UPDATE_DOMAIN_VERIFICATION_USER_SELECTION})
+ * to update the preferences of the user, when they have chosen to explicitly allow an
+ * application to open links. This is done through querying
+ * {@link #getDomainVerificationUserState(String)} and calling
+ * {@link #setDomainVerificationUserSelection(UUID, Set, boolean)} and
+ * {@link #setDomainVerificationLinkHandlingAllowed(String, boolean)}.
+ *
+ * @hide
+ */
+ public DomainVerificationManager(Context context,
+ IDomainVerificationManager domainVerificationManager) {
+ mContext = context;
+ mDomainVerificationManager = domainVerificationManager;
+ }
+
+ /**
* Used to iterate all {@link DomainVerificationInfo} values to do cleanup or retries. This is
* usually a heavy workload and should be done infrequently.
*
* @return the current snapshot of package names with valid autoVerify URLs.
+ * @hide
*/
+ @SystemApi
@NonNull
@RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT)
- List<String> getValidVerificationPackageNames();
+ public List<String> queryValidVerificationPackageNames() {
+ try {
+ return mDomainVerificationManager.queryValidVerificationPackageNames();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
/**
* Retrieves the domain verification state for a given package.
@@ -183,61 +258,106 @@
* @return the data for the package, or null if it does not declare any autoVerify domains
* @throws NameNotFoundException If the package is unavailable. This is an unrecoverable error
* and should not be re-tried except on a time scheduled basis.
+ * @hide
*/
+ @SystemApi
@Nullable
@RequiresPermission(anyOf = {
android.Manifest.permission.DOMAIN_VERIFICATION_AGENT,
android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION
})
- DomainVerificationInfo getDomainVerificationInfo(@NonNull String packageName)
- throws NameNotFoundException;
+ public DomainVerificationInfo getDomainVerificationInfo(@NonNull String packageName)
+ throws NameNotFoundException {
+ try {
+ return mDomainVerificationManager.getDomainVerificationInfo(packageName);
+ } catch (Exception e) {
+ Exception converted = rethrow(e, packageName);
+ if (converted instanceof NameNotFoundException) {
+ throw (NameNotFoundException) converted;
+ } else if (converted instanceof RuntimeException) {
+ throw (RuntimeException) converted;
+ } else {
+ throw new RuntimeException(converted);
+ }
+ }
+ }
/**
- * Change the verification status of the {@param domains} of the package associated with
- * {@param domainSetId}.
+ * Change the verification status of the {@param domains} of the package associated with {@param
+ * domainSetId}.
*
* @param domainSetId See {@link DomainVerificationInfo#getIdentifier()}.
* @param domains List of host names to change the state of.
* @param state See {@link DomainVerificationInfo#getHostToStateMap()}.
* @throws IllegalArgumentException If the ID is invalidated or the {@param domains} are
* invalid. This usually means the work being processed by the
- * verification agent is outdated and a new request should
- * be scheduled, if one has not already been done as part of
- * the {@link Intent#ACTION_DOMAINS_NEED_VERIFICATION}
- * broadcast.
+ * verification agent is outdated and a new request should be
+ * scheduled, if one has not already been done as part of the
+ * {@link Intent#ACTION_DOMAINS_NEED_VERIFICATION} broadcast.
* @throws NameNotFoundException If the ID is known to be good, but the package is
- * unavailable. This may be because the package is
- * installed on a volume that is no longer mounted. This
- * error is unrecoverable until the package is available
- * again, and should not be re-tried except on a time
- * scheduled basis.
+ * unavailable. This may be because the package is installed on
+ * a volume that is no longer mounted. This error is
+ * unrecoverable until the package is available again, and
+ * should not be re-tried except on a time scheduled basis.
+ * @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT)
- void setDomainVerificationStatus(@NonNull UUID domainSetId, @NonNull Set<String> domains,
- @DomainVerificationState.State int state) throws NameNotFoundException;
+ public void setDomainVerificationStatus(@NonNull UUID domainSetId, @NonNull Set<String> domains,
+ @DomainVerificationState.State int state) throws NameNotFoundException {
+ try {
+ mDomainVerificationManager.setDomainVerificationStatus(domainSetId.toString(),
+ new DomainSet(domains), state);
+ } catch (Exception e) {
+ Exception converted = rethrow(e, domainSetId);
+ if (converted instanceof NameNotFoundException) {
+ throw (NameNotFoundException) converted;
+ } else if (converted instanceof RuntimeException) {
+ throw (RuntimeException) converted;
+ } else {
+ throw new RuntimeException(converted);
+ }
+ }
+ }
/**
- * TODO(b/178525735): This documentation is incorrect in the context of UX changes.
- * Change whether the given {@param packageName} is allowed to automatically open verified
- * HTTP/HTTPS domains. The final state is determined along with the verification status for the
- * specific domain being opened and other system state. An app with this enabled is not
- * guaranteed to be the sole link handler for its domains.
+ * Change whether the given packageName is allowed to handle BROWSABLE and DEFAULT category web
+ * (HTTP/HTTPS) {@link Intent} Activity open requests. The final state is determined along with
+ * the verification status for the specific domain being opened and other system state. An app
+ * with this enabled is not guaranteed to be the sole link handler for its domains.
+ * <p>
+ * By default, all apps are allowed to open links. Users must disable them explicitly.
*
- * By default, all apps are allowed to open verified links. Users must disable them explicitly.
+ * @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)
- void setDomainVerificationLinkHandlingAllowed(@NonNull String packageName, boolean allowed)
- throws NameNotFoundException;
+ public void setDomainVerificationLinkHandlingAllowed(@NonNull String packageName,
+ boolean allowed) throws NameNotFoundException {
+ try {
+ mDomainVerificationManager.setDomainVerificationLinkHandlingAllowed(packageName,
+ allowed, mContext.getUserId());
+ } catch (Exception e) {
+ Exception converted = rethrow(e, packageName);
+ if (converted instanceof NameNotFoundException) {
+ throw (NameNotFoundException) converted;
+ } else if (converted instanceof RuntimeException) {
+ throw (RuntimeException) converted;
+ } else {
+ throw new RuntimeException(converted);
+ }
+ }
+ }
/**
* Update the recorded user selection for the given {@param domains} for the given {@param
* domainSetId}. This state is recorded for the lifetime of a domain for a package on device,
* and will never be reset by the system short of an app data clear.
- *
+ * <p>
* This state is stored per device user. If another user needs to be changed, the appropriate
- * permissions must be acquired and
- * {@link Context#createPackageContextAsUser(String, int, UserHandle)} should be used.
- *
+ * permissions must be acquired and {@link Context#createContextAsUser(UserHandle, int)} should
+ * be used.
+ * <p>
* Enabling an unverified domain will allow an application to open it, but this can only occur
* if no other app on the device is approved for a higher approval level. This can queried
* using {@link #getOwnersForDomain(String)}.
@@ -255,33 +375,55 @@
* @throws IllegalArgumentException If the ID is invalidated or the {@param domains} are
* invalid.
* @throws NameNotFoundException If the ID is known to be good, but the package is
- * unavailable. This may be because the package is
- * installed on a volume that is no longer mounted. This
- * error is unrecoverable until the package is available
- * again, and should not be re-tried except on a time
- * scheduled basis.
+ * unavailable. This may be because the package is installed on
+ * a volume that is no longer mounted. This error is
+ * unrecoverable until the package is available again, and
+ * should not be re-tried except on a time scheduled basis.
+ * @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)
- void setDomainVerificationUserSelection(@NonNull UUID domainSetId,
- @NonNull Set<String> domains, boolean enabled) throws NameNotFoundException;
+ public void setDomainVerificationUserSelection(@NonNull UUID domainSetId,
+ @NonNull Set<String> domains, boolean enabled) throws NameNotFoundException {
+ try {
+ mDomainVerificationManager.setDomainVerificationUserSelection(domainSetId.toString(),
+ new DomainSet(domains), enabled, mContext.getUserId());
+ } catch (Exception e) {
+ Exception converted = rethrow(e, domainSetId);
+ if (converted instanceof NameNotFoundException) {
+ throw (NameNotFoundException) converted;
+ } else if (converted instanceof RuntimeException) {
+ throw (RuntimeException) converted;
+ } else {
+ throw new RuntimeException(converted);
+ }
+ }
+ }
/**
* Retrieve the user selection data for the given {@param packageName} and the current user.
- * It is the responsibility of the caller to ensure that the
- * {@link DomainVerificationUserSelection#getIdentifier()} matches any prior API calls.
- *
- * This state is stored per device user. If another user needs to be accessed, the appropriate
- * permissions must be acquired and
- * {@link Context#createPackageContextAsUser(String, int, UserHandle)} should be used.
*
* @param packageName The app to query state for.
- * @return the user selection verification data for the given package for the current user,
- * or null if the package does not declare any HTTP/HTTPS domains.
+ * @return the user selection verification data for the given package for the current user, or
+ * null if the package does not declare any HTTP/HTTPS domains.
*/
@Nullable
- @RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)
- DomainVerificationUserSelection getDomainVerificationUserSelection(@NonNull String packageName)
- throws NameNotFoundException;
+ public DomainVerificationUserState getDomainVerificationUserState(
+ @NonNull String packageName) throws NameNotFoundException {
+ try {
+ return mDomainVerificationManager.getDomainVerificationUserState(packageName,
+ mContext.getUserId());
+ } catch (Exception e) {
+ Exception converted = rethrow(e, packageName);
+ if (converted instanceof NameNotFoundException) {
+ throw (NameNotFoundException) converted;
+ } else if (converted instanceof RuntimeException) {
+ throw (RuntimeException) converted;
+ } else {
+ throw new RuntimeException(converted);
+ }
+ }
+ }
/**
* For the given domain, return all apps which are approved to open it in a
@@ -291,21 +433,65 @@
*
* By default the list will be returned ordered from lowest to highest
* priority.
+ *
+ * @hide
*/
+ @SystemApi
@NonNull
@RequiresPermission(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)
- List<DomainOwner> getOwnersForDomain(@NonNull String domain);
+ public List<DomainOwner> getOwnersForDomain(@NonNull String domain) {
+ try {
+ return mDomainVerificationManager.getOwnersForDomain(domain, mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private Exception rethrow(Exception exception, @Nullable UUID domainSetId) {
+ return rethrow(exception, domainSetId, null);
+ }
+
+ private Exception rethrow(Exception exception, @Nullable String packageName) {
+ return rethrow(exception, null, packageName);
+ }
+
+ private Exception rethrow(Exception exception, @Nullable UUID domainSetId,
+ @Nullable String packageName) {
+ if (exception instanceof ServiceSpecificException) {
+ int packedErrorCode = ((ServiceSpecificException) exception).errorCode;
+ if (packageName == null) {
+ packageName = exception.getMessage();
+ }
+
+ @Error int managerErrorCode = packedErrorCode & 0xFFFF;
+ switch (managerErrorCode) {
+ case ERROR_INVALID_DOMAIN_SET:
+ int errorSpecificCode = packedErrorCode >> 16;
+ return new IllegalArgumentException(InvalidDomainSetException.buildMessage(
+ domainSetId, packageName, errorSpecificCode));
+ case ERROR_NAME_NOT_FOUND:
+ return new NameNotFoundException(packageName);
+ default:
+ return exception;
+ }
+ } else if (exception instanceof RemoteException) {
+ return ((RemoteException) exception).rethrowFromSystemServer();
+ } else {
+ return exception;
+ }
+ }
/**
* Thrown if a {@link DomainVerificationInfo#getIdentifier()}} or an associated set of domains
* provided by the caller is no longer valid. This may be recoverable, and the caller should
* re-query the package name associated with the ID using
- * {@link #getDomainVerificationInfo(String)} in order to check. If that also fails, then the
- * package is no longer known to the device and thus all pending work for it should be dropped.
+ * {@link #getDomainVerificationInfo(String)}
+ * in order to check. If that also fails, then the package is no longer known to the device and
+ * thus all pending work for it should be dropped.
*
* @hide
*/
- class InvalidDomainSetException extends IllegalArgumentException {
+ public static class InvalidDomainSetException extends IllegalArgumentException {
public static final int REASON_ID_NULL = 1;
public static final int REASON_ID_INVALID = 2;
@@ -313,7 +499,9 @@
public static final int REASON_UNKNOWN_DOMAIN = 4;
public static final int REASON_UNABLE_TO_APPROVE = 5;
- /** @hide */
+ /**
+ * @hide
+ */
@IntDef({
REASON_ID_NULL,
REASON_ID_INVALID,
@@ -352,7 +540,9 @@
@Nullable
private final String mPackageName;
- /** @hide */
+ /**
+ * @hide
+ */
public InvalidDomainSetException(@Nullable UUID domainSetId, @Nullable String packageName,
@Reason int reason) {
super(buildMessage(domainSetId, packageName, reason));
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationManagerImpl.java b/core/java/android/content/pm/verify/domain/DomainVerificationManagerImpl.java
deleted file mode 100644
index 8b9865c..0000000
--- a/core/java/android/content/pm/verify/domain/DomainVerificationManagerImpl.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2020 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 android.content.pm.verify.domain;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-
-import java.util.List;
-import java.util.Set;
-import java.util.UUID;
-
-/**
- * @hide
- */
-@SuppressWarnings("RedundantThrows")
-public class DomainVerificationManagerImpl implements DomainVerificationManager {
-
- public static final int ERROR_INVALID_DOMAIN_SET = 1;
- public static final int ERROR_NAME_NOT_FOUND = 2;
-
- @IntDef(prefix = { "ERROR_" }, value = {
- ERROR_INVALID_DOMAIN_SET,
- ERROR_NAME_NOT_FOUND,
- })
- private @interface Error {
- }
-
- private final Context mContext;
-
- private final IDomainVerificationManager mDomainVerificationManager;
-
- public DomainVerificationManagerImpl(Context context,
- IDomainVerificationManager domainVerificationManager) {
- mContext = context;
- mDomainVerificationManager = domainVerificationManager;
- }
-
- @NonNull
- @Override
- public List<String> getValidVerificationPackageNames() {
- try {
- return mDomainVerificationManager.getValidVerificationPackageNames();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- @Nullable
- @Override
- public DomainVerificationInfo getDomainVerificationInfo(@NonNull String packageName)
- throws NameNotFoundException {
- try {
- return mDomainVerificationManager.getDomainVerificationInfo(packageName);
- } catch (Exception e) {
- Exception converted = rethrow(e, packageName);
- if (converted instanceof NameNotFoundException) {
- throw (NameNotFoundException) converted;
- } else if (converted instanceof RuntimeException) {
- throw (RuntimeException) converted;
- } else {
- throw new RuntimeException(converted);
- }
- }
- }
-
- @Override
- public void setDomainVerificationStatus(@NonNull UUID domainSetId, @NonNull Set<String> domains,
- int state) throws IllegalArgumentException, NameNotFoundException {
- try {
- mDomainVerificationManager.setDomainVerificationStatus(domainSetId.toString(),
- new DomainSet(domains), state);
- } catch (Exception e) {
- Exception converted = rethrow(e, domainSetId);
- if (converted instanceof NameNotFoundException) {
- throw (NameNotFoundException) converted;
- } else if (converted instanceof RuntimeException) {
- throw (RuntimeException) converted;
- } else {
- throw new RuntimeException(converted);
- }
- }
- }
-
- @Override
- public void setDomainVerificationLinkHandlingAllowed(@NonNull String packageName,
- boolean allowed) throws NameNotFoundException {
- try {
- mDomainVerificationManager.setDomainVerificationLinkHandlingAllowed(packageName,
- allowed, mContext.getUserId());
- } catch (Exception e) {
- Exception converted = rethrow(e, packageName);
- if (converted instanceof NameNotFoundException) {
- throw (NameNotFoundException) converted;
- } else if (converted instanceof RuntimeException) {
- throw (RuntimeException) converted;
- } else {
- throw new RuntimeException(converted);
- }
- }
- }
-
- @Override
- public void setDomainVerificationUserSelection(@NonNull UUID domainSetId,
- @NonNull Set<String> domains, boolean enabled)
- throws IllegalArgumentException, NameNotFoundException {
- try {
- mDomainVerificationManager.setDomainVerificationUserSelection(domainSetId.toString(),
- new DomainSet(domains), enabled, mContext.getUserId());
- } catch (Exception e) {
- Exception converted = rethrow(e, domainSetId);
- if (converted instanceof NameNotFoundException) {
- throw (NameNotFoundException) converted;
- } else if (converted instanceof RuntimeException) {
- throw (RuntimeException) converted;
- } else {
- throw new RuntimeException(converted);
- }
- }
- }
-
- @Nullable
- @Override
- public DomainVerificationUserSelection getDomainVerificationUserSelection(
- @NonNull String packageName) throws NameNotFoundException {
- try {
- return mDomainVerificationManager.getDomainVerificationUserSelection(packageName,
- mContext.getUserId());
- } catch (Exception e) {
- Exception converted = rethrow(e, packageName);
- if (converted instanceof NameNotFoundException) {
- throw (NameNotFoundException) converted;
- } else if (converted instanceof RuntimeException) {
- throw (RuntimeException) converted;
- } else {
- throw new RuntimeException(converted);
- }
- }
- }
-
- @NonNull
- @Override
- public List<DomainOwner> getOwnersForDomain(@NonNull String domain) {
- try {
- return mDomainVerificationManager.getOwnersForDomain(domain, mContext.getUserId());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- private Exception rethrow(Exception exception, @Nullable UUID domainSetId) {
- return rethrow(exception, domainSetId, null);
- }
-
- private Exception rethrow(Exception exception, @Nullable String packageName) {
- return rethrow(exception, null, packageName);
- }
-
- private Exception rethrow(Exception exception, @Nullable UUID domainSetId,
- @Nullable String packageName) {
- if (exception instanceof ServiceSpecificException) {
- int packedErrorCode = ((ServiceSpecificException) exception).errorCode;
- if (packageName == null) {
- packageName = exception.getMessage();
- }
-
- @Error int managerErrorCode = packedErrorCode & 0xFFFF;
- switch (managerErrorCode) {
- case ERROR_INVALID_DOMAIN_SET:
- int errorSpecificCode = packedErrorCode >> 16;
- return new IllegalArgumentException(InvalidDomainSetException.buildMessage(
- domainSetId, packageName, errorSpecificCode));
- case ERROR_NAME_NOT_FOUND:
- return new NameNotFoundException(packageName);
- default:
- return exception;
- }
- } else if (exception instanceof RemoteException) {
- return ((RemoteException) exception).rethrowFromSystemServer();
- } else {
- return exception;
- }
- }
-}
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl b/core/java/android/content/pm/verify/domain/DomainVerificationUserState.aidl
similarity index 93%
rename from core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl
rename to core/java/android/content/pm/verify/domain/DomainVerificationUserState.aidl
index ddb5ef8..94690c1 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationUserState.aidl
@@ -16,4 +16,4 @@
package android.content.pm.verify.domain;
-parcelable DomainVerificationUserSelection;
+parcelable DomainVerificationUserState;
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java b/core/java/android/content/pm/verify/domain/DomainVerificationUserState.java
similarity index 82%
rename from core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java
rename to core/java/android/content/pm/verify/domain/DomainVerificationUserState.java
index d23f5f1..1e60abb 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java
+++ b/core/java/android/content/pm/verify/domain/DomainVerificationUserState.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Context;
+import android.content.Intent;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
@@ -29,39 +30,36 @@
import com.android.internal.util.Parcelling;
import java.util.Map;
-import java.util.Set;
import java.util.UUID;
/**
* Contains the user selection state for a package. This means all web HTTP(S) domains declared by a
* package in its manifest, whether or not they were marked for auto verification.
* <p>
- * By default, all apps are allowed to automatically open links with domains that they've
- * successfully verified against. This is reflected by {@link #isLinkHandlingAllowed()}. The user
- * can decide to disable this, disallowing the application from opening all links. Note that the
- * toggle affects <b>all</b> links and is not based on the verification state of the domains.
+ * Applications should use {@link #getHostToStateMap()} if necessary to
+ * check if/how they are verified for a domain, which is required starting from platform
+ * {@link android.os.Build.VERSION_CODES#S} in order to open {@link Intent}s which declare
+ * {@link Intent#CATEGORY_BROWSABLE} or no category and also match against
+ * {@link Intent#CATEGORY_DEFAULT} {@link android.content.IntentFilter}s, either through an
+ * explicit declaration of {@link Intent#CATEGORY_DEFAULT} or through the use of
+ * {@link android.content.pm.PackageManager#MATCH_DEFAULT_ONLY}, which is usually added for the
+ * caller when using {@link Context#startActivity(Intent)} and similar.
+ * <p>
+ * By default, all apps are allowed to automatically open links for the above case for domains that
+ * they've successfully verified against. This is reflected by {@link #isLinkHandlingAllowed()}.
+ * The user can decide to disable this, disallowing the application from opening all links. Note
+ * that the toggle affects <b>all</b> links and is not based on the verification state of the
+ * domains.
* <p>
* Assuming the toggle is enabled, the user can also select additional unverified domains to grant
* to the application to open, which is reflected in {@link #getHostToStateMap()}. But only a single
* application can be approved for a domain unless the applications are both approved. If another
* application is approved, the user will not be allowed to enable the domain.
- * <p>
- * These values can be changed through the
- * {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String,
- * boolean)} and {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set,
- * boolean)} APIs.
- * <p>
- * Note that because state is per user, if a different user needs to be changed, one will need to
- * use {@link Context#createContextAsUser(UserHandle, int)} and hold the {@link
- * android.Manifest.permission#INTERACT_ACROSS_USERS} permission.
- *
- * @hide
*/
-@SystemApi
@SuppressWarnings("DefaultAnnotationParam")
@DataClass(genAidl = true, genHiddenConstructor = true, genParcelable = true, genToString = true,
genEqualsHashCode = true, genHiddenConstDefs = true)
-public final class DomainVerificationUserSelection implements Parcelable {
+public final class DomainVerificationUserState implements Parcelable {
/**
* The domain is unverified and unselected, and the application is unable to open web links
@@ -70,9 +68,8 @@
public static final int DOMAIN_STATE_NONE = 0;
/**
- * The domain has been selected through the
- * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)}
- * API, under the assumption it has not been reset by the system.
+ * The domain has been selected by the user. This may be reset to {@link #DOMAIN_STATE_NONE} if
+ * another application is selected or verified for the same domain.
*/
public static final int DOMAIN_STATE_SELECTED = 1;
@@ -119,7 +116,16 @@
@NonNull
private Map<String, Integer> unparcelHostToStateMap(Parcel in) {
return DomainVerificationUtils.readHostMap(in, new ArrayMap<>(),
- DomainVerificationUserSelection.class.getClassLoader());
+ DomainVerificationUserState.class.getClassLoader());
+ }
+
+ /**
+ * @see DomainVerificationInfo#getIdentifier
+ * @hide
+ */
+ @SystemApi
+ public @NonNull UUID getIdentifier() {
+ return mIdentifier;
}
@@ -130,7 +136,7 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationUserState.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -162,7 +168,7 @@
}
/**
- * Creates a new DomainVerificationUserSelection.
+ * Creates a new DomainVerificationUserState.
*
* @param packageName
* The package name that this data corresponds to.
@@ -175,7 +181,7 @@
* @hide
*/
@DataClass.Generated.Member
- public DomainVerificationUserSelection(
+ public DomainVerificationUserState(
@NonNull UUID identifier,
@NonNull String packageName,
@NonNull UserHandle user,
@@ -201,14 +207,6 @@
}
/**
- * @see DomainVerificationInfo#getIdentifier
- */
- @DataClass.Generated.Member
- public @NonNull UUID getIdentifier() {
- return mIdentifier;
- }
-
- /**
* The package name that this data corresponds to.
*/
@DataClass.Generated.Member
@@ -246,7 +244,7 @@
// You can override field toString logic by defining methods like:
// String fieldNameToString() { ... }
- return "DomainVerificationUserSelection { " +
+ return "DomainVerificationUserState { " +
"identifier = " + mIdentifier + ", " +
"packageName = " + mPackageName + ", " +
"user = " + mUser + ", " +
@@ -259,13 +257,13 @@
@DataClass.Generated.Member
public boolean equals(@Nullable Object o) {
// You can override field equality logic by defining either of the methods like:
- // boolean fieldNameEquals(DomainVerificationUserSelection other) { ... }
+ // boolean fieldNameEquals(DomainVerificationUserState other) { ... }
// boolean fieldNameEquals(FieldType otherValue) { ... }
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
@SuppressWarnings("unchecked")
- DomainVerificationUserSelection that = (DomainVerificationUserSelection) o;
+ DomainVerificationUserState that = (DomainVerificationUserState) o;
//noinspection PointlessBooleanExpression
return true
&& java.util.Objects.equals(mIdentifier, that.mIdentifier)
@@ -323,7 +321,7 @@
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
- /* package-private */ DomainVerificationUserSelection(@NonNull Parcel in) {
+ /* package-private */ DomainVerificationUserState(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
@@ -354,24 +352,24 @@
}
@DataClass.Generated.Member
- public static final @NonNull Parcelable.Creator<DomainVerificationUserSelection> CREATOR
- = new Parcelable.Creator<DomainVerificationUserSelection>() {
+ public static final @NonNull Parcelable.Creator<DomainVerificationUserState> CREATOR
+ = new Parcelable.Creator<DomainVerificationUserState>() {
@Override
- public DomainVerificationUserSelection[] newArray(int size) {
- return new DomainVerificationUserSelection[size];
+ public DomainVerificationUserState[] newArray(int size) {
+ return new DomainVerificationUserState[size];
}
@Override
- public DomainVerificationUserSelection createFromParcel(@NonNull Parcel in) {
- return new DomainVerificationUserSelection(in);
+ public DomainVerificationUserState createFromParcel(@NonNull Parcel in) {
+ return new DomainVerificationUserState(in);
}
};
@DataClass.Generated(
- time = 1613683603297L,
+ time = 1614721840152L,
codegenVersion = "1.0.22",
- sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.java",
- inputSignatures = "public static final int DOMAIN_STATE_NONE\npublic static final int DOMAIN_STATE_SELECTED\npublic static final int DOMAIN_STATE_VERIFIED\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForUUID.class) java.util.UUID mIdentifier\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull android.os.UserHandle mUser\nprivate final @android.annotation.NonNull boolean mLinkHandlingAllowed\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Integer> mHostToStateMap\nprivate void parcelHostToStateMap(android.os.Parcel,int)\nprivate @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Integer> unparcelHostToStateMap(android.os.Parcel)\nclass DomainVerificationUserSelection extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genHiddenConstructor=true, genParcelable=true, genToString=true, genEqualsHashCode=true, genHiddenConstDefs=true)")
+ sourceFile = "frameworks/base/core/java/android/content/pm/verify/domain/DomainVerificationUserState.java",
+ inputSignatures = "public static final int DOMAIN_STATE_NONE\npublic static final int DOMAIN_STATE_SELECTED\npublic static final int DOMAIN_STATE_VERIFIED\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForUUID.class) java.util.UUID mIdentifier\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull android.os.UserHandle mUser\nprivate final @android.annotation.NonNull boolean mLinkHandlingAllowed\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Integer> mHostToStateMap\nprivate void parcelHostToStateMap(android.os.Parcel,int)\nprivate @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.Integer> unparcelHostToStateMap(android.os.Parcel)\npublic @android.annotation.SystemApi @android.annotation.NonNull java.util.UUID getIdentifier()\nclass DomainVerificationUserState extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true, genHiddenConstructor=true, genParcelable=true, genToString=true, genEqualsHashCode=true, genHiddenConstDefs=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/content/pm/verify/domain/IDomainVerificationManager.aidl b/core/java/android/content/pm/verify/domain/IDomainVerificationManager.aidl
index 701af32..332b925 100644
--- a/core/java/android/content/pm/verify/domain/IDomainVerificationManager.aidl
+++ b/core/java/android/content/pm/verify/domain/IDomainVerificationManager.aidl
@@ -19,7 +19,7 @@
import android.content.pm.verify.domain.DomainOwner;
import android.content.pm.verify.domain.DomainSet;
import android.content.pm.verify.domain.DomainVerificationInfo;
-import android.content.pm.verify.domain.DomainVerificationUserSelection;
+import android.content.pm.verify.domain.DomainVerificationUserState;
import java.util.List;
/**
@@ -28,13 +28,13 @@
*/
interface IDomainVerificationManager {
- List<String> getValidVerificationPackageNames();
+ List<String> queryValidVerificationPackageNames();
@nullable
DomainVerificationInfo getDomainVerificationInfo(String packageName);
@nullable
- DomainVerificationUserSelection getDomainVerificationUserSelection(String packageName,
+ DomainVerificationUserState getDomainVerificationUserState(String packageName,
int userId);
@nullable
diff --git a/core/java/android/hardware/biometrics/BiometricAuthenticator.java b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
index fd98d37..31d1b69 100644
--- a/core/java/android/hardware/biometrics/BiometricAuthenticator.java
+++ b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
@@ -62,10 +62,13 @@
* @hide
*/
int TYPE_FACE = 1 << 3;
- @IntDef({TYPE_NONE,
+
+ @IntDef(flag = true, value = {
+ TYPE_NONE,
TYPE_CREDENTIAL,
TYPE_FINGERPRINT,
- TYPE_IRIS})
+ TYPE_IRIS
+ })
@Retention(RetentionPolicy.SOURCE)
@interface Modality {}
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 5b28e00..1fdce5e 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -23,6 +23,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -193,15 +194,15 @@
int DEVICE_CREDENTIAL = 1 << 15;
}
- private final Context mContext;
- private final IAuthService mService;
+ @NonNull private final Context mContext;
+ @NonNull private final IAuthService mService;
/**
* @hide
* @param context
* @param service
*/
- public BiometricManager(Context context, IAuthService service) {
+ public BiometricManager(@NonNull Context context, @NonNull IAuthService service) {
mContext = context;
mService = service;
}
@@ -274,7 +275,8 @@
*/
@Deprecated
@RequiresPermission(USE_BIOMETRIC)
- public @BiometricError int canAuthenticate() {
+ @BiometricError
+ public int canAuthenticate() {
return canAuthenticate(Authenticators.BIOMETRIC_WEAK);
}
@@ -304,7 +306,8 @@
* authenticators can currently be used (enrolled and available).
*/
@RequiresPermission(USE_BIOMETRIC)
- public @BiometricError int canAuthenticate(@Authenticators.Types int authenticators) {
+ @BiometricError
+ public int canAuthenticate(@Authenticators.Types int authenticators) {
return canAuthenticate(mContext.getUserId(), authenticators);
}
@@ -312,8 +315,10 @@
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public @BiometricError int canAuthenticate(int userId,
- @Authenticators.Types int authenticators) {
+ @BiometricError
+ public int canAuthenticate(
+ int userId, @Authenticators.Types int authenticators) {
+
if (mService != null) {
try {
final String opPackageName = mContext.getOpPackageName();
@@ -322,7 +327,7 @@
throw e.rethrowFromSystemServer();
}
} else {
- Slog.w(TAG, "hasEnrolledBiometrics(): Service not connected");
+ Slog.w(TAG, "canAuthenticate(): Service not connected");
return BIOMETRIC_ERROR_HW_UNAVAILABLE;
}
}
@@ -404,5 +409,115 @@
}
}
+ /**
+ * Provides a localized string that may be used as the label for a button that invokes
+ * {@link BiometricPrompt}.
+ *
+ * <p>When possible, this method should use the given authenticator requirements to more
+ * precisely specify the authentication type that will be used. For example, if
+ * <strong>Class 3</strong> biometric authentication is requested on a device with a
+ * <strong>Class 3</strong> fingerprint sensor and a <strong>Class 2</strong> face sensor, the
+ * returned string should indicate that fingerprint authentication will be used.
+ *
+ * <p>This method should also try to specify which authentication method(s) will be used in
+ * practice when multiple authenticators meet the given requirements. For example, if biometric
+ * authentication is requested on a device with both face and fingerprint sensors but the user
+ * has selected face as their preferred method, the returned string should indicate that face
+ * authentication will be used.
+ *
+ * @param authenticators A bit field representing the types of {@link Authenticators} that may
+ * be used for authentication.
+ * @return The label for a button that invokes {@link BiometricPrompt} for authentication.
+ */
+ @RequiresPermission(USE_BIOMETRIC)
+ @Nullable
+ public CharSequence getButtonLabel(@Authenticators.Types int authenticators) {
+ if (mService != null) {
+ final int userId = mContext.getUserId();
+ final String opPackageName = mContext.getOpPackageName();
+ try {
+ return mService.getButtonLabel(userId, opPackageName, authenticators);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ Slog.w(TAG, "getButtonLabel(): Service not connected");
+ return null;
+ }
+ }
+
+ /**
+ * Provides a localized string that may be shown while the user is authenticating with
+ * {@link BiometricPrompt}.
+ *
+ * <p>When possible, this method should use the given authenticator requirements to more
+ * precisely specify the authentication type that will be used. For example, if
+ * <strong>Class 3</strong> biometric authentication is requested on a device with a
+ * <strong>Class 3</strong> fingerprint sensor and a <strong>Class 2</strong> face sensor, the
+ * returned string should indicate that fingerprint authentication will be used.
+ *
+ * <p>This method should also try to specify which authentication method(s) will be used in
+ * practice when multiple authenticators meet the given requirements. For example, if biometric
+ * authentication is requested on a device with both face and fingerprint sensors but the user
+ * has selected face as their preferred method, the returned string should indicate that face
+ * authentication will be used.
+ *
+ * @param authenticators A bit field representing the types of {@link Authenticators} that may
+ * be used for authentication.
+ * @return The label for a button that invokes {@link BiometricPrompt} for authentication.
+ */
+ @RequiresPermission(USE_BIOMETRIC)
+ @Nullable
+ public CharSequence getPromptMessage(@Authenticators.Types int authenticators) {
+ if (mService != null) {
+ final int userId = mContext.getUserId();
+ final String opPackageName = mContext.getOpPackageName();
+ try {
+ return mService.getPromptMessage(userId, opPackageName, authenticators);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ Slog.w(TAG, "getPromptMessage(): Service not connected");
+ return null;
+ }
+ }
+
+ /**
+ * Provides a localized string that may be shown as the title for an app setting that enables
+ * biometric authentication.
+ *
+ * <p>When possible, this method should use the given authenticator requirements to more
+ * precisely specify the authentication type that will be used. For example, if
+ * <strong>Class 3</strong> biometric authentication is requested on a device with a
+ * <strong>Class 3</strong> fingerprint sensor and a <strong>Class 2</strong> face sensor, the
+ * returned string should indicate that fingerprint authentication will be used.
+ *
+ * <p>This method should <em>not</em> try to specify which authentication method(s) will be used
+ * in practice when multiple authenticators meet the given requirements. For example, if
+ * biometric authentication is requested on a device with both face and fingerprint sensors, the
+ * returned string should indicate that either face or fingerprint authentication may be used,
+ * regardless of whether the user has enrolled or selected either as their preferred method.
+ *
+ * @param authenticators A bit field representing the types of {@link Authenticators} that may
+ * be used for authentication.
+ * @return The label for a button that invokes {@link BiometricPrompt} for authentication.
+ */
+ @RequiresPermission(USE_BIOMETRIC)
+ @Nullable
+ public CharSequence getSettingName(@Authenticators.Types int authenticators) {
+ if (mService != null) {
+ final int userId = mContext.getUserId();
+ final String opPackageName = mContext.getOpPackageName();
+ try {
+ return mService.getSettingName(userId, opPackageName, authenticators);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ Slog.w(TAG, "getSettingName(): Service not connected");
+ return null;
+ }
+ }
}
diff --git a/core/java/android/hardware/biometrics/IAuthService.aidl b/core/java/android/hardware/biometrics/IAuthService.aidl
index d8c9dbc..1472bb9 100644
--- a/core/java/android/hardware/biometrics/IAuthService.aidl
+++ b/core/java/android/hardware/biometrics/IAuthService.aidl
@@ -68,4 +68,16 @@
// the requirements for integrating with Keystore. The AuthenticatorID are known in Keystore
// land as SIDs, and are used during key generation.
long[] getAuthenticatorIds();
+
+ // Provides a localized string that may be used as the label for a button that invokes
+ // BiometricPrompt.
+ CharSequence getButtonLabel(int userId, String opPackageName, int authenticators);
+
+ // Provides a localized string that may be shown while the user is authenticating with
+ // BiometricPrompt.
+ CharSequence getPromptMessage(int userId, String opPackageName, int authenticators);
+
+ // Provides a localized string that may be shown as the title for an app setting that enables
+ // biometric authentication.
+ CharSequence getSettingName(int userId, String opPackageName, int authenticators);
}
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index 2433186..6d8bf0f 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -75,4 +75,10 @@
long[] getAuthenticatorIds(int callingUserId);
int getCurrentStrength(int sensorId);
+
+ // Returns a bit field of the modality (or modalities) that are will be used for authentication.
+ int getCurrentModality(String opPackageName, int userId, int callingUserId, int authenticators);
+
+ // Returns a bit field of the authentication modalities that are supported by this device.
+ int getSupportedModalities(int authenticators);
}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 16ab900..07ebbaf 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -24,13 +24,11 @@
import android.hardware.camera2.impl.SyntheticKey;
import android.hardware.camera2.params.RecommendedStreamConfigurationMap;
import android.hardware.camera2.params.SessionConfiguration;
-import android.hardware.camera2.utils.ArrayUtils;
import android.hardware.camera2.utils.TypeReference;
import android.os.Build;
import android.util.Rational;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -641,27 +639,7 @@
*/
@NonNull
public Set<String> getPhysicalCameraIds() {
- int[] availableCapabilities = get(REQUEST_AVAILABLE_CAPABILITIES);
- if (availableCapabilities == null) {
- throw new AssertionError("android.request.availableCapabilities must be non-null "
- + "in the characteristics");
- }
-
- if (!ArrayUtils.contains(availableCapabilities,
- REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA)) {
- return Collections.emptySet();
- }
- byte[] physicalCamIds = get(LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
-
- String physicalCamIdString = null;
- try {
- physicalCamIdString = new String(physicalCamIds, "UTF-8");
- } catch (java.io.UnsupportedEncodingException e) {
- throw new AssertionError("android.logicalCam.physicalIds must be UTF-8 string");
- }
- String[] physicalCameraIdArray = physicalCamIdString.split("\0");
-
- return Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(physicalCameraIdArray)));
+ return mProperties.getPhysicalCameraIds();
}
/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
@@ -2931,6 +2909,74 @@
new Key<android.util.Size>("android.scaler.defaultSecureImageSize", android.util.Size.class);
/**
+ * <p>The available multi-resolution stream configurations that this
+ * physical camera device supports
+ * (i.e. format, width, height, output/input stream).</p>
+ * <p>This list contains a subset of the parent logical camera's multi-resolution stream
+ * configurations which belong to this physical camera, and it will advertise and will only
+ * advertise the maximum supported resolutions for a particular format.</p>
+ * <p>If this camera device isn't a physical camera device constituting a logical camera,
+ * but a standalone ULTRA_HIGH_RESOLUTION_SENSOR camera, this field represents the
+ * multi-resolution input/output stream configurations of default mode and max resolution
+ * modes. The sizes will be the maximum resolution of a particular format for default mode
+ * and max resolution mode.</p>
+ * <p>This field will only be advertised if the device is a physical camera of a
+ * logical multi-camera device or an ultra high resolution sensor camera. For a logical
+ * multi-camera, the camera API will derive the logical camera’s multi-resolution stream
+ * configurations from all physical cameras. For an ultra high resolution sensor camera, this
+ * is used directly as the camera’s multi-resolution stream configurations.</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ * <p><b>Limited capability</b> -
+ * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+ * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+ *
+ * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+ * @hide
+ */
+ public static final Key<android.hardware.camera2.params.StreamConfiguration[]> SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS =
+ new Key<android.hardware.camera2.params.StreamConfiguration[]>("android.scaler.physicalCameraMultiResolutionStreamConfigurations", android.hardware.camera2.params.StreamConfiguration[].class);
+
+ /**
+ * <p>The multi-resolution stream configurations supported by this logical camera
+ * or ultra high resolution sensor camera device.</p>
+ * <p>Multi-resolution streams can be used by a LOGICAL_MULTI_CAMERA or an
+ * ULTRA_HIGH_RESOLUTION_SENSOR camera where the images sent or received can vary in
+ * resolution per frame. This is useful in cases where the camera device's effective full
+ * resolution changes depending on factors such as the current zoom level, lighting
+ * condition, focus distance, or pixel mode.</p>
+ * <ul>
+ * <li>For a logical multi-camera implementing optical zoom, at different zoom level, a
+ * different physical camera may be active, resulting in different full-resolution image
+ * sizes.</li>
+ * <li>For an ultra high resolution camera, depending on whether the camera operates in default
+ * mode, or maximum resolution mode, the output full-size images may be of either binned
+ * resolution or maximum resolution.</li>
+ * </ul>
+ * <p>To use multi-resolution output streams, the supported formats can be queried by {@link android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getOutputFormats }.
+ * A {@link android.hardware.camera2.MultiResolutionImageReader } can then be created for a
+ * supported format with the MultiResolutionStreamInfo group queried by {@link android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getOutputInfo }.</p>
+ * <p>If a camera device supports multi-resolution output streams for a particular format, for
+ * each of its mandatory stream combinations, the camera device will support using a
+ * MultiResolutionImageReader for the MAXIMUM stream of supported formats. Refer to
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession } for additional details.</p>
+ * <p>To use multi-resolution input streams, the supported formats can be queried by {@link android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getInputFormats }.
+ * A reprocessable CameraCaptureSession can then be created using an {@link android.hardware.camera2.params.InputConfiguration InputConfiguration} constructed with
+ * the input MultiResolutionStreamInfo group, queried by {@link android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getInputInfo }.</p>
+ * <p>If a camera device supports multi-resolution {@code YUV} input and multi-resolution
+ * {@code YUV} output, or multi-resolution {@code PRIVATE} input and multi-resolution
+ * {@code PRIVATE} output, {@code JPEG} and {@code YUV} are guaranteed to be supported
+ * multi-resolution output stream formats. Refer to
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession } for
+ * details about the additional mandatory stream combinations in this case.</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ */
+ @PublicKey
+ @NonNull
+ @SyntheticKey
+ public static final Key<android.hardware.camera2.params.MultiResolutionStreamConfigurationMap> SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP =
+ new Key<android.hardware.camera2.params.MultiResolutionStreamConfigurationMap>("android.scaler.multiResolutionStreamConfigurationMap", android.hardware.camera2.params.MultiResolutionStreamConfigurationMap.class);
+
+ /**
* <p>The area of the image sensor which corresponds to active pixels after any geometric
* distortion correction has been applied.</p>
* <p>This is the rectangle representing the size of the active region of the sensor (i.e.
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index ac6ba0a..af48b71 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -770,6 +770,8 @@
* streams with {@code Y8} in all guaranteed stream combinations for the device's hardware level
* and capabilities.</p>
*
+ * <p>Clients can access the above mandatory stream combination tables via
+ * {@link android.hardware.camera2.params.MandatoryStreamCombination}.</p>
*
* <p>Devices capable of outputting HEIC formats ({@link StreamConfigurationMap#getOutputFormats}
* contains {@link android.graphics.ImageFormat#HEIC}) will support substituting {@code JPEG}
@@ -777,8 +779,33 @@
* level and capabilities. Calling createCaptureSession with both JPEG and HEIC outputs is not
* supported.</p>
*
- * <p>Clients can access the above mandatory stream combination tables via
- * {@link android.hardware.camera2.params.MandatoryStreamCombination}.</p>
+ * <p>Devices capable of multi-resolution output for a particular format (
+ * {@link android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getOutputInfo}
+ * returns a non-empty list) support using {@link MultiResolutionImageReader} for MAXIMUM
+ * resolution streams of that format for all mandatory stream combinations. For example,
+ * if a LIMITED camera device supports multi-resolution output streams for both {@code JPEG} and
+ * {@code PRIVATE}, in addition to the stream configurations
+ * in the LIMITED and Legacy table above, the camera device supports the following guaranteed
+ * stream combinations ({@code MULTI_RES} in the Max size column refers to a {@link
+ * MultiResolutionImageReader} created based on the variable max resolutions supported):
+ *
+ * <table>
+ * <tr><th colspan="7">LEGACY-level additional guaranteed combinations with MultiResolutionoutputs</th></tr>
+ * <tr> <th colspan="2" id="rb">Target 1</th> <th colspan="2" id="rb">Target 2</th> <th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
+ * <tr> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th></tr>
+ * <tr> <td>{@code PRIV}</td><td id="rb">{@code MULTI_RES}</td> <td colspan="2" id="rb"></td> <td colspan="2" id="rb"></td> <td>Simple preview, GPU video processing, or no-preview video recording.</td> </tr>
+ * <tr> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td colspan="2" id="rb"></td> <td colspan="2" id="rb"></td> <td>No-viewfinder still image capture.</td> </tr>
+ * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td colspan="2" id="rb"></td> <td>Standard still imaging.</td> </tr>
+ * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td>Still capture plus in-app processing.</td> </tr>
+ * </table><br>
+ * <table>
+ * <tr><th colspan="7">LIMITED-level additional guaranteed configurations with MultiResolutionoutputs</th></tr>
+ * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
+ * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
+ * <tr> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td>Two-input in-app processing with still capture.</td> </tr>
+ * </table><br>
+ * The same logic applies to other hardware levels and capabilities.
+ * </p>
*
* <p>Since the capabilities of camera devices vary greatly, a given camera device may support
* target combinations with sizes outside of these guarantees, but this can only be tested for
@@ -939,6 +966,32 @@
* </table><br>
* </p>
*
+ * <p>If a camera device supports multi-resolution {@code YUV} input and multi-resolution
+ * {@code YUV} output or supports multi-resolution {@code PRIVATE} input and multi-resolution
+ * {@code PRIVATE} output, the additional mandatory stream combinations for LIMITED and FULL devices are listed
+ * below ({@code MULTI_RES} in the Max size column refers to a
+ * {@link MultiResolutionImageReader} for output, and a multi-resolution
+ * {@link InputConfiguration} for input):
+ * <table>
+ * <tr><th colspan="11">LIMITED-level additional guaranteed configurations for creating a reprocessable capture session with multi-resolution input and multi-resolution outputs<br>({@code PRIV} input is guaranteed only if PRIVATE reprocessing is supported. {@code YUV} input is guaranteed only if YUV reprocessing is supported)</th></tr>
+ * <tr><th colspan="2" id="rb">Input</th><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th rowspan="2">Sample use case(s)</th> </tr>
+ * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
+ * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MULTI_RES}</td> <td>Same as input</td><td id="rb">{@code MULTI_RES}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td></td><td id="rb"></td> <td></td><td id="rb"></td> <td>No-viewfinder still image reprocessing.</td> </tr>
+ * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MULTI_RES}</td> <td>Same as input</td><td id="rb">{@code MULTI_RES}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td></td><td id="rb"></td> <td>ZSL(Zero-Shutter-Lag) still imaging.</td> </tr>
+ * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MULTI_RES}</td> <td>Same as input</td><td id="rb">{@code MULTI_RES}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td></td><td id="rb"></td> <td>ZSL still and in-app processing imaging.</td> </tr>
+ * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MULTI_RES}</td> <td>Same as input</td><td id="rb">{@code MULTI_RES}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td>ZSL in-app processing with still capture.</td> </tr>
+ * </table><br>
+ * <table>
+ * <tr><th colspan="11">FULL-level additional guaranteed configurations for creating a reprocessable capture session with multi-resolution input and multi-resolution outputs<br>({@code PRIV} input is guaranteed only if PRIVATE reprocessing is supported. {@code YUV} input is guaranteed only if YUV reprocessing is supported)</th></tr>
+ * <tr><th colspan="2" id="rb">Input</th><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th rowspan="2">Sample use case(s)</th> </tr>
+ * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
+ * <tr> <td>{@code PRIV}</td><td id="rb">{@code MULTI_RES}</td> <td>{@code PRIV}</td><td id="rb">{@code MULTI_RES}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code MULTI_RES}</td> <td></td><td id="rb"></td> <td>Maximum-resolution ZSL in-app processing with regular preview.</td> </tr>
+ * <tr> <td>{@code PRIV}</td><td id="rb">{@code MULTI_RES}</td> <td>{@code PRIV}</td><td id="rb">{@code MULTI_RES}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code MULTI_RES}</td> <td></td><td id="rb"></td> <td>Maximum-resolution two-input ZSL in-app processing.</td> </tr>
+ * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MULTI_RES}</td> <td>Same as input</td><td id="rb">{@code MULTI_RES}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td>ZSL still capture and in-app processing.</td> </tr>
+ * </table><br>
+ * No additional mandatory stream combinations for RAW capability and LEVEL-3 hardware level.
+ * </p>
+ *
* <h3>Constrained high-speed recording</h3>
*
* <p>The application can use a
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 3e0e3f62..a3c6f2f 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -31,6 +31,7 @@
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.params.ExtensionSessionConfiguration;
import android.hardware.camera2.params.SessionConfiguration;
+import android.hardware.camera2.params.StreamConfiguration;
import android.hardware.camera2.utils.CameraIdAndSessionConfiguration;
import android.hardware.camera2.utils.ConcurrentCameraIdCombination;
import android.hardware.display.DisplayManager;
@@ -51,6 +52,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
@@ -372,6 +374,47 @@
}
/**
+ * Get all physical cameras' multi-resolution stream configuration map
+ *
+ * <p>For a logical multi-camera, query the map between physical camera id and
+ * the physical camera's multi-resolution stream configuration. This map is in turn
+ * combined to form the logical camera's multi-resolution stream configuration map.</p>
+ */
+ private Map<String, StreamConfiguration[]> getPhysicalCameraMultiResolutionConfigs(
+ CameraMetadataNative info, ICameraService cameraService)
+ throws CameraAccessException {
+ HashMap<String, StreamConfiguration[]> multiResolutionStreamConfigurations =
+ new HashMap<String, StreamConfiguration[]>();
+
+ // Query the characteristics of all physical sub-cameras, and combine the multi-resolution
+ // stream configurations. Note that framework derived formats such as HEIC and DEPTH_JPEG
+ // aren't supported as multi-resolution input or output formats.
+ Set<String> physicalCameraIds = info.getPhysicalCameraIds();
+ try {
+ for (String physicalCameraId : physicalCameraIds) {
+ CameraMetadataNative physicalCameraInfo =
+ cameraService.getCameraCharacteristics(physicalCameraId);
+ StreamConfiguration[] configs = physicalCameraInfo.get(
+ CameraCharacteristics.
+ SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS);
+ if (configs != null) {
+ multiResolutionStreamConfigurations.put(physicalCameraId, configs);
+ }
+ }
+
+ // TODO: If this is an ultra high resolution sensor camera, combine the multi-resolution
+ // stream combination from "info" as well.
+ } catch (RemoteException e) {
+ ServiceSpecificException sse = new ServiceSpecificException(
+ ICameraService.ERROR_DISCONNECTED,
+ "Camera service is currently unavailable");
+ throwAsPublicException(sse);
+ }
+
+ return multiResolutionStreamConfigurations;
+ }
+
+ /**
* <p>Query the capabilities of a camera device. These capabilities are
* immutable for a given camera.</p>
*
@@ -418,12 +461,19 @@
} catch (NumberFormatException e) {
Log.v(TAG, "Failed to parse camera Id " + cameraId + " to integer");
}
+
boolean hasConcurrentStreams =
CameraManagerGlobal.get().cameraIdHasConcurrentStreamsLocked(cameraId);
info.setHasMandatoryConcurrentStreams(hasConcurrentStreams);
info.setDisplaySize(displaySize);
- characteristics = new CameraCharacteristics(info);
+ Map<String, StreamConfiguration[]> multiResolutionSizeMap =
+ getPhysicalCameraMultiResolutionConfigs(info, cameraService);
+ if (multiResolutionSizeMap.size() > 0) {
+ info.setMultiResolutionStreamConfigurationMap(multiResolutionSizeMap);
+ }
+
+ characteristics = new CameraCharacteristics(info);
} catch (ServiceSpecificException e) {
throwAsPublicException(e);
} catch (RemoteException e) {
diff --git a/core/java/android/hardware/camera2/MultiResolutionImageReader.java b/core/java/android/hardware/camera2/MultiResolutionImageReader.java
new file mode 100644
index 0000000..c592f19
--- /dev/null
+++ b/core/java/android/hardware/camera2/MultiResolutionImageReader.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2021 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 android.hardware.camera2;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.graphics.ImageFormat;
+import android.graphics.ImageFormat.Format;
+import android.hardware.HardwareBuffer;
+import android.hardware.HardwareBuffer.Usage;
+import android.media.Image;
+import android.media.ImageReader;
+import android.hardware.camera2.params.MultiResolutionStreamInfo;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android.view.Surface;
+
+
+import java.nio.NioUtils;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * <p>The MultiResolutionImageReader class wraps a group of {@link ImageReader ImageReaders} with
+ * the same format and different sizes, source camera Id, or camera sensor modes.</p>
+ *
+ * <p>The main use case of this class is for a
+ * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA logical
+ * multi-camera} or an ultra high resolution sensor camera to output variable-size images. For a
+ * logical multi-camera which implements optical zoom, different physical cameras may have different
+ * maximum resolutions. As a result, when the camera device switches between physical cameras
+ * depending on zoom ratio, the maximum resolution for a particular format may change. For an
+ * ultra high resolution sensor camera, the camera device may deem it better or worse to run in
+ * maximum resolution mode / default mode depending on lighting conditions. So the application may
+ * choose to let the camera device decide on its behalf.</p>
+ *
+ * <p>MultiResolutionImageReader should be used for a camera device only if the camera device
+ * supports multi-resolution output stream by advertising the specified output format in {@link
+ * CameraCharacteristics#SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP}.</p>
+ *
+ * <p>To acquire images from the MultiResolutionImageReader, the application must use the
+ * {@link ImageReader} object passed by
+ * {@link ImageReader.OnImageAvailableListener#onImageAvailable} callback to call
+ * {@link ImageReader#acquireNextImage} or {@link ImageReader#acquireLatestImage}. The application
+ * must not use the {@link ImageReader} passed by an {@link
+ * ImageReader.OnImageAvailableListener#onImageAvailable} callback to acquire future images
+ * because future images may originate from a different {@link ImageReader} contained within the
+ * {@code MultiResolutionImageReader}.</p>
+ *
+ *
+ * @see ImageReader
+ * @see android.hardware.camera2.CameraCharacteristics#SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP
+ */
+public class MultiResolutionImageReader implements AutoCloseable {
+
+ private static final String TAG = "MultiResolutionImageReader";
+
+ /**
+ * <p>
+ * Create a new multi-resolution reader based on a group of camera stream properties returned
+ * by a camera device.
+ * </p>
+ * <p>
+ * The valid size and formats depend on the camera characteristics.
+ * {@code MultiResolutionImageReader} for an image format is supported by the camera device if
+ * the format is in the supported multi-resolution output stream formats returned by
+ * {@link android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getOutputFormats}.
+ * If the image format is supported, the {@code MultiResolutionImageReader} object can be
+ * created with the {@code streams} objects returned by
+ * {@link android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getOutputInfo}.
+ * </p>
+ * <p>
+ * The {@code maxImages} parameter determines the maximum number of
+ * {@link Image} objects that can be be acquired from each of the {@code ImageReader}
+ * within the {@code MultiResolutionImageReader}. However, requesting more buffers will
+ * use up more memory, so it is important to use only the minimum number necessary. The
+ * application is strongly recommended to acquire no more than {@code maxImages} images
+ * from all of the internal ImageReader objects combined. By keeping track of the number of
+ * acquired images for the MultiResolutionImageReader, the application doesn't need to do the
+ * bookkeeping for each internal ImageReader returned from {@link
+ * ImageReader.OnImageAvailableListener#onImageAvailable onImageAvailable} callback.
+ * </p>
+ * <p>
+ * Unlike the normal ImageReader, the MultiResolutionImageReader has a more complex
+ * configuration sequence. Instead of passing the same surface to OutputConfiguration and
+ * CaptureRequest, the
+ * {@link android.hardware.camera2.params.OutputConfiguration#createInstancesForMultiResolutionOutput}
+ * call needs to be used to create the OutputConfigurations for session creation, and then
+ * {@link #getSurface} is used to get {@link CaptureRequest.Builder#addTarget the target for
+ * CaptureRequest}.
+ * </p>
+ * @param streams The group of multi-resolution stream info, which is used to create
+ * a multi-resolution reader containing a number of ImageReader objects. Each
+ * ImageReader object represents a multi-resolution stream in the group.
+ * @param format The format of the Image that this multi-resolution reader will produce.
+ * This must be one of the {@link android.graphics.ImageFormat} or
+ * {@link android.graphics.PixelFormat} constants. Note that not all formats are
+ * supported, like ImageFormat.NV21. The supported multi-resolution
+ * reader format can be queried by {@link
+ * android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getOutputFormats}.
+ * @param maxImages The maximum number of images the user will want to
+ * access simultaneously. This should be as small as possible to
+ * limit memory use. Once maxImages images are obtained by the
+ * user from any given internal ImageReader, one of them has to be released before
+ * a new Image will become available for access through the ImageReader's
+ * {@link ImageReader#acquireLatestImage()} or
+ * {@link ImageReader#acquireNextImage()}. Must be greater than 0.
+ * @see Image
+ * @see
+ * android.hardware.camera2.CameraCharacteristics#SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP
+ * @see
+ * android.hardware.camera2.params.MultiResolutionStreamConfigurationMap
+ */
+ public static @NonNull MultiResolutionImageReader newInstance(
+ @NonNull Collection<MultiResolutionStreamInfo> streams,
+ @Format int format,
+ @IntRange(from = 1) int maxImages) {
+ return new MultiResolutionImageReader(streams, format, maxImages);
+ }
+
+ /**
+ * @hide
+ */
+ protected MultiResolutionImageReader(Collection<MultiResolutionStreamInfo> streams,
+ int format, int maxImages) {
+ mFormat = format;
+ mMaxImages = maxImages;
+
+ if (streams == null || streams.size() <= 1) {
+ throw new IllegalArgumentException(
+ "The streams info collection must contain at least 2 entries");
+ }
+ if (mMaxImages < 1) {
+ throw new IllegalArgumentException(
+ "Maximum outstanding image count must be at least 1");
+ }
+
+ if (format == ImageFormat.NV21) {
+ throw new IllegalArgumentException(
+ "NV21 format is not supported");
+ }
+
+ int numImageReaders = streams.size();
+ mReaders = new ImageReader[numImageReaders];
+ mStreamInfo = new MultiResolutionStreamInfo[numImageReaders];
+ int index = 0;
+ for (MultiResolutionStreamInfo streamInfo : streams) {
+ mReaders[index] = ImageReader.newInstance(streamInfo.getWidth(),
+ streamInfo.getHeight(), format, maxImages);
+ mStreamInfo[index] = streamInfo;
+ index++;
+ }
+ }
+
+ /**
+ * Set onImageAvailableListener callback.
+ *
+ * <p>This function sets the onImageAvailableListener for all the internal
+ * {@link ImageReader} objects.</p>
+ *
+ * <p>For a multi-resolution ImageReader, the timestamps of images acquired in
+ * onImageAvailable callback from different internal ImageReaders may become
+ * out-of-order due to the asynchronous callbacks between the different resolution
+ * image queues.</p>
+ *
+ * @param listener
+ * The listener that will be run.
+ * @param executor
+ * The executor which will be used when invoking the callback.
+ */
+ @SuppressLint({"ExecutorRegistration", "SamShouldBeLast"})
+ public void setOnImageAvailableListener(
+ @Nullable ImageReader.OnImageAvailableListener listener,
+ @Nullable @CallbackExecutor Executor executor) {
+ for (int i = 0; i < mReaders.length; i++) {
+ mReaders[i].setOnImageAvailableListenerWithExecutor(listener, executor);
+ }
+ }
+
+ @Override
+ public void close() {
+ flush();
+
+ for (int i = 0; i < mReaders.length; i++) {
+ mReaders[i].close();
+ }
+ }
+
+ @Override
+ protected void finalize() {
+ close();
+ }
+
+ /**
+ * Flush pending images from all internal ImageReaders
+ *
+ * <p>Acquire and close pending images from all internal ImageReaders. This has the same
+ * effect as calling acquireLatestImage() on all internal ImageReaders, and closing all
+ * latest images.</p>
+ */
+ public void flush() {
+ flushOther(null);
+ }
+
+ /**
+ * Flush pending images from other internal ImageReaders
+ *
+ * <p>Acquire and close pending images from all internal ImageReaders except for the
+ * one specified.</p>
+ *
+ * @param reader The ImageReader object that won't be flushed.
+ *
+ * @hide
+ */
+ public void flushOther(ImageReader reader) {
+ for (int i = 0; i < mReaders.length; i++) {
+ if (reader != null && reader == mReaders[i]) {
+ continue;
+ }
+
+ while (true) {
+ Image image = mReaders[i].acquireNextImageNoThrowISE();
+ if (image == null) {
+ break;
+ } else {
+ image.close();
+ }
+ }
+ }
+ }
+
+ /**
+ * Get the internal ImageReader objects
+ *
+ * @hide
+ */
+ public @NonNull ImageReader[] getReaders() {
+ return mReaders;
+ }
+
+ /**
+ * Get the surface that is used as a target for {@link CaptureRequest}
+ *
+ * <p>The application must use the surface returned by this function as a target for
+ * {@link CaptureRequest}. The camera device makes the decision on which internal
+ * {@code ImageReader} will receive the output image.</p>
+ *
+ * <p>Please note that holding on to the Surface objects returned by this method is not enough
+ * to keep their parent MultiResolutionImageReaders from being reclaimed. In that sense, a
+ * Surface acts like a {@link java.lang.ref.WeakReference weak reference} to the
+ * MultiResolutionImageReader that provides it.</p>
+ *
+ * @return a {@link Surface} to use as the target for a capture request.
+ */
+ public @NonNull Surface getSurface() {
+ //TODO: Pick the surface from the reader for default mode stream.
+ return mReaders[0].getSurface();
+ }
+
+ /**
+ * Get the MultiResolutionStreamInfo describing the ImageReader an image originates from
+ *
+ *<p>An image from a {@code MultiResolutionImageReader} is produced from one of the underlying
+ *{@code ImageReader}s. This function returns the {@link MultiResolutionStreamInfo} to describe
+ *the property for that {@code ImageReader}, such as width, height, and physical camera Id.</p>
+ *
+ * @param reader An internal ImageReader within {@code MultiResolutionImageReader}.
+ *
+ * @return The stream info describing the internal {@code ImageReader}.
+ */
+ public @NonNull MultiResolutionStreamInfo getStreamInfoForImageReader(
+ @NonNull ImageReader reader) {
+ for (int i = 0; i < mReaders.length; i++) {
+ if (reader == mReaders[i]) {
+ return mStreamInfo[i];
+ }
+ }
+
+ throw new IllegalArgumentException("ImageReader doesn't belong to this multi-resolution "
+ + "imagereader");
+ }
+
+ // mReaders and mStreamInfo has the same length, and their entries are 1:1 mapped.
+ private final ImageReader[] mReaders;
+ private final MultiResolutionStreamInfo[] mStreamInfo;
+
+ private final int mFormat;
+ private final int mMaxImages;
+}
diff --git a/core/java/android/hardware/camera2/TotalCaptureResult.java b/core/java/android/hardware/camera2/TotalCaptureResult.java
index da65f71..df8eecc 100644
--- a/core/java/android/hardware/camera2/TotalCaptureResult.java
+++ b/core/java/android/hardware/camera2/TotalCaptureResult.java
@@ -61,8 +61,8 @@
private final List<CaptureResult> mPartialResults;
private final int mSessionId;
- // The map between physical camera id and capture result
- private final HashMap<String, CaptureResult> mPhysicalCaptureResults;
+ // The map between physical camera ids and their total capture result
+ private final HashMap<String, TotalCaptureResult> mPhysicalCaptureResults;
/**
* Takes ownership of the passed-in camera metadata and the partial results
@@ -83,10 +83,11 @@
mSessionId = sessionId;
- mPhysicalCaptureResults = new HashMap<String, CaptureResult>();
+ mPhysicalCaptureResults = new HashMap<String, TotalCaptureResult>();
for (PhysicalCaptureResultInfo onePhysicalResult : physicalResults) {
- CaptureResult physicalResult = new CaptureResult(onePhysicalResult.getCameraId(),
- onePhysicalResult.getCameraMetadata(), parent, extras);
+ TotalCaptureResult physicalResult = new TotalCaptureResult(
+ onePhysicalResult.getCameraId(), onePhysicalResult.getCameraMetadata(),
+ parent, extras, /*partials*/null, sessionId, new PhysicalCaptureResultInfo[0]);
mPhysicalCaptureResults.put(onePhysicalResult.getCameraId(),
physicalResult);
}
@@ -103,7 +104,7 @@
mPartialResults = new ArrayList<>();
mSessionId = CameraCaptureSession.SESSION_ID_NONE;
- mPhysicalCaptureResults = new HashMap<String, CaptureResult>();
+ mPhysicalCaptureResults = new HashMap<String, TotalCaptureResult>();
}
/**
@@ -146,8 +147,37 @@
* cameras. Otherwise, an empty map is returned.</p>
* @return unmodifiable map between physical camera ids and their capture result metadata
+ *
+ * @deprecated
+ * <p>Please use {@link #getPhysicalCameraTotalResults() instead to get the
+ * physical cameras' {@code TotalCaptureResult}.</p>
*/
public Map<String, CaptureResult> getPhysicalCameraResults() {
return Collections.unmodifiableMap(mPhysicalCaptureResults);
}
+
+ /**
+ * Get the map between physical camera ids and their total capture result metadata
+ *
+ * <p>This function can be called for logical multi-camera devices, which are devices that have
+ * REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA capability.</p>
+ *
+ * <p>If one or more streams from the underlying physical cameras were requested by the
+ * corresponding capture request, this function returns the total result metadata for those
+ * physical cameras. Otherwise, an empty map is returned.</p>
+ *
+ * <p>This function replaces the deprecated {@link #getPhysicalCameraResults}, and its return
+ * value is a map of TotalCaptureResult rather than CaptureResult. </p>
+ *
+ * <p>To reprocess an image from a physical camera stream, typically returned from a
+ * {@link MultiResolutionImageReader}, the application must look up this map to get the {@link
+ * TotalCaptureResult} from the physical camera and pass it to {@link
+ * CameraDevice#createReprocessCaptureRequest}.</p>
+ *
+ * @return unmodifiable map between physical camera ids and their total capture result metadata
+ */
+ @NonNull
+ public Map<String, TotalCaptureResult> getPhysicalCameraTotalResults() {
+ return Collections.unmodifiableMap(mPhysicalCaptureResults);
+ }
}
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index ce3c81a..4defd23 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -36,6 +36,8 @@
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.ExtensionSessionConfiguration;
import android.hardware.camera2.params.InputConfiguration;
+import android.hardware.camera2.params.MultiResolutionStreamConfigurationMap;
+import android.hardware.camera2.params.MultiResolutionStreamInfo;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.params.SessionConfiguration;
import android.hardware.camera2.params.StreamConfigurationMap;
@@ -468,7 +470,8 @@
}
if (inputConfig != null) {
int streamId = mRemoteDevice.createInputStream(inputConfig.getWidth(),
- inputConfig.getHeight(), inputConfig.getFormat());
+ inputConfig.getHeight(), inputConfig.getFormat(),
+ inputConfig.isMultiResolution());
mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(
streamId, inputConfig);
}
@@ -1355,7 +1358,42 @@
}
private void checkInputConfiguration(InputConfiguration inputConfig) {
- if (inputConfig != null) {
+ if (inputConfig == null) {
+ return;
+ }
+
+ if (inputConfig.isMultiResolution()) {
+ MultiResolutionStreamConfigurationMap configMap = mCharacteristics.get(
+ CameraCharacteristics.SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP);
+
+ int[] inputFormats = configMap.getInputFormats();
+ boolean validFormat = false;
+ for (int format : inputFormats) {
+ if (format == inputConfig.getFormat()) {
+ validFormat = true;
+ }
+ }
+
+ if (validFormat == false) {
+ throw new IllegalArgumentException("multi-resolution input format " +
+ inputConfig.getFormat() + " is not valid");
+ }
+
+ boolean validSize = false;
+ Collection<MultiResolutionStreamInfo> inputStreamInfo =
+ configMap.getInputInfo(inputConfig.getFormat());
+ for (MultiResolutionStreamInfo info : inputStreamInfo) {
+ if (inputConfig.getWidth() == info.getWidth() &&
+ inputConfig.getHeight() == info.getHeight()) {
+ validSize = true;
+ }
+ }
+
+ if (validSize == false) {
+ throw new IllegalArgumentException("Multi-resolution input size " +
+ inputConfig.getWidth() + "x" + inputConfig.getHeight() + " is not valid");
+ }
+ } else {
StreamConfigurationMap configMap = mCharacteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index e9bae0b..0cdf744 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -16,6 +16,7 @@
package android.hardware.camera2.impl;
+import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.ImageFormat;
import android.graphics.Point;
@@ -53,6 +54,7 @@
import android.hardware.camera2.params.HighSpeedVideoConfiguration;
import android.hardware.camera2.params.LensShadingMap;
import android.hardware.camera2.params.MandatoryStreamCombination;
+import android.hardware.camera2.params.MultiResolutionStreamConfigurationMap;
import android.hardware.camera2.params.OisSample;
import android.hardware.camera2.params.RecommendedStreamConfiguration;
import android.hardware.camera2.params.RecommendedStreamConfigurationMap;
@@ -61,6 +63,7 @@
import android.hardware.camera2.params.StreamConfigurationDuration;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.hardware.camera2.params.TonemapCurve;
+import android.hardware.camera2.utils.ArrayUtils;
import android.hardware.camera2.utils.TypeReference;
import android.location.Location;
import android.location.LocationManager;
@@ -79,9 +82,14 @@
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
/**
* Implementation of camera metadata marshal/unmarshal across Binder to
@@ -747,6 +755,15 @@
return (T) metadata.getExtendedSceneModeCapabilities();
}
});
+ sGetCommandMap.put(
+ CameraCharacteristics.SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP.getNativeKey(),
+ new GetCommand() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+ return (T) metadata.getMultiResolutionStreamConfigurationMap();
+ }
+ });
}
private int[] getAvailableFormats() {
@@ -1688,6 +1705,7 @@
private boolean mHasMandatoryConcurrentStreams = false;
private Size mDisplaySize = new Size(0, 0);
private long mBufferSize = 0;
+ private MultiResolutionStreamConfigurationMap mMultiResolutionStreamConfigurationMap = null;
/**
* Set the current camera Id.
@@ -1723,6 +1741,30 @@
mDisplaySize = displaySize;
}
+ /**
+ * Set the multi-resolution stream configuration map.
+ *
+ * @param multiResolutionMap The multi-resolution stream configuration map.
+ *
+ * @hide
+ */
+ public void setMultiResolutionStreamConfigurationMap(
+ @NonNull Map<String, StreamConfiguration[]> multiResolutionMap) {
+ mMultiResolutionStreamConfigurationMap =
+ new MultiResolutionStreamConfigurationMap(multiResolutionMap);
+ }
+
+ /**
+ * Get the multi-resolution stream configuration map.
+ *
+ * @return The multi-resolution stream configuration map.
+ *
+ * @hide
+ */
+ public MultiResolutionStreamConfigurationMap getMultiResolutionStreamConfigurationMap() {
+ return mMultiResolutionStreamConfigurationMap;
+ }
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private long mMetadataPtr; // native std::shared_ptr<CameraMetadata>*
@@ -1777,6 +1819,7 @@
mCameraId = other.mCameraId;
mHasMandatoryConcurrentStreams = other.mHasMandatoryConcurrentStreams;
mDisplaySize = other.mDisplaySize;
+ mMultiResolutionStreamConfigurationMap = other.mMultiResolutionStreamConfigurationMap;
updateNativeAllocation();
other.updateNativeAllocation();
}
@@ -1980,6 +2023,39 @@
return true;
}
+ /**
+ * Return the set of physical camera ids that this logical {@link CameraDevice} is made
+ * up of.
+ *
+ * If the camera device isn't a logical camera, return an empty set.
+ *
+ * @hide
+ */
+ public Set<String> getPhysicalCameraIds() {
+ int[] availableCapabilities = get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
+ if (availableCapabilities == null) {
+ throw new AssertionError("android.request.availableCapabilities must be non-null "
+ + "in the characteristics");
+ }
+
+ if (!ArrayUtils.contains(availableCapabilities,
+ CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA)) {
+ return Collections.emptySet();
+ }
+ byte[] physicalCamIds = get(CameraCharacteristics.LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
+
+ String physicalCamIdString = null;
+ try {
+ physicalCamIdString = new String(physicalCamIds, "UTF-8");
+ } catch (java.io.UnsupportedEncodingException e) {
+ throw new AssertionError("android.logicalCam.physicalIds must be UTF-8 string");
+ }
+ String[] physicalCameraIdArray = physicalCamIdString.split("\0");
+
+ return Collections.unmodifiableSet(
+ new HashSet<String>(Arrays.asList(physicalCameraIdArray)));
+ }
+
static {
registerAllMarshalers();
}
diff --git a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
index ba4395f..b6b1968 100644
--- a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
+++ b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
@@ -140,9 +140,10 @@
}
}
- public int createInputStream(int width, int height, int format) throws CameraAccessException {
+ public int createInputStream(int width, int height, int format, boolean isMultiResolution)
+ throws CameraAccessException {
try {
- return mRemoteDevice.createInputStream(width, height, format);
+ return mRemoteDevice.createInputStream(width, height, format, isMultiResolution);
} catch (Throwable t) {
CameraManager.throwAsPublicException(t);
throw new UnsupportedOperationException("Unexpected exception", t);
diff --git a/core/java/android/hardware/camera2/params/InputConfiguration.java b/core/java/android/hardware/camera2/params/InputConfiguration.java
index 0a50f97..d63683f 100644
--- a/core/java/android/hardware/camera2/params/InputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/InputConfiguration.java
@@ -16,9 +16,17 @@
package android.hardware.camera2.params;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.graphics.ImageFormat.Format;
+import android.hardware.camera2.params.MultiResolutionStreamInfo;
import android.hardware.camera2.utils.HashCodeHelpers;
+import java.util.Collection;
+import java.util.List;
+
+import static com.android.internal.util.Preconditions.*;
+
/**
* Immutable class to store an input configuration that is used to create a reprocessable capture
* session.
@@ -31,11 +39,12 @@
private final int mWidth;
private final int mHeight;
private final int mFormat;
+ private final boolean mIsMultiResolution;
/**
* Create an input configration with the width, height, and user-defined format.
*
- * <p>Images of an user-defined format are accessible by applications. Use
+ * <p>Images of a user-defined format are accessible by applications. Use
* {@link android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP}
* to query supported input formats</p>
*
@@ -51,6 +60,52 @@
mWidth = width;
mHeight = height;
mFormat = format;
+ mIsMultiResolution = false;
+ }
+
+ /**
+ * Create an input configration with the format and a list of multi-resolution input stream
+ * info.
+ *
+ * <p>Use {@link
+ * android.hardware.camera2.CameraCharacteristics#SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP}
+ * to query supported multi-resolution input formats.</p>
+ *
+ * <p>To do reprocessing with variable resolution input, the application calls
+ * {@link android.media.ImageWriter#queueInputImage ImageWriter.queueInputImage}
+ * using an image from an {@link android.media.ImageReader ImageReader} or {@link
+ * android.hardware.camera2.MultiResolutionImageReader MultiResolutionImageReader}. See
+ * {@link android.hardware.camera2.CameraDevice#createReprocessCaptureRequest} for more
+ * details on camera reprocessing.
+ * </p>
+ *
+ * @param multiResolutionInputs A group of multi-resolution input info for the specified format.
+ * @param format Format of the input buffers. One of ImageFormat or PixelFormat constants.
+ *
+ * @see android.graphics.ImageFormat
+ * @see android.graphics.PixelFormat
+ * @see
+ * android.hardware.camera2.CameraCharacteristics#SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP
+ */
+ public InputConfiguration(@NonNull Collection<MultiResolutionStreamInfo> multiResolutionInputs,
+ @Format int format) {
+ checkCollectionNotEmpty(multiResolutionInputs, "Input multi-resolution stream info");
+ //TODO: Pick the default mode stream info for ultra-high resolution sensor camera
+ MultiResolutionStreamInfo info = multiResolutionInputs.iterator().next();
+ mWidth = info.getWidth();
+ mHeight = info.getHeight();
+ mFormat = format;
+ mIsMultiResolution = true;
+ }
+
+ /**
+ * @hide
+ */
+ public InputConfiguration(int width, int height, int format, boolean isMultiResolution) {
+ mWidth = width;
+ mHeight = height;
+ mFormat = format;
+ mIsMultiResolution = isMultiResolution;
}
/**
@@ -81,6 +136,18 @@
}
/**
+ * Whether this input configuration is of multi-resolution.
+ *
+ * <p>An multi-resolution InputConfiguration means that the reprocessing session created from it
+ * allows input images of different sizes.</p>
+ *
+ * @return this input configuration is multi-resolution or not.
+ */
+ public boolean isMultiResolution() {
+ return mIsMultiResolution;
+ }
+
+ /**
* Check if this InputConfiguration is equal to another InputConfiguration.
*
* <p>Two input configurations are equal if and only if they have the same widths, heights, and
@@ -100,7 +167,8 @@
if (otherInputConfig.getWidth() == mWidth &&
otherInputConfig.getHeight() == mHeight &&
- otherInputConfig.getFormat() == mFormat) {
+ otherInputConfig.getFormat() == mFormat &&
+ otherInputConfig.isMultiResolution() == mIsMultiResolution) {
return true;
}
return false;
@@ -111,19 +179,21 @@
*/
@Override
public int hashCode() {
- return HashCodeHelpers.hashCode(mWidth, mHeight, mFormat);
+ return HashCodeHelpers.hashCode(mWidth, mHeight, mFormat, mIsMultiResolution ? 1 : 0);
}
/**
* Return this {@link InputConfiguration} as a string representation.
*
- * <p> {@code "InputConfiguration(w:%d, h:%d, format:%d)"}, where {@code %d} represents
- * the width, height, and format, respectively.</p>
+ * <p> {@code "InputConfiguration(w:%d, h:%d, format:%d, isMultiResolution:%d)"},
+ * where {@code %d} represents the width, height, format, and multi-resolution flag
+ * respectively.</p>
*
* @return string representation of {@link InputConfiguration}
*/
@Override
public String toString() {
- return String.format("InputConfiguration(w:%d, h:%d, format:%d)", mWidth, mHeight, mFormat);
+ return String.format("InputConfiguration(w:%d, h:%d, format:%d, isMultiResolution %b)",
+ mWidth, mHeight, mFormat, mIsMultiResolution);
}
}
diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
index 776d155..8a0172e 100644
--- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
+++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
@@ -1297,19 +1297,6 @@
}
/**
- * Size comparison method used by size comparators.
- */
- private static int compareSizes(int widthA, int heightA, int widthB, int heightB) {
- long left = widthA * (long) heightA;
- long right = widthB * (long) heightB;
- if (left == right) {
- left = widthA;
- right = widthB;
- }
- return (left < right) ? -1 : (left > right ? 1 : 0);
- }
-
- /**
* Size comparator that compares the number of pixels it covers.
*
* <p>If two the areas of two sizes are same, compare the widths.</p>
@@ -1317,8 +1304,8 @@
public static class SizeComparator implements Comparator<Size> {
@Override
public int compare(@NonNull Size lhs, @NonNull Size rhs) {
- return compareSizes(lhs.getWidth(), lhs.getHeight(), rhs.getWidth(),
- rhs.getHeight());
+ return StreamConfigurationMap.compareSizes(lhs.getWidth(), lhs.getHeight(),
+ rhs.getWidth(), rhs.getHeight());
}
}
diff --git a/core/java/android/hardware/camera2/params/MultiResolutionStreamConfigurationMap.java b/core/java/android/hardware/camera2/params/MultiResolutionStreamConfigurationMap.java
new file mode 100644
index 0000000..1b368fb
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/MultiResolutionStreamConfigurationMap.java
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2021 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 android.hardware.camera2.params;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import android.graphics.ImageFormat;
+import android.graphics.ImageFormat.Format;
+import android.graphics.PixelFormat;
+import android.hardware.camera2.params.MultiResolutionStreamInfo;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.hardware.camera2.utils.HashCodeHelpers;
+
+import android.util.Size;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.List;
+import java.util.Set;
+
+import static com.android.internal.util.Preconditions.*;
+
+/**
+ * Immutable class to store the information of the multi-resolution streams supported by
+ * the camera device.
+ *
+ * <p>For a {@link
+ * android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
+ * logical multi-camera} or an ultra high resolution sensor camera, the maximum resolution of images
+ * produced by the camera device may be variable. For example, for a logical multi-camera, depending
+ * on factors such as current zoom ratio, the camera device may be backed by different physical
+ * cameras. If the physical cameras are of different resolutions, the application may intend to
+ * consume the variable full resolution images from the physical cameras. For an ultra high
+ * resolution sensor camera, the same use case exists where depending on lighting conditions, the
+ * camera device may deem it better to run in default mode and maximum resolution mode.
+ * </p>
+ *
+ * <p>For the use cases described above, multi-resolution output streams can be used by
+ * {@link android.hardware.camera2.MultiResolutionImageReader} to allow the
+ * camera device to output variable size maximum-resolution images.</p>
+ *
+ * <p>Similarly, multi-resolution input streams can be used for reprocessing of variable size
+ * images. In order to reprocess input images of different sizes, the {@link InputConfiguration}
+ * used for creating reprocessable session can be initialized using the group of input stream
+ * configurations returned by {@link #getInputInfo}.</p>
+ */
+public final class MultiResolutionStreamConfigurationMap {
+ /**
+ * Create a new {@link MultiResolutionStreamConfigurationMap}.
+ *
+ * @param configurations a non-{@code null} array of multi-resolution stream
+ * configurations supported by this camera device
+ * @hide
+ */
+ public MultiResolutionStreamConfigurationMap(
+ @NonNull Map<String, StreamConfiguration[]> configurations) {
+ checkNotNull(configurations, "multi-resolution configurations must not be null");
+ if (configurations.size() == 0) {
+ throw new IllegalArgumentException("multi-resolution configurations must not be empty");
+ }
+
+ mConfigurations = configurations;
+
+ // For each multi-resolution stream configuration, track how many formats and sizes there
+ // are available to configure
+ for (Map.Entry<String, StreamConfiguration[]> entry :
+ mConfigurations.entrySet()) {
+ String cameraId = entry.getKey();
+ StreamConfiguration[] configs = entry.getValue();
+
+ for (int i = 0; i < configs.length; i++) {
+ StreamConfiguration config = configs[i];
+ int format = config.getFormat();
+
+ MultiResolutionStreamInfo multiResolutionStreamInfo = new MultiResolutionStreamInfo(
+ config.getWidth(), config.getHeight(), cameraId);
+ Map<Integer, List<MultiResolutionStreamInfo>> destMap;
+ if (config.isInput()) {
+ destMap = mMultiResolutionInputConfigs;
+ } else {
+ destMap = mMultiResolutionOutputConfigs;
+ }
+
+ if (!destMap.containsKey(format)) {
+ List<MultiResolutionStreamInfo> multiResolutionStreamInfoList =
+ new ArrayList<MultiResolutionStreamInfo>();
+ destMap.put(format, multiResolutionStreamInfoList);
+ }
+ destMap.get(format).add(multiResolutionStreamInfo);
+ }
+ }
+ }
+
+ /**
+ * Size comparator that compares the number of pixels two MultiResolutionStreamInfo size covers.
+ *
+ * <p>If two the areas of two sizes are same, compare the widths.</p>
+ *
+ * @hide
+ */
+ public static class SizeComparator implements Comparator<MultiResolutionStreamInfo> {
+ @Override
+ public int compare(@NonNull MultiResolutionStreamInfo lhs,
+ @NonNull MultiResolutionStreamInfo rhs) {
+ return StreamConfigurationMap.compareSizes(
+ lhs.getWidth(), lhs.getHeight(), rhs.getWidth(), rhs.getHeight());
+ }
+ }
+
+ /**
+ * Get the output formats in this multi-resolution stream configuration.
+ *
+ * <p>A logical multi-camera or an ultra high resolution sensor camera may support
+ * {@link android.hardware.camera2.MultiResolutionImageReader} to dynamically output maximum
+ * resolutions of different sizes (when switching between physical cameras, or between different
+ * modes of an ultra high resolution sensor camera). This function returns the formats
+ * supported for such case.</p>
+ *
+ * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
+ * or in {@link PixelFormat} (and there is no possibility of collision).</p>
+ *
+ * @return an array of integer format, or empty array if multi-resolution output is not
+ * supported
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ * @see android.hardware.camera2.MultiResolutionImageReader
+ */
+ public @NonNull @Format int[] getOutputFormats() {
+ return getPublicImageFormats(/*output*/true);
+ }
+
+ /**
+ * Get the input formats in this multi-resolution stream configuration.
+ *
+ * <p>A logical multi-camera or ultra high resolution sensor camera may support reprocessing
+ * images of different resolutions when switching between physical cameras, or between
+ * different modes of the ultra high resolution sensor camera. This function returns the
+ * formats supported for such case.</p>
+ *
+ * <p>The supported output format for an input format can be queried by calling the camera
+ * device's {@link StreamConfigurationMap#getValidOutputFormatsForInput}.</p>
+ *
+ * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
+ * or in {@link PixelFormat} (and there is no possibility of collision).</p>
+ *
+ * @return an array of integer format, or empty array if no multi-resolution reprocessing is
+ * supported
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ */
+ public @NonNull @Format int[] getInputFormats() {
+ return getPublicImageFormats(/*output*/false);
+ }
+
+ // Get the list of publicly visible multi-resolution input/output stream formats
+ private int[] getPublicImageFormats(boolean output) {
+ Map<Integer, List<MultiResolutionStreamInfo>> multiResolutionConfigs =
+ output ? mMultiResolutionOutputConfigs : mMultiResolutionInputConfigs;
+ int formatCount = multiResolutionConfigs.size();
+
+ int[] formats = new int[formatCount];
+ int i = 0;
+ for (Integer format : multiResolutionConfigs.keySet()) {
+ formats[i++] = StreamConfigurationMap.imageFormatToPublic(format);
+ }
+
+ return formats;
+ }
+
+ /**
+ * Get a group of {@code MultiResolutionStreamInfo} with the requested output image
+ * {@code format}
+ *
+ * <p>The {@code format} should be a supported format (one of the formats returned by
+ * {@link #getOutputFormats}).</p>
+ *
+ * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+ * @return
+ * a group of supported {@link MultiResolutionStreamInfo}. If the {@code format} is not
+ * a supported multi-resolution output, an empty group is returned.
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ * @see #getOutputFormats
+ */
+ public @NonNull Collection<MultiResolutionStreamInfo> getOutputInfo(@Format int format) {
+ return getInfo(format, /*false*/ true);
+ }
+
+ /**
+ * Get a group of {@code MultiResolutionStreamInfo} with the requested input image {@code format}
+ *
+ * <p>The {@code format} should be a supported format (one of the formats returned by
+ * {@link #getInputFormats}).</p>
+ *
+ * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+ * @return
+ * a group of supported {@link MultiResolutionStreamInfo}. If the {@code format} is not
+ * a supported multi-resolution input, an empty group is returned.
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ * @see #getInputFormats
+ */
+ public @NonNull Collection<MultiResolutionStreamInfo> getInputInfo(@Format int format) {
+ return getInfo(format, /*false*/ false);
+ }
+
+ // Get multi-resolution stream info for a particular format
+ private @NonNull Collection<MultiResolutionStreamInfo> getInfo(int format, boolean output) {
+ int internalFormat = StreamConfigurationMap.imageFormatToInternal(format);
+ Map<Integer, List<MultiResolutionStreamInfo>> multiResolutionConfigs =
+ output ? mMultiResolutionOutputConfigs : mMultiResolutionInputConfigs;
+ if (multiResolutionConfigs.containsKey(internalFormat)) {
+ return Collections.unmodifiableCollection(multiResolutionConfigs.get(internalFormat));
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ private void appendConfigurationsString(StringBuilder sb, boolean output) {
+ sb.append(output ? "Outputs(" : "Inputs(");
+ int[] formats = getPublicImageFormats(output);
+ if (formats != null) {
+ for (int format : formats) {
+ Collection<MultiResolutionStreamInfo> streamInfoList =
+ getInfo(format, output);
+ sb.append("[" + StreamConfigurationMap.formatToString(format) + ":");
+ for (MultiResolutionStreamInfo streamInfo : streamInfoList) {
+ sb.append(String.format("[w:%d, h:%d, id:%s], ",
+ streamInfo.getWidth(), streamInfo.getHeight(),
+ streamInfo.getPhysicalCameraId()));
+ }
+ // Remove the pending ", "
+ if (sb.charAt(sb.length() - 1) == ' ') {
+ sb.delete(sb.length() - 2, sb.length());
+ }
+ sb.append("]");
+ }
+ }
+ sb.append(")");
+ }
+
+ /**
+ * Check if this {@link MultiResolutionStreamConfigurationMap} is equal to another
+ * {@link MultiResolutionStreamConfigurationMap}.
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof MultiResolutionStreamConfigurationMap) {
+ final MultiResolutionStreamConfigurationMap other =
+ (MultiResolutionStreamConfigurationMap) obj;
+ if (!mConfigurations.keySet().equals(other.mConfigurations.keySet())) {
+ return false;
+ }
+
+ for (String id : mConfigurations.keySet()) {
+ if (!Arrays.equals(mConfigurations.get(id), other.mConfigurations.get(id))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return HashCodeHelpers.hashCodeGeneric(
+ mConfigurations, mMultiResolutionOutputConfigs, mMultiResolutionInputConfigs);
+ }
+
+ /**
+ * Return this {@link MultiResolutionStreamConfigurationMap} as a string representation.
+ *
+ * <p>{@code "MultiResolutionStreamConfigurationMap(Outputs([format1: [w:%d, h:%d, id:%s], ...
+ * ... [w:%d, h:%d, id:%s]), [format2: [w:%d, h:%d, id:%s], ... [w:%d, h:%d, id:%s]], ...),
+ * Inputs([format1: [w:%d, h:%d, id:%s], ... [w:%d, h:%d, id:%s], ...).</p>
+ *
+ * @return string representation of {@link MultiResolutionStreamConfigurationMap}
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("MultiResolutionStreamConfigurationMap(");
+ appendConfigurationsString(sb, /*output*/ true);
+ sb.append(",");
+ appendConfigurationsString(sb, /*output*/ false);
+ sb.append(")");
+
+ return sb.toString();
+ }
+
+
+ private final Map<String, StreamConfiguration[]> mConfigurations;
+
+ /** Format -> list of MultiResolutionStreamInfo used to create MultiResolutionImageReader */
+ private final Map<Integer, List<MultiResolutionStreamInfo>> mMultiResolutionOutputConfigs
+ = new HashMap<Integer, List<MultiResolutionStreamInfo>>();
+ /** Format -> list of MultiResolutionStreamInfo used for multi-resolution reprocessing */
+ private final Map<Integer, List<MultiResolutionStreamInfo>> mMultiResolutionInputConfigs
+ = new HashMap<Integer, List<MultiResolutionStreamInfo>>();
+}
diff --git a/core/java/android/hardware/camera2/params/MultiResolutionStreamInfo.java b/core/java/android/hardware/camera2/params/MultiResolutionStreamInfo.java
new file mode 100644
index 0000000..aa1d1d4
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/MultiResolutionStreamInfo.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2021 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 android.hardware.camera2.params;
+
+import android.annotation.NonNull;
+
+import java.util.Objects;
+
+/**
+ * A utility class describing the properties of one stream of fixed-size image buffers
+ * backing a multi-resolution image stream.
+ *
+ * <p>A group of {@link MultiResolutionStreamInfo} are used to describe the properties of a
+ * multi-resolution image stream for a particular format. The
+ * {@link android.hardware.camera2.MultiResolutionImageReader} class represents a
+ * multi-resolution output stream, and is constructed using a group of
+ * {@link MultiResolutionStreamInfo}. A group of {@link MultiResolutionStreamInfo} can also be used
+ * to create a multi-resolution reprocessable camera capture session. See
+ * {@link android.hardware.camera2.params.InputConfiguration} for details.</p>
+ *
+ * @see InputConfiguration
+ * @see android.hardware.camera2.MultiResolutionImageReader
+ */
+public class MultiResolutionStreamInfo {
+ private int mStreamWidth;
+ private int mStreamHeight;
+ private String mPhysicalCameraId;
+
+ /**
+ * Create a new {@link MultiResolutionStreamInfo}.
+ *
+ * <p>This class creates a {@link MultiResolutionStreamInfo} using image width, image height,
+ * and the physical camera Id images originate from.</p>
+ *
+ * <p>Normally applications do not need to create these directly. Use {@link
+ * MultiResolutionStreamConfigurationMap#getOutputInfo} or {@link
+ * MultiResolutionStreamConfigurationMap#getInputInfo} to obtain them for a particular format
+ * instead.</p>
+ */
+ public MultiResolutionStreamInfo(int streamWidth, int streamHeight,
+ @NonNull String physicalCameraId) {
+ mStreamWidth = streamWidth;
+ mStreamHeight = streamHeight;
+ mPhysicalCameraId = physicalCameraId;
+ }
+
+ /**
+ * The width of this particular image buffer stream in pixels.
+ */
+ public int getWidth() {
+ return mStreamWidth;
+ }
+
+ /**
+ * The height of this particular image buffer stream in pixels.
+ */
+ public int getHeight() {
+ return mStreamHeight;
+ }
+
+ /**
+ * The physical camera Id of this particular image buffer stream.
+ */
+ public @NonNull String getPhysicalCameraId() {
+ return mPhysicalCameraId;
+ }
+
+ /**
+ * Check if this {@link MultiResolutionStreamInfo} is equal to another
+ * {@link MultiResolutionStreamInfo}.
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof MultiResolutionStreamInfo) {
+ final MultiResolutionStreamInfo other = (MultiResolutionStreamInfo) obj;
+ return mStreamWidth == other.mStreamWidth &&
+ mStreamHeight == other.mStreamHeight &&
+ mPhysicalCameraId.equals(other.mPhysicalCameraId);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mStreamWidth, mStreamHeight, mPhysicalCameraId);
+ }
+}
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index a20a1bf..e31bd60 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -24,9 +24,13 @@
import android.annotation.SystemApi;
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.MultiResolutionImageReader;
+import android.hardware.camera2.params.MultiResolutionStreamInfo;
import android.hardware.camera2.utils.HashCodeHelpers;
import android.hardware.camera2.utils.SurfaceUtils;
+import android.media.ImageReader;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -34,6 +38,7 @@
import android.view.Surface;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -81,6 +86,13 @@
* {@link CameraCaptureSession#updateOutputConfiguration} can be called after the configuration
* finalize method returns without exceptions.</li>
*
+ * <li>If the camera device supports multi-resolution output streams, {@link
+ * CameraCharacteristics#SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP} will contain the
+ * formats and their corresponding stream info. The application can use an OutputConfiguration
+ * created with the multi-resolution stream info queried from {@link
+ * MultiResolutionStreamConfigurationMap#getOutputInfo} and
+ * {@link android.hardware.camera2.MultiResolutionImageReader} to capture variable size images.
+ *
* </ul>
*
* <p> As of {@link android.os.Build.VERSION_CODES#P Android P}, all formats except
@@ -88,6 +100,7 @@
* device support. On prior API levels, only {@link ImageFormat#PRIVATE} format may be used.</p>
*
* @see CameraDevice#createCaptureSessionByOutputConfigurations
+ * @see CameraCharacteristics#SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP
*
*/
public final class OutputConfiguration implements Parcelable {
@@ -206,6 +219,33 @@
}
/**
+ * Set the multi-resolution output flag.
+ *
+ * <p>Specify that this OutputConfiguration is part of a multi-resolution output stream group
+ * used by {@link android.hardware.camera2.MultiResolutionImageReader}.</p>
+ *
+ * <p>This function must only be called for an OutputConfiguration with a non-negative
+ * group ID. And all OutputConfigurations of a MultiResolutionImageReader will have the same
+ * group ID and have this flag set.</p>
+ *
+ * @throws IllegalStateException If surface sharing is enabled via {@link #enableSurfaceSharing}
+ * call, or no non-negative group ID has been set.
+ * @hide
+ */
+ void setMultiResolutionOutput() {
+ if (mIsShared) {
+ throw new IllegalStateException("Multi-resolution output flag must not be set for " +
+ "configuration with surface sharing");
+ }
+ if (mSurfaceGroupId == SURFACE_GROUP_ID_NONE) {
+ throw new IllegalStateException("Multi-resolution output flag should only be set for " +
+ "surface with non-negative group ID");
+ }
+
+ mIsMultiResolution = true;
+ }
+
+ /**
* Create a new {@link OutputConfiguration} instance.
*
* <p>This constructor takes an argument for desired camera rotation</p>
@@ -265,6 +305,45 @@
mIsDeferredConfig = false;
mIsShared = false;
mPhysicalCameraId = null;
+ mIsMultiResolution = false;
+ }
+
+ /**
+ * Create a list of {@link OutputConfiguration} instances for the outputs used by a
+ * {@link android.hardware.camera2.MultiResolutionImageReader}.
+ *
+ * <p>This constructor takes an argument for a
+ * {@link android.hardware.camera2.MultiResolutionImageReader}.</p>
+ *
+ * @param multiResolutionImageReader
+ * The multi-resolution image reader object.
+ */
+ public static @NonNull Collection<OutputConfiguration> createInstancesForMultiResolutionOutput(
+ @NonNull MultiResolutionImageReader multiResolutionImageReader) {
+ checkNotNull(multiResolutionImageReader, "Multi-resolution image reader must not be null");
+
+ int groupId = MULTI_RESOLUTION_GROUP_ID_COUNTER;
+ MULTI_RESOLUTION_GROUP_ID_COUNTER++;
+ // Skip in case the group id counter overflows to -1, the invalid value.
+ if (MULTI_RESOLUTION_GROUP_ID_COUNTER == -1) {
+ MULTI_RESOLUTION_GROUP_ID_COUNTER++;
+ }
+
+ ImageReader[] imageReaders = multiResolutionImageReader.getReaders();
+ ArrayList<OutputConfiguration> configs = new ArrayList<OutputConfiguration>();
+ for (int i = 0; i < imageReaders.length; i++) {
+ MultiResolutionStreamInfo streamInfo =
+ multiResolutionImageReader.getStreamInfoForImageReader(imageReaders[i]);
+
+ OutputConfiguration config = new OutputConfiguration(
+ groupId, imageReaders[i].getSurface());
+ config.setPhysicalCameraId(streamInfo.getPhysicalCameraId());
+ config.setMultiResolutionOutput();
+ configs.add(config);
+ // TODO: Set sensor pixel mode for ultra high resolution sensor camera.
+ }
+
+ return configs;
}
/**
@@ -319,6 +398,7 @@
mIsDeferredConfig = true;
mIsShared = false;
mPhysicalCameraId = null;
+ mIsMultiResolution = false;
}
/**
@@ -355,8 +435,18 @@
* <p>Up to {@link #getMaxSharedSurfaceCount} surfaces can be shared for an OutputConfiguration.
* The supported surfaces for sharing must be of type SurfaceTexture, SurfaceView,
* MediaRecorder, MediaCodec, or implementation defined ImageReader.</p>
+ *
+ * <p>This function must not be called from OuptutConfigurations created by {@link
+ * #createInstancesForMultiResolutionOutput}.</p>
+ *
+ * @throws IllegalStateException If this OutputConfiguration is created via {@link
+ * #createInstancesForMultiResolutionOutput} to back a MultiResolutionImageReader.
*/
public void enableSurfaceSharing() {
+ if (mIsMultiResolution) {
+ throw new IllegalStateException("Cannot enable surface sharing on "
+ + "multi-resolution output configurations");
+ }
mIsShared = true;
}
@@ -368,8 +458,7 @@
* This call achieves it by mapping the OutputConfiguration to the physical camera id.</p>
*
* <p>The valid physical camera ids can be queried by {@link
- * android.hardware.camera2.CameraCharacteristics#getPhysicalCameraIds}.
- * </p>
+ * CameraCharacteristics#getPhysicalCameraIds}.</p>
*
* <p>Passing in a null physicalCameraId means that the OutputConfiguration is for a logical
* stream.</p>
@@ -380,8 +469,16 @@
* after {@link CameraDevice#createCaptureSessionByOutputConfigurations} or {@link
* CameraDevice#createReprocessableCaptureSessionByConfigurations} has no effect.</p>
*
- * <p>The surface belonging to a physical camera OutputConfiguration must not be used as input
- * or output of a reprocessing request. </p>
+ * <p>As of {@link android.os.Build.VERSION_CODES#S Android 12}, an image buffer from a
+ * physical camera stream can be used for reprocessing to logical camera streams and streams
+ * from the same physical camera if the camera device supports multi-resolution input and output
+ * streams. See {@link CameraCharacteristics#SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP}
+ * for details. The behaviors of reprocessing from a non-physical camera stream to a physical
+ * camera stream, and from a physical camera stream to a physical camera stream of different
+ * physical camera, are device-specific and not guaranteed to be supported.</p>
+ *
+ * <p>On prior API levels, the surface belonging to a physical camera OutputConfiguration must
+ * not be used as input or output of a reprocessing request. </p>
*/
public void setPhysicalCameraId(@Nullable String physicalCameraId) {
mPhysicalCameraId = physicalCameraId;
@@ -527,6 +624,7 @@
this.mIsDeferredConfig = other.mIsDeferredConfig;
this.mIsShared = other.mIsShared;
this.mPhysicalCameraId = other.mPhysicalCameraId;
+ this.mIsMultiResolution = other.mIsMultiResolution;
}
/**
@@ -543,6 +641,7 @@
ArrayList<Surface> surfaces = new ArrayList<Surface>();
source.readTypedList(surfaces, Surface.CREATOR);
String physicalCameraId = source.readString();
+ boolean isMultiResolutionOutput = source.readInt() == 1;
checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
@@ -566,6 +665,7 @@
mConfiguredGenerationId = 0;
}
mPhysicalCameraId = physicalCameraId;
+ mIsMultiResolution = isMultiResolutionOutput;
}
/**
@@ -665,6 +765,7 @@
dest.writeInt(mIsShared ? 1 : 0);
dest.writeTypedList(mSurfaces);
dest.writeString(mPhysicalCameraId);
+ dest.writeInt(mIsMultiResolution ? 1 : 0);
}
/**
@@ -694,7 +795,8 @@
mConfiguredFormat != other.mConfiguredFormat ||
mConfiguredDataspace != other.mConfiguredDataspace ||
mConfiguredGenerationId != other.mConfiguredGenerationId ||
- !Objects.equals(mPhysicalCameraId, other.mPhysicalCameraId))
+ !Objects.equals(mPhysicalCameraId, other.mPhysicalCameraId) ||
+ mIsMultiResolution != other.mIsMultiResolution)
return false;
int minLen = Math.min(mSurfaces.size(), other.mSurfaces.size());
@@ -720,17 +822,24 @@
return HashCodeHelpers.hashCode(
mRotation, mConfiguredSize.hashCode(), mConfiguredFormat, mConfiguredDataspace,
mSurfaceGroupId, mSurfaceType, mIsShared ? 1 : 0,
- mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode());
+ mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(),
+ mIsMultiResolution ? 1 : 0);
}
return HashCodeHelpers.hashCode(
mRotation, mSurfaces.hashCode(), mConfiguredGenerationId,
mConfiguredSize.hashCode(), mConfiguredFormat,
mConfiguredDataspace, mSurfaceGroupId, mIsShared ? 1 : 0,
- mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode());
+ mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(),
+ mIsMultiResolution ? 1 : 0);
}
private static final String TAG = "OutputConfiguration";
+
+ // A surfaceGroupId counter used for MultiResolutionImageReader. Its value is
+ // incremented everytime {@link createInstancesForMultiResolutionOutput} is called.
+ private static int MULTI_RESOLUTION_GROUP_ID_COUNTER = 0;
+
private ArrayList<Surface> mSurfaces;
private final int mRotation;
private final int mSurfaceGroupId;
@@ -749,4 +858,7 @@
private boolean mIsShared;
// The physical camera id that this output configuration is for.
private String mPhysicalCameraId;
+ // Flag indicating if this config is for a multi-resolution output with a
+ // MultiResolutionImageReader
+ private boolean mIsMultiResolution;
}
diff --git a/core/java/android/hardware/camera2/params/SessionConfiguration.java b/core/java/android/hardware/camera2/params/SessionConfiguration.java
index 8fc919f..ea6b92d 100644
--- a/core/java/android/hardware/camera2/params/SessionConfiguration.java
+++ b/core/java/android/hardware/camera2/params/SessionConfiguration.java
@@ -130,11 +130,13 @@
int inputWidth = source.readInt();
int inputHeight = source.readInt();
int inputFormat = source.readInt();
+ boolean isInputMultiResolution = source.readBoolean();
ArrayList<OutputConfiguration> outConfigs = new ArrayList<OutputConfiguration>();
source.readTypedList(outConfigs, OutputConfiguration.CREATOR);
if ((inputWidth > 0) && (inputHeight > 0) && (inputFormat != -1)) {
- mInputConfig = new InputConfiguration(inputWidth, inputHeight, inputFormat);
+ mInputConfig = new InputConfiguration(inputWidth, inputHeight,
+ inputFormat, isInputMultiResolution);
}
mSessionType = sessionType;
mOutputConfigurations = outConfigs;
@@ -169,10 +171,12 @@
dest.writeInt(mInputConfig.getWidth());
dest.writeInt(mInputConfig.getHeight());
dest.writeInt(mInputConfig.getFormat());
+ dest.writeBoolean(mInputConfig.isMultiResolution());
} else {
dest.writeInt(/*inputWidth*/ 0);
dest.writeInt(/*inputHeight*/ 0);
dest.writeInt(/*inputFormat*/ -1);
+ dest.writeBoolean(/*isMultiResolution*/ false);
}
dest.writeTypedList(mOutputConfigurations);
}
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index 10a814a..a25ae60 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -1575,7 +1575,7 @@
return sizes;
}
- /** Get the list of publically visible output formats; does not include IMPL_DEFINED */
+ /** Get the list of publicly visible output formats */
private int[] getPublicFormats(boolean output) {
int[] formats = new int[getPublicFormatCount(output)];
@@ -1746,6 +1746,21 @@
return sb.toString();
}
+ /**
+ * Size comparison method used by size comparators.
+ *
+ * @hide
+ */
+ public static int compareSizes(int widthA, int heightA, int widthB, int heightB) {
+ long left = widthA * (long) heightA;
+ long right = widthB * (long) heightB;
+ if (left == right) {
+ left = widthA;
+ right = widthB;
+ }
+ return (left < right) ? -1 : (left > right ? 1 : 0);
+ }
+
private void appendOutputsString(StringBuilder sb) {
sb.append("Outputs(");
int[] formats = getOutputFormats();
@@ -1843,7 +1858,10 @@
sb.append(")");
}
- private String formatToString(int format) {
+ /**
+ * @hide
+ */
+ public static String formatToString(int format) {
switch (format) {
case ImageFormat.YV12:
return "YV12";
diff --git a/core/java/android/hardware/lights/LightsRequest.java b/core/java/android/hardware/lights/LightsRequest.java
index 2626a46..6fb0eb5 100644
--- a/core/java/android/hardware/lights/LightsRequest.java
+++ b/core/java/android/hardware/lights/LightsRequest.java
@@ -17,6 +17,7 @@
package android.hardware.lights;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.util.SparseArray;
import com.android.internal.util.Preconditions;
@@ -94,6 +95,20 @@
}
/**
+ * Overrides the color and intensity of a given light.
+ *
+ * @param light the light to modify
+ * @param state the desired color and intensity of the light *
+ * @deprecated Use {@link #addLight(Light, LightState)} instead.
+ * @hide
+ */
+ @SystemApi
+ @Deprecated
+ public @NonNull Builder setLight(@NonNull Light light, @NonNull LightState state) {
+ return addLight(light, state);
+ }
+
+ /**
* Removes the override for the color and intensity of a given light.
*
* @param light the light to modify
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index b016ed6..9bf791b 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -19,8 +19,6 @@
import android.net.INetworkPolicyListener;
import android.net.Network;
import android.net.NetworkPolicy;
-import android.net.NetworkQuotaInfo;
-import android.net.NetworkState;
import android.net.NetworkTemplate;
import android.telephony.SubscriptionPlan;
@@ -70,9 +68,6 @@
int getMultipathPreference(in Network network);
- @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
- NetworkQuotaInfo getNetworkQuotaInfo(in NetworkState state);
-
SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage);
void setSubscriptionPlans(int subId, in SubscriptionPlan[] plans, String callingPackage);
String getSubscriptionPlansOwner(int subId);
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index 268002f..8f1e2de 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -232,10 +232,11 @@
ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA512, SDK_VERSION_ZERO);
ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_AES_GCM, SDK_VERSION_ZERO);
- ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.S);
- ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.S);
- ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.S);
- ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.S);
+ // STOPSHIP: b/170424293 Use Build.VERSION_CODES.S when it is defined
+ ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.R + 1);
+ ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.R + 1);
+ ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.R + 1);
+ ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.R + 1);
}
private static final Set<String> ENABLED_ALGOS =
diff --git a/core/java/android/net/NetworkStateSnapshot.java b/core/java/android/net/NetworkStateSnapshot.java
index b3d8d4e..0d26c2d 100644
--- a/core/java/android/net/NetworkStateSnapshot.java
+++ b/core/java/android/net/NetworkStateSnapshot.java
@@ -24,6 +24,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.net.module.util.NetworkIdentityUtils;
+
import java.util.Objects;
/**
@@ -124,4 +126,15 @@
public int hashCode() {
return Objects.hash(network, networkCapabilities, linkProperties, subscriberId, legacyType);
}
+
+ @Override
+ public String toString() {
+ return "NetworkStateSnapshot{"
+ + "network=" + network
+ + ", networkCapabilities=" + networkCapabilities
+ + ", linkProperties=" + linkProperties
+ + ", subscriberId='" + NetworkIdentityUtils.scrubSubscriberId(subscriberId) + '\''
+ + ", legacyType=" + legacyType
+ + '}';
+ }
}
diff --git a/core/java/android/net/vcn/IVcnStatusCallback.aidl b/core/java/android/net/vcn/IVcnStatusCallback.aidl
index d91cef5..236ae8b 100644
--- a/core/java/android/net/vcn/IVcnStatusCallback.aidl
+++ b/core/java/android/net/vcn/IVcnStatusCallback.aidl
@@ -18,7 +18,6 @@
/** @hide */
oneway interface IVcnStatusCallback {
- void onEnteredSafeMode();
void onVcnStatusChanged(int statusCode);
void onGatewayConnectionError(
in int[] gatewayNetworkCapabilities,
diff --git a/core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl b/core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl
index f8ae492..62de821 100644
--- a/core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl
+++ b/core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl
@@ -17,6 +17,6 @@
package android.net.vcn;
/** @hide */
-interface IVcnUnderlyingNetworkPolicyListener {
+oneway interface IVcnUnderlyingNetworkPolicyListener {
void onPolicyChanged();
}
\ No newline at end of file
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index eb8c251..8ebf757 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -359,8 +359,6 @@
/**
* Value indicating that the VCN for the subscription group is not configured, or that the
* callback is not privileged for the subscription group.
- *
- * @hide
*/
public static final int VCN_STATUS_CODE_NOT_CONFIGURED = 0;
@@ -369,8 +367,6 @@
*
* <p>A VCN is inactive if a {@link VcnConfig} is present for the subscription group, but the
* provisioning package is not privileged.
- *
- * @hide
*/
public static final int VCN_STATUS_CODE_INACTIVE = 1;
@@ -380,8 +376,6 @@
* <p>A VCN is active if a {@link VcnConfig} is present for the subscription, the provisioning
* package is privileged, and the VCN is not in Safe Mode. In other words, a VCN is considered
* active while it is connecting, fully connected, and disconnecting.
- *
- * @hide
*/
public static final int VCN_STATUS_CODE_ACTIVE = 2;
@@ -391,8 +385,6 @@
* <p>A VCN will be put into Safe Mode if any of the gateway connections were unable to
* establish a connection within a system-determined timeout (while underlying networks were
* available).
- *
- * @hide
*/
public static final int VCN_STATUS_CODE_SAFE_MODE = 3;
@@ -407,8 +399,6 @@
/**
* Value indicating that an internal failure occurred in this Gateway Connection.
- *
- * @hide
*/
public static final int VCN_ERROR_CODE_INTERNAL_ERROR = 0;
@@ -416,8 +406,6 @@
* Value indicating that an error with this Gateway Connection's configuration occurred.
*
* <p>For example, this error code will be returned after authentication failures.
- *
- * @hide
*/
public static final int VCN_ERROR_CODE_CONFIG_ERROR = 1;
@@ -427,38 +415,19 @@
* <p>For example, this error code will be returned if an underlying {@link android.net.Network}
* for this Gateway Connection is lost, or if an error occurs while resolving the connection
* endpoint address.
- *
- * @hide
*/
public static final int VCN_ERROR_CODE_NETWORK_ERROR = 2;
- // TODO: make VcnStatusCallback @SystemApi
/**
* VcnStatusCallback is the interface for Carrier apps to receive updates for their VCNs.
*
* <p>VcnStatusCallbacks may be registered before {@link VcnConfig}s are provided for a
* subscription group.
- *
- * @hide
*/
public abstract static class VcnStatusCallback {
private VcnStatusCallbackBinder mCbBinder;
/**
- * Invoked when the VCN for this Callback's subscription group enters safe mode.
- *
- * <p>A VCN will be put into safe mode if any of the gateway connections were unable to
- * establish a connection within a system-determined timeout (while underlying networks were
- * available).
- *
- * <p>A VCN-configuring app may opt to exit safe mode by (re)setting the VCN configuration
- * via {@link #setVcnConfig(ParcelUuid, VcnConfig)}.
- *
- * @hide
- */
- public void onEnteredSafeMode() {}
-
- /**
* Invoked when status of the VCN for this callback's subscription group changes.
*
* @param statusCode the code for the status change encountered by this {@link
@@ -467,15 +436,16 @@
public abstract void onVcnStatusChanged(@VcnStatusCode int statusCode);
/**
- * Invoked when a VCN Gateway Connection corresponding to this callback's subscription
+ * Invoked when a VCN Gateway Connection corresponding to this callback's subscription group
* encounters an error.
*
- * @param networkCapabilities an array of underlying NetworkCapabilities for the Gateway
- * Connection that encountered the error for identification purposes. These will be a
- * sorted list with no duplicates, matching one of the {@link
+ * @param networkCapabilities an array of NetworkCapabilities.NET_CAPABILITY_* capabilities
+ * for the Gateway Connection that encountered the error, for identification purposes.
+ * These will be a sorted list with no duplicates and will match {@link
+ * VcnGatewayConnectionConfig#getRequiredUnderlyingCapabilities()} for one of the {@link
* VcnGatewayConnectionConfig}s set in the {@link VcnConfig} for this subscription
* group.
- * @param errorCode {@link VcnErrorCode} to indicate the error that occurred
+ * @param errorCode the code to indicate the error that occurred
* @param detail Throwable to provide additional information about the error, or {@code
* null} if none
*/
@@ -496,6 +466,10 @@
* <p>A {@link VcnStatusCallback} will only be invoked if the registering package has carrier
* privileges for the specified subscription at the time of invocation.
*
+ * <p>A {@link VcnStatusCallback} is eligible to begin receiving callbacks once it is registered
+ * and there is a VCN active for its specified subscription group (this may happen after the
+ * callback is registered).
+ *
* <p>{@link VcnStatusCallback#onVcnStatusChanged(int)} will be invoked on registration with the
* current status for the specified subscription group's VCN. If the registrant is not
* privileged for this subscription group, {@link #VCN_STATUS_CODE_NOT_CONFIGURED} will be
@@ -505,7 +479,6 @@
* @param executor The {@link Executor} to be used for invoking callbacks
* @param callback The VcnStatusCallback to be registered
* @throws IllegalStateException if callback is currently registered with VcnManager
- * @hide
*/
public void registerVcnStatusCallback(
@NonNull ParcelUuid subscriptionGroup,
@@ -538,7 +511,6 @@
* was registered with.
*
* @param callback The callback to be unregistered
- * @hide
*/
public void unregisterVcnStatusCallback(@NonNull VcnStatusCallback callback) {
requireNonNull(callback, "callback must not be null");
@@ -599,12 +571,6 @@
}
@Override
- public void onEnteredSafeMode() {
- Binder.withCleanCallingIdentity(
- () -> mExecutor.execute(() -> mCallback.onEnteredSafeMode()));
- }
-
- @Override
public void onVcnStatusChanged(@VcnStatusCode int statusCode) {
Binder.withCleanCallingIdentity(
() -> mExecutor.execute(() -> mCallback.onVcnStatusChanged(statusCode)));
diff --git a/core/java/android/net/vcn/persistablebundleutils/CertUtils.java b/core/java/android/net/vcn/persistablebundleutils/CertUtils.java
new file mode 100644
index 0000000..b6036b4
--- /dev/null
+++ b/core/java/android/net/vcn/persistablebundleutils/CertUtils.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 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 android.net.vcn.persistablebundleutils;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Objects;
+
+/**
+ * CertUtils provides utility methods for constructing Certificate.
+ *
+ * @hide
+ */
+public class CertUtils {
+ private static final String CERT_TYPE_X509 = "X.509";
+
+ /** Decodes an ASN.1 DER encoded Certificate */
+ public static X509Certificate certificateFromByteArray(byte[] derEncoded) {
+ Objects.requireNonNull(derEncoded, "derEncoded is null");
+
+ try {
+ CertificateFactory certFactory = CertificateFactory.getInstance(CERT_TYPE_X509);
+ InputStream in = new ByteArrayInputStream(derEncoded);
+ return (X509Certificate) certFactory.generateCertificate(in);
+ } catch (CertificateException e) {
+ throw new IllegalArgumentException("Fail to decode certificate", e);
+ }
+ }
+}
diff --git a/core/java/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java b/core/java/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java
new file mode 100644
index 0000000..ce5ec75
--- /dev/null
+++ b/core/java/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2021 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 android.net.vcn.persistablebundleutils;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import android.annotation.NonNull;
+import android.net.ipsec.ike.ChildSaProposal;
+import android.os.PersistableBundle;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Provides utility methods to convert ChildSaProposal to/from PersistableBundle.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = Visibility.PRIVATE)
+public final class ChildSaProposalUtils extends SaProposalUtilsBase {
+ /** Serializes a ChildSaProposal to a PersistableBundle. */
+ @NonNull
+ public static PersistableBundle toPersistableBundle(ChildSaProposal proposal) {
+ return SaProposalUtilsBase.toPersistableBundle(proposal);
+ }
+
+ /** Constructs a ChildSaProposal by deserializing a PersistableBundle. */
+ @NonNull
+ public static ChildSaProposal fromPersistableBundle(@NonNull PersistableBundle in) {
+ Objects.requireNonNull(in, "PersistableBundle was null");
+
+ final ChildSaProposal.Builder builder = new ChildSaProposal.Builder();
+
+ final PersistableBundle encryptionBundle = in.getPersistableBundle(ENCRYPT_ALGO_KEY);
+ Objects.requireNonNull(encryptionBundle, "Encryption algo bundle was null");
+ final List<EncryptionAlgoKeyLenPair> encryptList =
+ PersistableBundleUtils.toList(encryptionBundle, EncryptionAlgoKeyLenPair::new);
+ for (EncryptionAlgoKeyLenPair t : encryptList) {
+ builder.addEncryptionAlgorithm(t.encryptionAlgo, t.keyLen);
+ }
+
+ final int[] integrityAlgoIdArray = in.getIntArray(INTEGRITY_ALGO_KEY);
+ Objects.requireNonNull(integrityAlgoIdArray, "Integrity algo array was null");
+ for (int algo : integrityAlgoIdArray) {
+ builder.addIntegrityAlgorithm(algo);
+ }
+
+ final int[] dhGroupArray = in.getIntArray(DH_GROUP_KEY);
+ Objects.requireNonNull(dhGroupArray, "DH Group array was null");
+ for (int dh : dhGroupArray) {
+ builder.addDhGroup(dh);
+ }
+
+ return builder.build();
+ }
+}
diff --git a/core/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java b/core/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java
new file mode 100644
index 0000000..853a52d
--- /dev/null
+++ b/core/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2021 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 android.net.vcn.persistablebundleutils;
+
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import android.annotation.NonNull;
+import android.net.eap.EapSessionConfig;
+import android.net.eap.EapSessionConfig.EapAkaConfig;
+import android.net.eap.EapSessionConfig.EapAkaPrimeConfig;
+import android.net.eap.EapSessionConfig.EapMethodConfig;
+import android.net.eap.EapSessionConfig.EapMsChapV2Config;
+import android.net.eap.EapSessionConfig.EapSimConfig;
+import android.net.eap.EapSessionConfig.EapTtlsConfig;
+import android.net.eap.EapSessionConfig.EapUiccConfig;
+import android.os.PersistableBundle;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.Objects;
+
+/**
+ * Provides utility methods to convert EapSessionConfig to/from PersistableBundle.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = Visibility.PRIVATE)
+public final class EapSessionConfigUtils {
+ private static final String EAP_ID_KEY = "EAP_ID_KEY";
+ private static final String EAP_SIM_CONFIG_KEY = "EAP_SIM_CONFIG_KEY";
+ private static final String EAP_TTLS_CONFIG_KEY = "EAP_TTLS_CONFIG_KEY";
+ private static final String EAP_AKA_CONFIG_KEY = "EAP_AKA_CONFIG_KEY";
+ private static final String EAP_MSCHAP_V2_CONFIG_KEY = "EAP_MSCHAP_V2_CONFIG_KEY";
+ private static final String EAP_AKA_PRIME_CONFIG_KEY = "EAP_AKA_PRIME_CONFIG_KEY";
+
+ /** Serializes an EapSessionConfig to a PersistableBundle. */
+ @NonNull
+ public static PersistableBundle toPersistableBundle(@NonNull EapSessionConfig config) {
+ final PersistableBundle result = new PersistableBundle();
+
+ result.putPersistableBundle(
+ EAP_ID_KEY, PersistableBundleUtils.fromByteArray(config.getEapIdentity()));
+
+ if (config.getEapSimConfig() != null) {
+ result.putPersistableBundle(
+ EAP_SIM_CONFIG_KEY,
+ EapSimConfigUtils.toPersistableBundle(config.getEapSimConfig()));
+ }
+
+ if (config.getEapTtlsConfig() != null) {
+ result.putPersistableBundle(
+ EAP_TTLS_CONFIG_KEY,
+ EapTtlsConfigUtils.toPersistableBundle(config.getEapTtlsConfig()));
+ }
+
+ if (config.getEapAkaConfig() != null) {
+ result.putPersistableBundle(
+ EAP_AKA_CONFIG_KEY,
+ EapAkaConfigUtils.toPersistableBundle(config.getEapAkaConfig()));
+ }
+
+ if (config.getEapMsChapV2Config() != null) {
+ result.putPersistableBundle(
+ EAP_MSCHAP_V2_CONFIG_KEY,
+ EapMsChapV2ConfigUtils.toPersistableBundle(config.getEapMsChapV2Config()));
+ }
+
+ if (config.getEapAkaPrimeConfig() != null) {
+ result.putPersistableBundle(
+ EAP_AKA_PRIME_CONFIG_KEY,
+ EapAkaPrimeConfigUtils.toPersistableBundle(config.getEapAkaPrimeConfig()));
+ }
+
+ return result;
+ }
+
+ /** Constructs an EapSessionConfig by deserializing a PersistableBundle. */
+ @NonNull
+ public static EapSessionConfig fromPersistableBundle(@NonNull PersistableBundle in) {
+ Objects.requireNonNull(in, "PersistableBundle was null");
+
+ final EapSessionConfig.Builder builder = new EapSessionConfig.Builder();
+
+ final PersistableBundle eapIdBundle = in.getPersistableBundle(EAP_ID_KEY);
+ Objects.requireNonNull(eapIdBundle, "EAP ID was null");
+ builder.setEapIdentity(PersistableBundleUtils.toByteArray(eapIdBundle));
+
+ final PersistableBundle simBundle = in.getPersistableBundle(EAP_SIM_CONFIG_KEY);
+ if (simBundle != null) {
+ EapSimConfigUtils.setBuilderByReadingPersistableBundle(simBundle, builder);
+ }
+
+ final PersistableBundle ttlsBundle = in.getPersistableBundle(EAP_TTLS_CONFIG_KEY);
+ if (ttlsBundle != null) {
+ EapTtlsConfigUtils.setBuilderByReadingPersistableBundle(ttlsBundle, builder);
+ }
+
+ final PersistableBundle akaBundle = in.getPersistableBundle(EAP_AKA_CONFIG_KEY);
+ if (akaBundle != null) {
+ EapAkaConfigUtils.setBuilderByReadingPersistableBundle(akaBundle, builder);
+ }
+
+ final PersistableBundle msChapV2Bundle = in.getPersistableBundle(EAP_MSCHAP_V2_CONFIG_KEY);
+ if (msChapV2Bundle != null) {
+ EapMsChapV2ConfigUtils.setBuilderByReadingPersistableBundle(msChapV2Bundle, builder);
+ }
+
+ final PersistableBundle akaPrimeBundle = in.getPersistableBundle(EAP_AKA_PRIME_CONFIG_KEY);
+ if (akaPrimeBundle != null) {
+ EapAkaPrimeConfigUtils.setBuilderByReadingPersistableBundle(akaPrimeBundle, builder);
+ }
+
+ return builder.build();
+ }
+
+ private static class EapMethodConfigUtils {
+ private static final String METHOD_TYPE = "METHOD_TYPE";
+
+ /** Serializes an EapMethodConfig to a PersistableBundle. */
+ @NonNull
+ public static PersistableBundle toPersistableBundle(@NonNull EapMethodConfig config) {
+ final PersistableBundle result = new PersistableBundle();
+ result.putInt(METHOD_TYPE, config.getMethodType());
+ return result;
+ }
+ }
+
+ private static class EapUiccConfigUtils extends EapMethodConfigUtils {
+ static final String SUB_ID_KEY = "SUB_ID_KEY";
+ static final String APP_TYPE_KEY = "APP_TYPE_KEY";
+
+ @NonNull
+ protected static PersistableBundle toPersistableBundle(@NonNull EapUiccConfig config) {
+ final PersistableBundle result = EapMethodConfigUtils.toPersistableBundle(config);
+ result.putInt(SUB_ID_KEY, config.getSubId());
+ result.putInt(APP_TYPE_KEY, config.getAppType());
+
+ return result;
+ }
+ }
+
+ private static final class EapSimConfigUtils extends EapUiccConfigUtils {
+ @NonNull
+ public static PersistableBundle toPersistableBundle(EapSimConfig config) {
+ return EapUiccConfigUtils.toPersistableBundle(config);
+ }
+
+ public static void setBuilderByReadingPersistableBundle(
+ @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) {
+ Objects.requireNonNull(in, "PersistableBundle was null");
+ builder.setEapSimConfig(in.getInt(SUB_ID_KEY), in.getInt(APP_TYPE_KEY));
+ }
+ }
+
+ private static class EapAkaConfigUtils extends EapUiccConfigUtils {
+ @NonNull
+ public static PersistableBundle toPersistableBundle(@NonNull EapAkaConfig config) {
+ return EapUiccConfigUtils.toPersistableBundle(config);
+ }
+
+ public static void setBuilderByReadingPersistableBundle(
+ @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) {
+ Objects.requireNonNull(in, "PersistableBundle was null");
+ builder.setEapAkaConfig(in.getInt(SUB_ID_KEY), in.getInt(APP_TYPE_KEY));
+ }
+ }
+
+ private static final class EapAkaPrimeConfigUtils extends EapAkaConfigUtils {
+ private static final String NETWORK_NAME_KEY = "NETWORK_NAME_KEY";
+ private static final String ALL_MISMATCHED_NETWORK_KEY = "ALL_MISMATCHED_NETWORK_KEY";
+
+ @NonNull
+ public static PersistableBundle toPersistableBundle(@NonNull EapAkaPrimeConfig config) {
+ final PersistableBundle result = EapUiccConfigUtils.toPersistableBundle(config);
+ result.putString(NETWORK_NAME_KEY, config.getNetworkName());
+ result.putBoolean(ALL_MISMATCHED_NETWORK_KEY, config.allowsMismatchedNetworkNames());
+
+ return result;
+ }
+
+ public static void setBuilderByReadingPersistableBundle(
+ @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) {
+ Objects.requireNonNull(in, "PersistableBundle was null");
+ builder.setEapAkaPrimeConfig(
+ in.getInt(SUB_ID_KEY),
+ in.getInt(APP_TYPE_KEY),
+ in.getString(NETWORK_NAME_KEY),
+ in.getBoolean(ALL_MISMATCHED_NETWORK_KEY));
+ }
+ }
+
+ private static final class EapMsChapV2ConfigUtils extends EapMethodConfigUtils {
+ private static final String USERNAME_KEY = "USERNAME_KEY";
+ private static final String PASSWORD_KEY = "PASSWORD_KEY";
+
+ @NonNull
+ public static PersistableBundle toPersistableBundle(@NonNull EapMsChapV2Config config) {
+ final PersistableBundle result = EapMethodConfigUtils.toPersistableBundle(config);
+ result.putString(USERNAME_KEY, config.getUsername());
+ result.putString(PASSWORD_KEY, config.getPassword());
+
+ return result;
+ }
+
+ public static void setBuilderByReadingPersistableBundle(
+ @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) {
+ Objects.requireNonNull(in, "PersistableBundle was null");
+ builder.setEapMsChapV2Config(in.getString(USERNAME_KEY), in.getString(PASSWORD_KEY));
+ }
+ }
+
+ private static final class EapTtlsConfigUtils extends EapMethodConfigUtils {
+ private static final String TRUST_CERT_KEY = "TRUST_CERT_KEY";
+ private static final String EAP_SESSION_CONFIG_KEY = "EAP_SESSION_CONFIG_KEY";
+
+ @NonNull
+ public static PersistableBundle toPersistableBundle(@NonNull EapTtlsConfig config) {
+ final PersistableBundle result = EapMethodConfigUtils.toPersistableBundle(config);
+ try {
+ if (config.getServerCaCert() != null) {
+ final PersistableBundle caBundle =
+ PersistableBundleUtils.fromByteArray(
+ config.getServerCaCert().getEncoded());
+ result.putPersistableBundle(TRUST_CERT_KEY, caBundle);
+ }
+ } catch (CertificateEncodingException e) {
+ throw new IllegalStateException("Fail to encode the certificate");
+ }
+
+ result.putPersistableBundle(
+ EAP_SESSION_CONFIG_KEY,
+ EapSessionConfigUtils.toPersistableBundle(config.getInnerEapSessionConfig()));
+
+ return result;
+ }
+
+ public static void setBuilderByReadingPersistableBundle(
+ @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) {
+ Objects.requireNonNull(in, "PersistableBundle was null");
+
+ final PersistableBundle caBundle = in.getPersistableBundle(TRUST_CERT_KEY);
+ X509Certificate caCert = null;
+ if (caBundle != null) {
+ caCert =
+ CertUtils.certificateFromByteArray(
+ PersistableBundleUtils.toByteArray(caBundle));
+ }
+
+ final PersistableBundle eapSessionConfigBundle =
+ in.getPersistableBundle(EAP_SESSION_CONFIG_KEY);
+ Objects.requireNonNull(eapSessionConfigBundle, "Inner EAP Session Config was null");
+ final EapSessionConfig eapSessionConfig =
+ EapSessionConfigUtils.fromPersistableBundle(eapSessionConfigBundle);
+
+ builder.setEapTtlsConfig(caCert, eapSessionConfig);
+ }
+ }
+}
diff --git a/core/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java b/core/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java
new file mode 100644
index 0000000..6acb34e
--- /dev/null
+++ b/core/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2021 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 android.net.vcn.persistablebundleutils;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import android.annotation.NonNull;
+import android.net.InetAddresses;
+import android.net.ipsec.ike.IkeDerAsn1DnIdentification;
+import android.net.ipsec.ike.IkeFqdnIdentification;
+import android.net.ipsec.ike.IkeIdentification;
+import android.net.ipsec.ike.IkeIpv4AddrIdentification;
+import android.net.ipsec.ike.IkeIpv6AddrIdentification;
+import android.net.ipsec.ike.IkeKeyIdIdentification;
+import android.net.ipsec.ike.IkeRfc822AddrIdentification;
+import android.os.PersistableBundle;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.util.Objects;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * Abstract utility class to convert IkeIdentification to/from PersistableBundle.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = Visibility.PRIVATE)
+public final class IkeIdentificationUtils {
+ private static final String ID_TYPE_KEY = "ID_TYPE_KEY";
+
+ private static final String DER_ASN1_DN_KEY = "DER_ASN1_DN_KEY";
+ private static final String FQDN_KEY = "FQDN_KEY";
+ private static final String KEY_ID_KEY = "KEY_ID_KEY";
+ private static final String IP4_ADDRESS_KEY = "IP4_ADDRESS_KEY";
+ private static final String IP6_ADDRESS_KEY = "IP6_ADDRESS_KEY";
+ private static final String RFC822_ADDRESS_KEY = "RFC822_ADDRESS_KEY";
+
+ private static final int ID_TYPE_DER_ASN1_DN = 1;
+ private static final int ID_TYPE_FQDN = 2;
+ private static final int ID_TYPE_IPV4_ADDR = 3;
+ private static final int ID_TYPE_IPV6_ADDR = 4;
+ private static final int ID_TYPE_KEY_ID = 5;
+ private static final int ID_TYPE_RFC822_ADDR = 6;
+
+ /** Serializes an IkeIdentification to a PersistableBundle. */
+ @NonNull
+ public static PersistableBundle toPersistableBundle(@NonNull IkeIdentification ikeId) {
+ if (ikeId instanceof IkeDerAsn1DnIdentification) {
+ final PersistableBundle result = createPersistableBundle(ID_TYPE_DER_ASN1_DN);
+ IkeDerAsn1DnIdentification id = (IkeDerAsn1DnIdentification) ikeId;
+ result.putPersistableBundle(
+ DER_ASN1_DN_KEY,
+ PersistableBundleUtils.fromByteArray(id.derAsn1Dn.getEncoded()));
+ return result;
+ } else if (ikeId instanceof IkeFqdnIdentification) {
+ final PersistableBundle result = createPersistableBundle(ID_TYPE_FQDN);
+ IkeFqdnIdentification id = (IkeFqdnIdentification) ikeId;
+ result.putString(FQDN_KEY, id.fqdn);
+ return result;
+ } else if (ikeId instanceof IkeIpv4AddrIdentification) {
+ final PersistableBundle result = createPersistableBundle(ID_TYPE_IPV4_ADDR);
+ IkeIpv4AddrIdentification id = (IkeIpv4AddrIdentification) ikeId;
+ result.putString(IP4_ADDRESS_KEY, id.ipv4Address.getHostAddress());
+ return result;
+ } else if (ikeId instanceof IkeIpv6AddrIdentification) {
+ final PersistableBundle result = createPersistableBundle(ID_TYPE_IPV6_ADDR);
+ IkeIpv6AddrIdentification id = (IkeIpv6AddrIdentification) ikeId;
+ result.putString(IP6_ADDRESS_KEY, id.ipv6Address.getHostAddress());
+ return result;
+ } else if (ikeId instanceof IkeKeyIdIdentification) {
+ final PersistableBundle result = createPersistableBundle(ID_TYPE_KEY_ID);
+ IkeKeyIdIdentification id = (IkeKeyIdIdentification) ikeId;
+ result.putPersistableBundle(KEY_ID_KEY, PersistableBundleUtils.fromByteArray(id.keyId));
+ return result;
+ } else if (ikeId instanceof IkeRfc822AddrIdentification) {
+ final PersistableBundle result = createPersistableBundle(ID_TYPE_RFC822_ADDR);
+ IkeRfc822AddrIdentification id = (IkeRfc822AddrIdentification) ikeId;
+ result.putString(RFC822_ADDRESS_KEY, id.rfc822Name);
+ return result;
+ } else {
+ throw new IllegalStateException("Unrecognized IkeIdentification subclass");
+ }
+ }
+
+ private static PersistableBundle createPersistableBundle(int idType) {
+ final PersistableBundle result = new PersistableBundle();
+ result.putInt(ID_TYPE_KEY, idType);
+ return result;
+ }
+
+ /** Constructs an IkeIdentification by deserializing a PersistableBundle. */
+ @NonNull
+ public static IkeIdentification fromPersistableBundle(@NonNull PersistableBundle in) {
+ Objects.requireNonNull(in, "PersistableBundle was null");
+ int idType = in.getInt(ID_TYPE_KEY);
+ switch (idType) {
+ case ID_TYPE_DER_ASN1_DN:
+ final PersistableBundle dnBundle = in.getPersistableBundle(DER_ASN1_DN_KEY);
+ Objects.requireNonNull(dnBundle, "ASN1 DN was null");
+ return new IkeDerAsn1DnIdentification(
+ new X500Principal(PersistableBundleUtils.toByteArray(dnBundle)));
+ case ID_TYPE_FQDN:
+ return new IkeFqdnIdentification(in.getString(FQDN_KEY));
+ case ID_TYPE_IPV4_ADDR:
+ final String v4AddressStr = in.getString(IP4_ADDRESS_KEY);
+ Objects.requireNonNull(v4AddressStr, "IPv4 address was null");
+ return new IkeIpv4AddrIdentification(
+ (Inet4Address) InetAddresses.parseNumericAddress(v4AddressStr));
+ case ID_TYPE_IPV6_ADDR:
+ final String v6AddressStr = in.getString(IP6_ADDRESS_KEY);
+ Objects.requireNonNull(v6AddressStr, "IPv6 address was null");
+ return new IkeIpv6AddrIdentification(
+ (Inet6Address) InetAddresses.parseNumericAddress(v6AddressStr));
+ case ID_TYPE_KEY_ID:
+ final PersistableBundle keyIdBundle = in.getPersistableBundle(KEY_ID_KEY);
+ Objects.requireNonNull(in, "Key ID was null");
+ return new IkeKeyIdIdentification(PersistableBundleUtils.toByteArray(keyIdBundle));
+ case ID_TYPE_RFC822_ADDR:
+ return new IkeRfc822AddrIdentification(in.getString(RFC822_ADDRESS_KEY));
+ default:
+ throw new IllegalStateException("Unrecognized IKE ID type: " + idType);
+ }
+ }
+}
diff --git a/core/java/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java b/core/java/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java
new file mode 100644
index 0000000..1459671
--- /dev/null
+++ b/core/java/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2021 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 android.net.vcn.persistablebundleutils;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import android.annotation.NonNull;
+import android.net.ipsec.ike.IkeSaProposal;
+import android.os.PersistableBundle;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Provides utility methods to convert IkeSaProposal to/from PersistableBundle.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = Visibility.PRIVATE)
+public final class IkeSaProposalUtils extends SaProposalUtilsBase {
+ private static final String PRF_KEY = "PRF_KEY";
+
+ /** Serializes an IkeSaProposal to a PersistableBundle. */
+ @NonNull
+ public static PersistableBundle toPersistableBundle(IkeSaProposal proposal) {
+ final PersistableBundle result = SaProposalUtilsBase.toPersistableBundle(proposal);
+
+ final int[] prfArray =
+ proposal.getPseudorandomFunctions().stream().mapToInt(i -> i).toArray();
+ result.putIntArray(PRF_KEY, prfArray);
+
+ return result;
+ }
+
+ /** Constructs an IkeSaProposal by deserializing a PersistableBundle. */
+ @NonNull
+ public static IkeSaProposal fromPersistableBundle(@NonNull PersistableBundle in) {
+ Objects.requireNonNull(in, "PersistableBundle was null");
+
+ final IkeSaProposal.Builder builder = new IkeSaProposal.Builder();
+
+ final PersistableBundle encryptionBundle = in.getPersistableBundle(ENCRYPT_ALGO_KEY);
+ Objects.requireNonNull(encryptionBundle, "Encryption algo bundle was null");
+ final List<EncryptionAlgoKeyLenPair> encryptList =
+ PersistableBundleUtils.toList(encryptionBundle, EncryptionAlgoKeyLenPair::new);
+ for (EncryptionAlgoKeyLenPair t : encryptList) {
+ builder.addEncryptionAlgorithm(t.encryptionAlgo, t.keyLen);
+ }
+
+ final int[] integrityAlgoIdArray = in.getIntArray(INTEGRITY_ALGO_KEY);
+ Objects.requireNonNull(integrityAlgoIdArray, "Integrity algo array was null");
+ for (int algo : integrityAlgoIdArray) {
+ builder.addIntegrityAlgorithm(algo);
+ }
+
+ final int[] dhGroupArray = in.getIntArray(DH_GROUP_KEY);
+ Objects.requireNonNull(dhGroupArray, "DH Group array was null");
+ for (int dh : dhGroupArray) {
+ builder.addDhGroup(dh);
+ }
+
+ final int[] prfArray = in.getIntArray(PRF_KEY);
+ Objects.requireNonNull(prfArray, "PRF array was null");
+ for (int prf : prfArray) {
+ builder.addPseudorandomFunction(prf);
+ }
+
+ return builder.build();
+ }
+}
diff --git a/core/java/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java b/core/java/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java
new file mode 100644
index 0000000..0c9ee84
--- /dev/null
+++ b/core/java/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2021 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 android.net.vcn.persistablebundleutils;
+
+import android.annotation.NonNull;
+import android.net.ipsec.ike.SaProposal;
+import android.os.PersistableBundle;
+import android.util.Pair;
+
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Abstract utility class to convert SaProposal to/from PersistableBundle.
+ *
+ * @hide
+ */
+abstract class SaProposalUtilsBase {
+ static final String ENCRYPT_ALGO_KEY = "ENCRYPT_ALGO_KEY";
+ static final String INTEGRITY_ALGO_KEY = "INTEGRITY_ALGO_KEY";
+ static final String DH_GROUP_KEY = "DH_GROUP_KEY";
+
+ static class EncryptionAlgoKeyLenPair {
+ private static final String ALGO_KEY = "ALGO_KEY";
+ private static final String KEY_LEN_KEY = "KEY_LEN_KEY";
+
+ public final int encryptionAlgo;
+ public final int keyLen;
+
+ EncryptionAlgoKeyLenPair(int encryptionAlgo, int keyLen) {
+ this.encryptionAlgo = encryptionAlgo;
+ this.keyLen = keyLen;
+ }
+
+ EncryptionAlgoKeyLenPair(PersistableBundle in) {
+ Objects.requireNonNull(in, "PersistableBundle was null");
+
+ this.encryptionAlgo = in.getInt(ALGO_KEY);
+ this.keyLen = in.getInt(KEY_LEN_KEY);
+ }
+
+ public PersistableBundle toPersistableBundle() {
+ final PersistableBundle result = new PersistableBundle();
+
+ result.putInt(ALGO_KEY, encryptionAlgo);
+ result.putInt(KEY_LEN_KEY, keyLen);
+
+ return result;
+ }
+ }
+
+ /**
+ * Serializes common info of a SaProposal to a PersistableBundle.
+ *
+ * @hide
+ */
+ @NonNull
+ static PersistableBundle toPersistableBundle(SaProposal proposal) {
+ final PersistableBundle result = new PersistableBundle();
+
+ final List<EncryptionAlgoKeyLenPair> encryptAlgoKeyLenPairs = new ArrayList<>();
+ for (Pair<Integer, Integer> pair : proposal.getEncryptionAlgorithms()) {
+ encryptAlgoKeyLenPairs.add(new EncryptionAlgoKeyLenPair(pair.first, pair.second));
+ }
+ final PersistableBundle encryptionBundle =
+ PersistableBundleUtils.fromList(
+ encryptAlgoKeyLenPairs, EncryptionAlgoKeyLenPair::toPersistableBundle);
+ result.putPersistableBundle(ENCRYPT_ALGO_KEY, encryptionBundle);
+
+ final int[] integrityAlgoIdArray =
+ proposal.getIntegrityAlgorithms().stream().mapToInt(i -> i).toArray();
+ result.putIntArray(INTEGRITY_ALGO_KEY, integrityAlgoIdArray);
+
+ final int[] dhGroupArray = proposal.getDhGroups().stream().mapToInt(i -> i).toArray();
+ result.putIntArray(DH_GROUP_KEY, dhGroupArray);
+
+ return result;
+ }
+}
diff --git a/core/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java b/core/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java
new file mode 100644
index 0000000..e62acac
--- /dev/null
+++ b/core/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2021 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 android.net.vcn.persistablebundleutils;
+
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.InetAddresses;
+import android.net.ipsec.ike.ChildSaProposal;
+import android.net.ipsec.ike.IkeTrafficSelector;
+import android.net.ipsec.ike.TunnelModeChildSessionParams;
+import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Address;
+import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer;
+import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer;
+import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Netmask;
+import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6Address;
+import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer;
+import android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest;
+import android.os.PersistableBundle;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Provides utility methods to convert TunnelModeChildSessionParams to/from PersistableBundle.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = Visibility.PRIVATE)
+public final class TunnelModeChildSessionParamsUtils {
+ private static final String TAG = TunnelModeChildSessionParamsUtils.class.getSimpleName();
+
+ private static final String INBOUND_TS_KEY = "INBOUND_TS_KEY";
+ private static final String OUTBOUND_TS_KEY = "OUTBOUND_TS_KEY";
+ private static final String SA_PROPOSALS_KEY = "SA_PROPOSALS_KEY";
+ private static final String HARD_LIFETIME_SEC_KEY = "HARD_LIFETIME_SEC_KEY";
+ private static final String SOFT_LIFETIME_SEC_KEY = "SOFT_LIFETIME_SEC_KEY";
+ private static final String CONFIG_REQUESTS_KEY = "CONFIG_REQUESTS_KEY";
+
+ private static class ConfigRequest {
+ private static final int TYPE_IPV4_ADDRESS = 1;
+ private static final int TYPE_IPV6_ADDRESS = 2;
+ private static final int TYPE_IPV4_DNS = 3;
+ private static final int TYPE_IPV6_DNS = 4;
+ private static final int TYPE_IPV4_DHCP = 5;
+ private static final int TYPE_IPV4_NETMASK = 6;
+
+ private static final String TYPE_KEY = "type";
+ private static final String VALUE_KEY = "address";
+ private static final String IP6_PREFIX_LEN = "ip6PrefixLen";
+
+ private static final int PREFIX_LEN_UNUSED = -1;
+
+ public final int type;
+ public final int ip6PrefixLen;
+
+ // Null when it is an empty request
+ @Nullable public final InetAddress address;
+
+ ConfigRequest(TunnelModeChildConfigRequest config) {
+ int prefixLen = PREFIX_LEN_UNUSED;
+
+ if (config instanceof ConfigRequestIpv4Address) {
+ type = TYPE_IPV4_ADDRESS;
+ address = ((ConfigRequestIpv4Address) config).getAddress();
+ } else if (config instanceof ConfigRequestIpv6Address) {
+ type = TYPE_IPV6_ADDRESS;
+ address = ((ConfigRequestIpv6Address) config).getAddress();
+ if (address != null) {
+ prefixLen = ((ConfigRequestIpv6Address) config).getPrefixLength();
+ }
+ } else if (config instanceof ConfigRequestIpv4DnsServer) {
+ type = TYPE_IPV4_DNS;
+ address = null;
+ } else if (config instanceof ConfigRequestIpv6DnsServer) {
+ type = TYPE_IPV6_DNS;
+ address = null;
+ } else if (config instanceof ConfigRequestIpv4DhcpServer) {
+ type = TYPE_IPV4_DHCP;
+ address = null;
+ } else if (config instanceof ConfigRequestIpv4Netmask) {
+ type = TYPE_IPV4_NETMASK;
+ address = null;
+ } else {
+ throw new IllegalStateException("Unknown TunnelModeChildConfigRequest");
+ }
+
+ ip6PrefixLen = prefixLen;
+ }
+
+ ConfigRequest(PersistableBundle in) {
+ Objects.requireNonNull(in, "PersistableBundle was null");
+
+ type = in.getInt(TYPE_KEY);
+ ip6PrefixLen = in.getInt(IP6_PREFIX_LEN);
+
+ String addressStr = in.getString(VALUE_KEY);
+ if (addressStr == null) {
+ address = null;
+ } else {
+ address = InetAddresses.parseNumericAddress(addressStr);
+ }
+ }
+
+ @NonNull
+ public PersistableBundle toPersistableBundle() {
+ final PersistableBundle result = new PersistableBundle();
+
+ result.putInt(TYPE_KEY, type);
+ result.putInt(IP6_PREFIX_LEN, ip6PrefixLen);
+
+ if (address != null) {
+ result.putString(VALUE_KEY, address.getHostAddress());
+ }
+
+ return result;
+ }
+ }
+
+ /** Serializes a TunnelModeChildSessionParams to a PersistableBundle. */
+ @NonNull
+ public static PersistableBundle toPersistableBundle(
+ @NonNull TunnelModeChildSessionParams params) {
+ final PersistableBundle result = new PersistableBundle();
+
+ final PersistableBundle saProposalBundle =
+ PersistableBundleUtils.fromList(
+ params.getSaProposals(), ChildSaProposalUtils::toPersistableBundle);
+ result.putPersistableBundle(SA_PROPOSALS_KEY, saProposalBundle);
+
+ final PersistableBundle inTsBundle =
+ PersistableBundleUtils.fromList(
+ params.getInboundTrafficSelectors(),
+ IkeTrafficSelectorUtils::toPersistableBundle);
+ result.putPersistableBundle(INBOUND_TS_KEY, inTsBundle);
+
+ final PersistableBundle outTsBundle =
+ PersistableBundleUtils.fromList(
+ params.getOutboundTrafficSelectors(),
+ IkeTrafficSelectorUtils::toPersistableBundle);
+ result.putPersistableBundle(OUTBOUND_TS_KEY, outTsBundle);
+
+ result.putInt(HARD_LIFETIME_SEC_KEY, params.getHardLifetimeSeconds());
+ result.putInt(SOFT_LIFETIME_SEC_KEY, params.getSoftLifetimeSeconds());
+
+ final List<ConfigRequest> reqList = new ArrayList<>();
+ for (TunnelModeChildConfigRequest req : params.getConfigurationRequests()) {
+ reqList.add(new ConfigRequest(req));
+ }
+ final PersistableBundle configReqListBundle =
+ PersistableBundleUtils.fromList(reqList, ConfigRequest::toPersistableBundle);
+ result.putPersistableBundle(CONFIG_REQUESTS_KEY, configReqListBundle);
+
+ return result;
+ }
+
+ private static List<IkeTrafficSelector> getTsFromPersistableBundle(
+ PersistableBundle in, String key) {
+ PersistableBundle tsBundle = in.getPersistableBundle(key);
+ Objects.requireNonNull(tsBundle, "Value for key " + key + " was null");
+ return PersistableBundleUtils.toList(
+ tsBundle, IkeTrafficSelectorUtils::fromPersistableBundle);
+ }
+
+ /** Constructs a TunnelModeChildSessionParams by deserializing a PersistableBundle. */
+ @NonNull
+ public static TunnelModeChildSessionParams fromPersistableBundle(
+ @NonNull PersistableBundle in) {
+ Objects.requireNonNull(in, "PersistableBundle was null");
+
+ final TunnelModeChildSessionParams.Builder builder =
+ new TunnelModeChildSessionParams.Builder();
+
+ final PersistableBundle proposalBundle = in.getPersistableBundle(SA_PROPOSALS_KEY);
+ Objects.requireNonNull(proposalBundle, "SA proposal was null");
+ final List<ChildSaProposal> proposals =
+ PersistableBundleUtils.toList(
+ proposalBundle, ChildSaProposalUtils::fromPersistableBundle);
+ for (ChildSaProposal p : proposals) {
+ builder.addSaProposal(p);
+ }
+
+ for (IkeTrafficSelector ts : getTsFromPersistableBundle(in, INBOUND_TS_KEY)) {
+ builder.addInboundTrafficSelectors(ts);
+ }
+
+ for (IkeTrafficSelector ts : getTsFromPersistableBundle(in, OUTBOUND_TS_KEY)) {
+ builder.addOutboundTrafficSelectors(ts);
+ }
+
+ builder.setLifetimeSeconds(
+ in.getInt(HARD_LIFETIME_SEC_KEY), in.getInt(SOFT_LIFETIME_SEC_KEY));
+ final PersistableBundle configReqListBundle = in.getPersistableBundle(CONFIG_REQUESTS_KEY);
+ Objects.requireNonNull(configReqListBundle, "Config request list was null");
+ final List<ConfigRequest> reqList =
+ PersistableBundleUtils.toList(configReqListBundle, ConfigRequest::new);
+
+ boolean hasIpv4AddressReq = false;
+ boolean hasIpv4NetmaskReq = false;
+ for (ConfigRequest req : reqList) {
+ switch (req.type) {
+ case ConfigRequest.TYPE_IPV4_ADDRESS:
+ hasIpv4AddressReq = true;
+ if (req.address == null) {
+ builder.addInternalAddressRequest(AF_INET);
+ } else {
+ builder.addInternalAddressRequest((Inet4Address) req.address);
+ }
+ break;
+ case ConfigRequest.TYPE_IPV6_ADDRESS:
+ if (req.address == null) {
+ builder.addInternalAddressRequest(AF_INET6);
+ } else {
+ builder.addInternalAddressRequest(
+ (Inet6Address) req.address, req.ip6PrefixLen);
+ }
+ break;
+ case ConfigRequest.TYPE_IPV4_NETMASK:
+ // Do not need to set netmask because it will be automatically set by the
+ // builder when an IPv4 internal address request is set.
+ hasIpv4NetmaskReq = true;
+ break;
+ case ConfigRequest.TYPE_IPV4_DNS:
+ if (req.address != null) {
+ Log.w(TAG, "Requesting a specific IPv4 DNS server is unsupported");
+ }
+ builder.addInternalDnsServerRequest(AF_INET);
+ break;
+ case ConfigRequest.TYPE_IPV6_DNS:
+ if (req.address != null) {
+ Log.w(TAG, "Requesting a specific IPv6 DNS server is unsupported");
+ }
+ builder.addInternalDnsServerRequest(AF_INET6);
+ break;
+ case ConfigRequest.TYPE_IPV4_DHCP:
+ if (req.address != null) {
+ Log.w(TAG, "Requesting a specific IPv4 DHCP server is unsupported");
+ }
+ builder.addInternalDhcpServerRequest(AF_INET);
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Unrecognized config request type: " + req.type);
+ }
+ }
+
+ if (hasIpv4AddressReq != hasIpv4NetmaskReq) {
+ Log.w(
+ TAG,
+ String.format(
+ "Expect IPv4 address request and IPv4 netmask request either both"
+ + " exist or both absent, but found hasIpv4AddressReq exists? %b,"
+ + " hasIpv4AddressReq exists? %b, ",
+ hasIpv4AddressReq, hasIpv4NetmaskReq));
+ }
+
+ return builder.build();
+ }
+}
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index de7b885..f12eb88 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -37,6 +37,8 @@
private final long mStatsStartRealtimeMs;
private final double mDischargedPowerLowerBound;
private final double mDischargedPowerUpperBound;
+ private final long mBatteryTimeRemainingMs;
+ private final long mChargeTimeRemainingMs;
private final ArrayList<UidBatteryConsumer> mUidBatteryConsumers;
private final ArrayList<SystemBatteryConsumer> mSystemBatteryConsumers;
private final ArrayList<UserBatteryConsumer> mUserBatteryConsumers;
@@ -50,6 +52,8 @@
mDischargedPowerUpperBound = builder.mDischargedPowerUpperBoundMah;
mHistoryBuffer = builder.mHistoryBuffer;
mHistoryTagPool = builder.mHistoryTagPool;
+ mBatteryTimeRemainingMs = builder.mBatteryTimeRemainingMs;
+ mChargeTimeRemainingMs = builder.mChargeTimeRemainingMs;
double totalPower = 0;
@@ -110,6 +114,25 @@
}
/**
+ * Returns an approximation for how much run time (in milliseconds) is remaining on
+ * the battery. Returns -1 if no time can be computed: either there is not
+ * enough current data to make a decision, or the battery is currently
+ * charging.
+ */
+ public long getBatteryTimeRemainingMs() {
+ return mBatteryTimeRemainingMs;
+ }
+
+ /**
+ * Returns an approximation for how much time (in milliseconds) remains until the battery
+ * is fully charged. Returns -1 if no time can be computed: either there is not
+ * enough current data to make a decision, or the battery is currently discharging.
+ */
+ public long getChargeTimeRemainingMs() {
+ return mChargeTimeRemainingMs;
+ }
+
+ /**
* Total amount of battery charge drained since BatteryStats reset (e.g. due to being fully
* charged), in mAh
*/
@@ -156,6 +179,8 @@
mDischargePercentage = source.readInt();
mDischargedPowerLowerBound = source.readDouble();
mDischargedPowerUpperBound = source.readDouble();
+ mBatteryTimeRemainingMs = source.readLong();
+ mChargeTimeRemainingMs = source.readLong();
mUidBatteryConsumers = new ArrayList<>();
source.readParcelableList(mUidBatteryConsumers, getClass().getClassLoader());
mSystemBatteryConsumers = new ArrayList<>();
@@ -194,6 +219,8 @@
dest.writeInt(mDischargePercentage);
dest.writeDouble(mDischargedPowerLowerBound);
dest.writeDouble(mDischargedPowerUpperBound);
+ dest.writeLong(mBatteryTimeRemainingMs);
+ dest.writeLong(mChargeTimeRemainingMs);
dest.writeParcelableList(mUidBatteryConsumers, flags);
dest.writeParcelableList(mSystemBatteryConsumers, flags);
dest.writeParcelableList(mUserBatteryConsumers, flags);
@@ -237,6 +264,8 @@
private int mDischargePercentage;
private double mDischargedPowerLowerBoundMah;
private double mDischargedPowerUpperBoundMah;
+ private long mBatteryTimeRemainingMs = -1;
+ private long mChargeTimeRemainingMs = -1;
private final SparseArray<UidBatteryConsumer.Builder> mUidBatteryConsumerBuilders =
new SparseArray<>();
private final SparseArray<SystemBatteryConsumer.Builder> mSystemBatteryConsumerBuilders =
@@ -289,6 +318,26 @@
}
/**
+ * Sets an approximation for how much time (in milliseconds) remains until the battery
+ * is fully discharged.
+ */
+ @NonNull
+ public Builder setBatteryTimeRemainingMs(long batteryTimeRemainingMs) {
+ mBatteryTimeRemainingMs = batteryTimeRemainingMs;
+ return this;
+ }
+
+ /**
+ * Sets an approximation for how much time (in milliseconds) remains until the battery
+ * is fully charged.
+ */
+ @NonNull
+ public Builder setChargeTimeRemainingMs(long chargeTimeRemainingMs) {
+ mChargeTimeRemainingMs = chargeTimeRemainingMs;
+ return this;
+ }
+
+ /**
* Sets the parceled recent history.
*/
@NonNull
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 74df1b2..a5b0e8d 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1288,10 +1288,12 @@
public static final String HOST = getString("ro.build.host");
/**
- * Returns true if we are running a debug build such as "user-debug" or "eng".
- * @hide
+ * Returns true if the device is running a debuggable build such as "userdebug" or "eng".
+ *
+ * Debuggable builds allow users to gain root access via local shell, attach debuggers to any
+ * application regardless of whether they have the "debuggable" attribute set, or downgrade
+ * selinux into "permissive" mode in particular.
*/
- @UnsupportedAppUsage
public static final boolean IS_DEBUGGABLE =
SystemProperties.getInt("ro.debuggable", 0) == 1;
diff --git a/core/java/android/os/BytesMatcher.java b/core/java/android/os/BytesMatcher.java
new file mode 100644
index 0000000..8537f47
--- /dev/null
+++ b/core/java/android/os/BytesMatcher.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2021 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 android.os;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothUuid;
+import android.net.MacAddress;
+import android.util.Log;
+
+import com.android.internal.util.HexDump;
+
+import java.util.ArrayList;
+import java.util.function.Predicate;
+
+/**
+ * Predicate that tests if a given {@code byte[]} value matches a set of
+ * configured rules.
+ * <p>
+ * Rules are tested in the order in which they were originally added, which
+ * means a narrow rule can reject a specific value before a later broader rule
+ * might accept that same value, or vice versa.
+ * <p>
+ * Matchers can contain rules of varying lengths, and tested values will only be
+ * matched against rules of the exact same length. This is designed to support
+ * {@link BluetoothUuid} style values which can be variable length.
+ *
+ * @hide
+ */
+public class BytesMatcher implements Predicate<byte[]> {
+ private static final String TAG = "BytesMatcher";
+
+ private static final char TYPE_ACCEPT = '+';
+ private static final char TYPE_REJECT = '-';
+
+ private final ArrayList<Rule> mRules = new ArrayList<>();
+
+ private static class Rule {
+ public final char type;
+ public final @NonNull byte[] value;
+ public final @Nullable byte[] mask;
+
+ public Rule(char type, @NonNull byte[] value, @Nullable byte[] mask) {
+ if (mask != null && value.length != mask.length) {
+ throw new IllegalArgumentException(
+ "Expected length " + value.length + " but found " + mask.length);
+ }
+ this.type = type;
+ this.value = value;
+ this.mask = mask;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ encode(builder);
+ return builder.toString();
+ }
+
+ public void encode(@NonNull StringBuilder builder) {
+ builder.append(type);
+ builder.append(HexDump.toHexString(value));
+ if (mask != null) {
+ builder.append('/');
+ builder.append(HexDump.toHexString(mask));
+ }
+ }
+
+ public boolean test(@NonNull byte[] value) {
+ if (value.length != this.value.length) {
+ return false;
+ }
+ for (int i = 0; i < this.value.length; i++) {
+ byte local = this.value[i];
+ byte remote = value[i];
+ if (this.mask != null) {
+ local &= this.mask[i];
+ remote &= this.mask[i];
+ }
+ if (local != remote) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Add a rule that will result in {@link #test(byte[])} returning
+ * {@code true} when a value being tested matches it.
+ * <p>
+ * Rules are tested in the order in which they were originally added, which
+ * means a narrow rule can reject a specific value before a later broader
+ * rule might accept that same value, or vice versa.
+ *
+ * @param value to be matched
+ * @param mask to be applied to both values before testing for equality; if
+ * {@code null} then both values must match exactly
+ */
+ public void addAcceptRule(@NonNull byte[] value, @Nullable byte[] mask) {
+ mRules.add(new Rule(TYPE_ACCEPT, value, mask));
+ }
+
+ /**
+ * Add a rule that will result in {@link #test(byte[])} returning
+ * {@code false} when a value being tested matches it.
+ * <p>
+ * Rules are tested in the order in which they were originally added, which
+ * means a narrow rule can reject a specific value before a later broader
+ * rule might accept that same value, or vice versa.
+ *
+ * @param value to be matched
+ * @param mask to be applied to both values before testing for equality; if
+ * {@code null} then both values must match exactly
+ */
+ public void addRejectRule(@NonNull byte[] value, @Nullable byte[] mask) {
+ mRules.add(new Rule(TYPE_REJECT, value, mask));
+ }
+
+ /**
+ * Test if the given {@code ParcelUuid} value matches the set of rules
+ * configured in this matcher.
+ */
+ public boolean testBluetoothUuid(@NonNull ParcelUuid value) {
+ return test(BluetoothUuid.uuidToBytes(value));
+ }
+
+ /**
+ * Test if the given {@code MacAddress} value matches the set of rules
+ * configured in this matcher.
+ */
+ public boolean testMacAddress(@NonNull MacAddress value) {
+ return test(value.toByteArray());
+ }
+
+ /**
+ * Test if the given {@code byte[]} value matches the set of rules
+ * configured in this matcher.
+ */
+ @Override
+ public boolean test(@NonNull byte[] value) {
+ return test(value, false);
+ }
+
+ /**
+ * Test if the given {@code byte[]} value matches the set of rules
+ * configured in this matcher.
+ */
+ public boolean test(@NonNull byte[] value, boolean defaultValue) {
+ final int size = mRules.size();
+ for (int i = 0; i < size; i++) {
+ final Rule rule = mRules.get(i);
+ if (rule.test(value)) {
+ return (rule.type == TYPE_ACCEPT);
+ }
+ }
+ return defaultValue;
+ }
+
+ /**
+ * Encode the given matcher into a human-readable {@link String} which can
+ * be used to transport matchers across device boundaries.
+ * <p>
+ * The human-readable format is an ordered list separated by commas, where
+ * each rule is a {@code +} or {@code -} symbol indicating if the match
+ * should be accepted or rejected, then followed by a hex value and an
+ * optional hex mask. For example, {@code -caff,+cafe/ff00} is a valid
+ * encoded matcher.
+ *
+ * @see #decode(String)
+ */
+ public static @NonNull String encode(@NonNull BytesMatcher matcher) {
+ final StringBuilder builder = new StringBuilder();
+ final int size = matcher.mRules.size();
+ for (int i = 0; i < size; i++) {
+ final Rule rule = matcher.mRules.get(i);
+ rule.encode(builder);
+ builder.append(',');
+ }
+ builder.deleteCharAt(builder.length() - 1);
+ return builder.toString();
+ }
+
+ /**
+ * Decode the given human-readable {@link String} used to transport matchers
+ * across device boundaries.
+ * <p>
+ * The human-readable format is an ordered list separated by commas, where
+ * each rule is a {@code +} or {@code -} symbol indicating if the match
+ * should be accepted or rejected, then followed by a hex value and an
+ * optional hex mask. For example, {@code -caff,+cafe/ff00} is a valid
+ * encoded matcher.
+ *
+ * @see #encode(BytesMatcher)
+ */
+ public static @NonNull BytesMatcher decode(@NonNull String value) {
+ final BytesMatcher matcher = new BytesMatcher();
+ final int length = value.length();
+ for (int i = 0; i < length;) {
+ final char type = value.charAt(i);
+
+ int nextRule = value.indexOf(',', i);
+ int nextMask = value.indexOf('/', i);
+
+ if (nextRule == -1) nextRule = length;
+ if (nextMask > nextRule) nextMask = -1;
+
+ final byte[] ruleValue;
+ final byte[] ruleMask;
+ if (nextMask >= 0) {
+ ruleValue = HexDump.hexStringToByteArray(value.substring(i + 1, nextMask));
+ ruleMask = HexDump.hexStringToByteArray(value.substring(nextMask + 1, nextRule));
+ } else {
+ ruleValue = HexDump.hexStringToByteArray(value.substring(i + 1, nextRule));
+ ruleMask = null;
+ }
+
+ switch (type) {
+ case TYPE_ACCEPT:
+ matcher.addAcceptRule(ruleValue, ruleMask);
+ break;
+ case TYPE_REJECT:
+ matcher.addRejectRule(ruleValue, ruleMask);
+ break;
+ default:
+ Log.w(TAG, "Ignoring unknown type " + type);
+ break;
+ }
+
+ i = nextRule + 1;
+ }
+ return matcher;
+ }
+}
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 8f61613..ae7d94c 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -42,8 +42,7 @@
void updateWakeLockWorkSource(IBinder lock, in WorkSource ws, String historyTag);
boolean isWakeLockLevelSupported(int level);
- @UnsupportedAppUsage
- void userActivity(long time, int event, int flags);
+ void userActivity(int displayId, long time, int event, int flags);
void wakeUp(long time, int reason, String details, String opPackageName);
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
void goToSleep(long time, int reason, int flags);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index e5163d8..786a7d0 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -1277,7 +1277,7 @@
})
public void userActivity(long when, int event, int flags) {
try {
- mService.userActivity(when, event, flags);
+ mService.userActivity(mContext.getDisplayId(), when, event, flags);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 0587610..03e5f1d 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -503,6 +503,20 @@
}
/** @hide */
+ public static String effectStrengthToString(int effectStrength) {
+ switch (effectStrength) {
+ case EFFECT_STRENGTH_LIGHT:
+ return "LIGHT";
+ case EFFECT_STRENGTH_MEDIUM:
+ return "MEDIUM";
+ case EFFECT_STRENGTH_STRONG:
+ return "STRONG";
+ default:
+ return Integer.toString(effectStrength);
+ }
+ }
+
+ /** @hide */
@TestApi
public static class OneShot extends VibrationEffect implements Parcelable {
private final long mDuration;
@@ -936,8 +950,8 @@
@Override
public String toString() {
- return "Prebaked{mEffectId=" + mEffectId
- + ", mEffectStrength=" + mEffectStrength
+ return "Prebaked{mEffectId=" + effectIdToString(mEffectId)
+ + ", mEffectStrength=" + effectStrengthToString(mEffectStrength)
+ ", mFallback=" + mFallback
+ ", mFallbackEffect=" + mFallbackEffect
+ "}";
diff --git a/core/java/android/os/VibratorInfo.java b/core/java/android/os/VibratorInfo.java
index 07272e7..50d2de3 100644
--- a/core/java/android/os/VibratorInfo.java
+++ b/core/java/android/os/VibratorInfo.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.hardware.vibrator.IVibrator;
import android.util.SparseBooleanArray;
import java.util.ArrayList;
@@ -33,20 +34,7 @@
* @hide
*/
public final class VibratorInfo implements Parcelable {
-
- /**
- * Capability to set amplitude values to vibrations.
- * @hide
- */
- // Internally this maps to the HAL constant IVibrator::CAP_AMPLITUDE_CONTROL
- public static final int CAPABILITY_AMPLITUDE_CONTROL = 4;
-
- /**
- * Capability to compose primitives into a single effect.
- * @hide
- */
- // Internally this maps to the HAL constant IVibrator::CAP_COMPOSE_EFFECTS
- public static final int CAPABILITY_COMPOSE_EFFECTS = 32;
+ private static final String TAG = "VibratorInfo";
private final int mId;
private final long mCapabilities;
@@ -108,7 +96,7 @@
return "VibratorInfo{"
+ "mId=" + mId
+ ", mCapabilities=" + Arrays.toString(getCapabilitiesNames())
- + ", mCapabilities flags=" + mCapabilities
+ + ", mCapabilities flags=" + Long.toBinaryString(mCapabilities)
+ ", mSupportedEffects=" + Arrays.toString(getSupportedEffectsNames())
+ ", mSupportedPrimitives=" + Arrays.toString(getSupportedPrimitivesNames())
+ '}';
@@ -125,7 +113,7 @@
* @return True if the hardware can control the amplitude of the vibrations, otherwise false.
*/
public boolean hasAmplitudeControl() {
- return hasCapability(CAPABILITY_AMPLITUDE_CONTROL);
+ return hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL);
}
/**
@@ -153,7 +141,7 @@
* @return Whether the primitive is supported.
*/
public boolean isPrimitiveSupported(@VibrationEffect.Composition.Primitive int primitiveId) {
- return hasCapability(CAPABILITY_COMPOSE_EFFECTS) && mSupportedPrimitives != null
+ return hasCapability(IVibrator.CAP_COMPOSE_EFFECTS) && mSupportedPrimitives != null
&& mSupportedPrimitives.get(primitiveId, false);
}
@@ -170,11 +158,26 @@
private String[] getCapabilitiesNames() {
List<String> names = new ArrayList<>();
- if (hasCapability(CAPABILITY_AMPLITUDE_CONTROL)) {
+ if (hasCapability(IVibrator.CAP_ON_CALLBACK)) {
+ names.add("ON_CALLBACK");
+ }
+ if (hasCapability(IVibrator.CAP_PERFORM_CALLBACK)) {
+ names.add("PERFORM_CALLBACK");
+ }
+ if (hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
+ names.add("COMPOSE_EFFECTS");
+ }
+ if (hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
+ names.add("ALWAYS_ON_CONTROL");
+ }
+ if (hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
names.add("AMPLITUDE_CONTROL");
}
- if (hasCapability(CAPABILITY_COMPOSE_EFFECTS)) {
- names.add("COMPOSE_EFFECTS");
+ if (hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
+ names.add("EXTERNAL_CONTROL");
+ }
+ if (hasCapability(IVibrator.CAP_EXTERNAL_AMPLITUDE_CONTROL)) {
+ names.add("EXTERNAL_AMPLITUDE_CONTROL");
}
return names.toArray(new String[names.size()]);
}
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 9ffc5aa0..bf28981 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -333,7 +333,7 @@
* started.
* @param pkgDataInfoMap Map from related package names to private data directory
* volume UUID and inode number.
- * @param whitelistedDataInfoMap Map from allowlisted package names to private data directory
+ * @param allowlistedDataInfoList Map from allowlisted package names to private data directory
* volume UUID and inode number.
* @param bindMountAppsData whether zygote needs to mount CE and DE data.
* @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
@@ -359,7 +359,7 @@
@Nullable Map<String, Pair<String, Long>>
pkgDataInfoMap,
@Nullable Map<String, Pair<String, Long>>
- whitelistedDataInfoMap,
+ allowlistedDataInfoList,
boolean bindMountAppsData,
boolean bindMountAppStorageDirs,
@Nullable String[] zygoteArgs) {
@@ -373,7 +373,7 @@
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges,
- pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData,
+ pkgDataInfoMap, allowlistedDataInfoList, bindMountAppsData,
bindMountAppStorageDirs, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
@@ -615,7 +615,7 @@
* @param disabledCompatChanges a list of disabled compat changes for the process being started.
* @param pkgDataInfoMap Map from related package names to private data directory volume UUID
* and inode number.
- * @param whitelistedDataInfoMap Map from allowlisted package names to private data directory
+ * @param allowlistedDataInfoList Map from allowlisted package names to private data directory
* volume UUID and inode number.
* @param bindMountAppsData whether zygote needs to mount CE and DE data.
* @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
@@ -642,7 +642,7 @@
@Nullable Map<String, Pair<String, Long>>
pkgDataInfoMap,
@Nullable Map<String, Pair<String, Long>>
- whitelistedDataInfoMap,
+ allowlistedDataInfoList,
boolean bindMountAppsData,
boolean bindMountAppStorageDirs,
@Nullable String[] extraArgs)
@@ -733,12 +733,12 @@
}
argsForZygote.add(sb.toString());
}
- if (whitelistedDataInfoMap != null && whitelistedDataInfoMap.size() > 0) {
+ if (allowlistedDataInfoList != null && allowlistedDataInfoList.size() > 0) {
StringBuilder sb = new StringBuilder();
- sb.append(Zygote.WHITELISTED_DATA_INFO_MAP);
+ sb.append(Zygote.ALLOWLISTED_DATA_INFO_MAP);
sb.append("=");
boolean started = false;
- for (Map.Entry<String, Pair<String, Long>> entry : whitelistedDataInfoMap.entrySet()) {
+ for (Map.Entry<String, Pair<String, Long>> entry : allowlistedDataInfoList.entrySet()) {
if (started) {
sb.append(',');
}
@@ -1318,7 +1318,7 @@
true /* startChildZygote */, null /* packageName */,
ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS /* zygotePolicyFlags */, false /* isTopApp */,
null /* disabledCompatChanges */, null /* pkgDataInfoMap */,
- null /* whitelistedDataInfoMap */, true /* bindMountAppsData*/,
+ null /* allowlistedDataInfoList */, true /* bindMountAppsData*/,
/* bindMountAppStorageDirs */ false, extraArgs);
} catch (ZygoteStartFailedEx ex) {
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
index 87dced8..dc6f63a 100644
--- a/core/java/android/os/incremental/IncrementalManager.java
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -58,6 +58,8 @@
private static final String ALLOWED_PROPERTY = "incremental.allowed";
+ public static final int MIN_VERSION_TO_SUPPORT_FSVERITY = 2;
+
public static final int CREATE_MODE_TEMPORARY_BIND =
IIncrementalService.CREATE_MODE_TEMPORARY_BIND;
public static final int CREATE_MODE_PERMANENT_BIND =
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index b12bb2e..396ba2d 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.os.IVold;
+import java.util.List;
import java.util.Set;
/**
@@ -112,4 +113,10 @@
* @param bytes number of bytes which need to be freed
*/
public abstract void freeCache(@Nullable String volumeUuid, long bytes);
+
+ /**
+ * Returns the {@link VolumeInfo#getId()} values for the volumes matching
+ * {@link VolumeInfo#isPrimary()}
+ */
+ public abstract List<String> getPrimaryVolumeIds();
}
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 084b18e..913b827 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -668,7 +668,7 @@
public void getPrivilegesDescriptionStringForProfile(
@NonNull String profileName,
@NonNull @CallbackExecutor Executor executor,
- @NonNull Consumer<String> callback) {
+ @NonNull Consumer<CharSequence> callback) {
mRemoteService.postAsync(service -> {
AndroidFuture<String> future = new AndroidFuture<>();
service.getPrivilegesDescriptionStringForProfile(profileName, future);
diff --git a/core/java/android/service/autofill/AutofillServiceInfo.java b/core/java/android/service/autofill/AutofillServiceInfo.java
index fbc25a6..4c8ee59 100644
--- a/core/java/android/service/autofill/AutofillServiceInfo.java
+++ b/core/java/android/service/autofill/AutofillServiceInfo.java
@@ -18,10 +18,13 @@
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.AppGlobals;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -44,6 +47,8 @@
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
/**
* {@link ServiceInfo} and meta-data about an {@link AutofillService}.
@@ -76,6 +81,8 @@
@Nullable
private final String mSettingsActivity;
+ @Nullable
+ private final String mPasswordsActivity;
@Nullable
private final ArrayMap<String, Long> mCompatibilityPackages;
@@ -113,12 +120,14 @@
AutofillService.SERVICE_META_DATA);
if (parser == null) {
mSettingsActivity = null;
+ mPasswordsActivity = null;
mCompatibilityPackages = null;
mInlineSuggestionsEnabled = false;
return;
}
String settingsActivity = null;
+ String passwordsActivity = null;
ArrayMap<String, Long> compatibilityPackages = null;
boolean inlineSuggestionsEnabled = false; // false by default.
@@ -139,6 +148,8 @@
com.android.internal.R.styleable.AutofillService);
settingsActivity = afsAttributes.getString(
R.styleable.AutofillService_settingsActivity);
+ passwordsActivity = afsAttributes.getString(
+ R.styleable.AutofillService_passwordsActivity);
inlineSuggestionsEnabled = afsAttributes.getBoolean(
R.styleable.AutofillService_supportsInlineSuggestions, false);
} finally {
@@ -155,6 +166,7 @@
}
mSettingsActivity = settingsActivity;
+ mPasswordsActivity = passwordsActivity;
mCompatibilityPackages = compatibilityPackages;
mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
}
@@ -221,6 +233,7 @@
return compatibilityPackages;
}
+ @NonNull
public ServiceInfo getServiceInfo() {
return mServiceInfo;
}
@@ -230,6 +243,12 @@
return mSettingsActivity;
}
+ @Nullable
+ public String getPasswordsActivity() {
+ return mPasswordsActivity;
+ }
+
+ @Nullable
public ArrayMap<String, Long> getCompatibilityPackages() {
return mCompatibilityPackages;
}
@@ -238,12 +257,37 @@
return mInlineSuggestionsEnabled;
}
+ /**
+ * Queries the valid autofill services available for the user.
+ */
+ public static List<AutofillServiceInfo> getAvailableServices(
+ Context context, @UserIdInt int user) {
+ final List<AutofillServiceInfo> services = new ArrayList<>();
+
+ final List<ResolveInfo> resolveInfos =
+ context.getPackageManager().queryIntentServicesAsUser(
+ new Intent(AutofillService.SERVICE_INTERFACE),
+ PackageManager.GET_META_DATA,
+ user);
+ for (ResolveInfo resolveInfo : resolveInfos) {
+ final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+ try {
+ services.add(new AutofillServiceInfo(context, serviceInfo));
+ } catch (SecurityException e) {
+ // Service does not declare the proper permission, ignore it.
+ Log.w(TAG, "Error getting info for " + serviceInfo + ": " + e);
+ }
+ }
+ return services;
+ }
+
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append(getClass().getSimpleName());
builder.append("[").append(mServiceInfo);
builder.append(", settings:").append(mSettingsActivity);
+ builder.append(", passwords activity:").append(mPasswordsActivity);
builder.append(", hasCompatPckgs:").append(mCompatibilityPackages != null
&& !mCompatibilityPackages.isEmpty()).append("]");
builder.append(", inline suggestions enabled:").append(mInlineSuggestionsEnabled);
@@ -256,6 +300,7 @@
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("Component: "); pw.println(getServiceInfo().getComponentName());
pw.print(prefix); pw.print("Settings: "); pw.println(mSettingsActivity);
+ pw.print(prefix); pw.print("Passwords activity: "); pw.println(mPasswordsActivity);
pw.print(prefix); pw.print("Compat packages: "); pw.println(mCompatibilityPackages);
pw.print(prefix); pw.print("Inline Suggestions Enabled: ");
pw.println(mInlineSuggestionsEnabled);
diff --git a/core/java/android/service/storage/ExternalStorageService.java b/core/java/android/service/storage/ExternalStorageService.java
index 1e07a87..bbe184b 100644
--- a/core/java/android/service/storage/ExternalStorageService.java
+++ b/core/java/android/service/storage/ExternalStorageService.java
@@ -239,14 +239,13 @@
}
@Override
- public void notifyAnrDelayStarted(String packageName, int uid, int tid, int reason,
- RemoteCallback callback) throws RemoteException {
+ public void notifyAnrDelayStarted(String packageName, int uid, int tid, int reason)
+ throws RemoteException {
mHandler.post(() -> {
try {
onAnrDelayStarted(packageName, uid, tid, reason);
- sendResult(packageName, null /* throwable */, callback);
} catch (Throwable t) {
- sendResult(packageName, t, callback);
+ // Ignored
}
});
}
diff --git a/core/java/android/service/storage/IExternalStorageService.aidl b/core/java/android/service/storage/IExternalStorageService.aidl
index ba98efa..0766b75 100644
--- a/core/java/android/service/storage/IExternalStorageService.aidl
+++ b/core/java/android/service/storage/IExternalStorageService.aidl
@@ -32,6 +32,5 @@
in RemoteCallback callback);
void freeCache(@utf8InCpp String sessionId, in String volumeUuid, long bytes,
in RemoteCallback callback);
- void notifyAnrDelayStarted(String packageName, int uid, int tid, int reason,
- in RemoteCallback callback);
+ void notifyAnrDelayStarted(String packageName, int uid, int tid, int reason);
}
\ No newline at end of file
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index e7ceada..e37921e 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -17,10 +17,7 @@
package android.telephony;
import android.Manifest;
-import android.annotation.CallbackExecutor;
-import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.compat.annotation.ChangeId;
@@ -31,16 +28,12 @@
import android.os.HandlerExecutor;
import android.os.Looper;
import android.telephony.Annotation.CallState;
-import android.telephony.Annotation.DataActivityType;
import android.telephony.Annotation.DisconnectCauses;
-import android.telephony.Annotation.NetworkType;
import android.telephony.Annotation.PreciseDisconnectCauses;
import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SimActivationState;
import android.telephony.Annotation.SrvccState;
-import android.telephony.NetworkRegistrationInfo.Domain;
import android.telephony.TelephonyManager.DataEnabledReason;
-import android.telephony.TelephonyManager.DataState;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsReasonInfo;
@@ -49,8 +42,6 @@
import dalvik.system.VMRuntime;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.Map;
@@ -71,49 +62,15 @@
* information unless it has the appropriate permissions declared in
* its manifest file. Where permissions apply, they are noted in the
* appropriate LISTEN_ flags.
+ *
+ * @deprecated Use {@link TelephonyCallback} instead.
*/
+@Deprecated
public class PhoneStateListener {
private static final String LOG_TAG = "PhoneStateListener";
private static final boolean DBG = false; // STOPSHIP if true
/**
- * Experiment flag to set the per-pid registration limit for PhoneStateListeners
- *
- * Limit on registrations of {@link PhoneStateListener}s on a per-pid
- * basis. When this limit is exceeded, any calls to {@link TelephonyManager#listen} will fail
- * with an {@link IllegalStateException}.
- *
- * {@link android.os.Process#PHONE_UID}, {@link android.os.Process#SYSTEM_UID}, and the uid that
- * TelephonyRegistry runs under are exempt from this limit.
- *
- * If the value of the flag is less than 1, enforcement of the limit will be disabled.
- * @hide
- */
- public static final String FLAG_PER_PID_REGISTRATION_LIMIT =
- "phone_state_listener_per_pid_registration_limit";
-
- /**
- * Default value for the per-pid registation limit.
- * See {@link #FLAG_PER_PID_REGISTRATION_LIMIT}.
- * @hide
- */
- public static final int DEFAULT_PER_PID_REGISTRATION_LIMIT = 50;
-
- /**
- * This change enables a limit on the number of {@link PhoneStateListener} objects any process
- * may register via {@link TelephonyManager#listen}. The default limit is 50, which may change
- * via remote device config updates.
- *
- * This limit is enforced via an {@link IllegalStateException} thrown from
- * {@link TelephonyManager#listen} when the offending process attempts to register one too many
- * listeners.
- *
- * @hide
- */
- @ChangeId
- public static final long PHONE_STATE_LISTENER_LIMIT_CHANGE_ID = 150880553L;
-
- /**
* Stop listening for updates.
*
* The PhoneStateListener is not tied to any subscription and unregistered for any update.
@@ -125,7 +82,7 @@
*
* @see #onServiceStateChanged
* @see ServiceState
- * @deprecated Use {@link ServiceStateChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.ServiceStateListener} instead.
*/
@Deprecated
public static final int LISTEN_SERVICE_STATE = 0x00000001;
@@ -135,7 +92,7 @@
* {@more}
*
* @see #onSignalStrengthChanged
- * @deprecated Use {@link SignalStrengthsChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.SignalStrengthsListener} instead.
*/
@Deprecated
public static final int LISTEN_SIGNAL_STRENGTH = 0x00000002;
@@ -151,7 +108,7 @@
* voicemail icon.
*
* @see #onMessageWaitingIndicatorChanged
- * @deprecated Use {@link MessageWaitingIndicatorChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.MessageWaitingIndicatorListener} instead.
*/
@Deprecated
public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 0x00000004;
@@ -164,7 +121,7 @@
* {@link TelephonyManager#hasCarrierPrivileges}).
*
* @see #onCallForwardingIndicatorChanged
- * @deprecated Use {@link CallForwardingIndicatorChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.CallForwardingIndicatorListener} instead.
*/
@Deprecated
public static final int LISTEN_CALL_FORWARDING_INDICATOR = 0x00000008;
@@ -182,7 +139,7 @@
* instead.
*
* @see #onCellLocationChanged
- * @deprecated Use {@link CellLocationChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.CellLocationListener} instead.
*/
@Deprecated
public static final int LISTEN_CELL_LOCATION = 0x00000010;
@@ -192,7 +149,7 @@
* {@more}
*
* @see #onCallStateChanged
- * @deprecated Use {@link CallStateChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.CallStateListener} instead.
*/
@Deprecated
public static final int LISTEN_CALL_STATE = 0x00000020;
@@ -201,7 +158,7 @@
* Listen for changes to the data connection state (cellular).
*
* @see #onDataConnectionStateChanged
- * @deprecated Use {@link DataConnectionStateChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.DataConnectionStateListener} instead.
*/
@Deprecated
public static final int LISTEN_DATA_CONNECTION_STATE = 0x00000040;
@@ -214,7 +171,7 @@
* data-traffic icon.
*
* @see #onDataActivity
- * @deprecated Use {@link DataActivityListener} instead.
+ * @deprecated Use {@link TelephonyCallback.DataActivityListener} instead.
*/
@Deprecated
public static final int LISTEN_DATA_ACTIVITY = 0x00000080;
@@ -226,7 +183,7 @@
* icon.
*
* @see #onSignalStrengthsChanged
- * @deprecated Use {@link SignalStrengthsChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.SignalStrengthsListener} instead.
*/
@Deprecated
public static final int LISTEN_SIGNAL_STRENGTHS = 0x00000100;
@@ -238,7 +195,8 @@
* @see #onSignalStrengthsChanged
*
* @hide
- * @deprecated Use {@link AlwaysReportedSignalStrengthChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.AlwaysReportedSignalStrengthListener}
+ * instead.
*/
@Deprecated
@RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
@@ -251,7 +209,7 @@
* permission.
*
* @see #onCellInfoChanged
- * @deprecated Use {@link CellInfoChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.CellInfoListener} instead.
*/
@Deprecated
public static final int LISTEN_CELL_INFO = 0x00000400;
@@ -265,7 +223,7 @@
* (see {@link TelephonyManager#hasCarrierPrivileges}).
*
* @hide
- * @deprecated Use {@link PreciseCallStateChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.PreciseCallStateListener} instead.
*/
@Deprecated
@RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
@@ -280,7 +238,7 @@
* (see {@link TelephonyManager#hasCarrierPrivileges}).
*
* @see #onPreciseDataConnectionStateChanged
- * @deprecated Use {@link PreciseDataConnectionStateChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.PreciseDataConnectionStateListener} instead.
*/
@Deprecated
@RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
@@ -306,7 +264,7 @@
*
* @see #onServiceStateChanged(ServiceState)
* @hide
- * @deprecated Use {@link SrvccStateChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.SrvccStateListener} instead.
*/
@Deprecated
@SystemApi
@@ -328,7 +286,7 @@
*
* @see android.service.carrier.CarrierService#notifyCarrierNetworkChange(boolean)
* @hide
- * @deprecated Use {@link CarrierNetworkChangeListener} instead.
+ * @deprecated Use {@link TelephonyCallback.CarrierNetworkListener} instead.
*/
@Deprecated
public static final int LISTEN_CARRIER_NETWORK_CHANGE = 0x00010000;
@@ -349,7 +307,7 @@
*
* @see #onVoiceActivationStateChanged
* @hide
- * @deprecated Use {@link VoiceActivationStateChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.VoiceActivationStateListener} instead.
*/
@Deprecated
@SystemApi
@@ -369,7 +327,7 @@
*
* @see #onDataActivationStateChanged
* @hide
- * @deprecated Use {@link DataActivationStateChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.DataActivationStateListener} instead.
*/
@Deprecated
public static final int LISTEN_DATA_ACTIVATION_STATE = 0x00040000;
@@ -378,7 +336,7 @@
* Listen for changes to the user mobile data state
*
* @see #onUserMobileDataStateChanged
- * @deprecated Use {@link UserMobileDataStateChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.UserMobileDataStateListener} instead.
*/
@Deprecated
public static final int LISTEN_USER_MOBILE_DATA_STATE = 0x00080000;
@@ -391,7 +349,7 @@
* {@link TelephonyManager#hasCarrierPrivileges}).
*
* @see #onDisplayInfoChanged
- * @deprecated Use {@link DisplayInfoChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.DisplayInfoListener} instead.
*/
@Deprecated
public static final int LISTEN_DISPLAY_INFO_CHANGED = 0x00100000;
@@ -401,7 +359,7 @@
*
* @see #onPhoneCapabilityChanged
* @hide
- * @deprecated Use {@link PhoneCapabilityChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.PhoneCapabilityListener} instead.
*/
@Deprecated
public static final int LISTEN_PHONE_CAPABILITY_CHANGE = 0x00200000;
@@ -413,7 +371,7 @@
* subscription user selected as default data subscription in DSDS mode.
*
* @see #onActiveDataSubscriptionIdChanged
- * @deprecated Use {@link ActiveDataSubscriptionIdChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.ActiveDataSubscriptionIdListener} instead.
*/
@Deprecated
public static final int LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE = 0x00400000;
@@ -423,7 +381,7 @@
*
* @see #onRadioPowerStateChanged
* @hide
- * @deprecated Use {@link RadioPowerStateChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.RadioPowerStateListener} instead.
*/
@Deprecated
@SystemApi
@@ -436,7 +394,7 @@
* <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
* app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
*
- * @deprecated Use {@link EmergencyNumberListChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.EmergencyNumberListListener} instead.
*/
@Deprecated
public static final int LISTEN_EMERGENCY_NUMBER_LIST = 0x01000000;
@@ -449,7 +407,7 @@
* or the calling app has carrier privileges
* (see {@link TelephonyManager#hasCarrierPrivileges}).
*
- * @deprecated Use {@link CallDisconnectCauseChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.CallDisconnectCauseListener} instead.
*/
@Deprecated
@RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
@@ -464,7 +422,7 @@
*
* @see #onCallAttributesChanged
* @hide
- * @deprecated Use {@link CallAttributesChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.CallAttributesListener} instead.
*/
@Deprecated
@SystemApi
@@ -480,7 +438,7 @@
* (see {@link TelephonyManager#hasCarrierPrivileges}).
*
* @see #onImsCallDisconnectCauseChanged(ImsReasonInfo)
- * @deprecated Use {@link ImsCallDisconnectCauseChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.ImsCallDisconnectCauseListener} instead.
*/
@Deprecated
@RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
@@ -491,7 +449,7 @@
*
* @see #onOutgoingEmergencyCall
* @hide
- * @deprecated Use {@link OutgoingEmergencyCallListener} instead.
+ * @deprecated Use {@link TelephonyCallback.OutgoingEmergencyCallListener} instead.
*/
@Deprecated
@SystemApi
@@ -503,7 +461,7 @@
*
* @see #onOutgoingEmergencySms
* @hide
- * @deprecated Use {@link OutgoingEmergencySmsListener} instead.
+ * @deprecated Use {@link TelephonyCallback.OutgoingEmergencySmsListener} instead.
*/
@Deprecated
@SystemApi
@@ -524,7 +482,7 @@
* of whether the calling app has carrier privileges.
*
* @see #onRegistrationFailed
- * @deprecated Use {@link RegistrationFailedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.RegistrationFailedListener} instead.
*/
@Deprecated
@RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
@@ -540,540 +498,12 @@
* of whether the calling app has carrier privileges.
*
* @see #onBarringInfoChanged
- * @deprecated Use {@link BarringInfoChangedListener} instead.
+ * @deprecated Use {@link TelephonyCallback.BarringInfoListener} instead.
*/
@Deprecated
@RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
public static final int LISTEN_BARRING_INFO = 0x80000000;
- /**
- * Event for changes to the network service state (cellular).
- *
- * @see ServiceStateChangedListener#onServiceStateChanged
- * @see ServiceState
- *
- * @hide
- */
- @SystemApi
- public static final int EVENT_SERVICE_STATE_CHANGED = 1;
-
- /**
- * Event for changes to the network signal strength (cellular).
- *
- * @see SignalStrengthsChangedListener#onSignalStrengthsChanged
- *
- * @hide
- */
- @SystemApi
- public static final int EVENT_SIGNAL_STRENGTH_CHANGED = 2;
-
- /**
- * Event for changes to the message-waiting indicator.
- *
- * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE} or that
- * the calling app has carrier privileges (see
- * {@link TelephonyManager#hasCarrierPrivileges}).
- * <p>
- * Example: The status bar uses this to determine when to display the
- * voicemail icon.
- *
- * @see MessageWaitingIndicatorChangedListener#onMessageWaitingIndicatorChanged
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public static final int EVENT_MESSAGE_WAITING_INDICATOR_CHANGED = 3;
-
- /**
- * Event for changes to the call-forwarding indicator.
- *
- * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE} or that
- * the calling app has carrier privileges (see
- * {@link TelephonyManager#hasCarrierPrivileges}).
- *
- * @see CallForwardingIndicatorChangedListener#onCallForwardingIndicatorChanged
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public static final int EVENT_CALL_FORWARDING_INDICATOR_CHANGED = 4;
-
- /**
- * Event for changes to the device's cell location. Note that
- * this will result in frequent callbacks to the listener.
- *
- * If you need regular location updates but want more control over
- * the update interval or location precision, you can set up a listener
- * through the {@link android.location.LocationManager location manager}
- * instead.
- *
- * @see CellLocationChangedListener#onCellLocationChanged
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
- public static final int EVENT_CELL_LOCATION_CHANGED = 5;
-
- /**
- * Event for changes to the device call state.
- *
- * @see CallStateChangedListener#onCallStateChanged
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.READ_CALL_LOG)
- public static final int EVENT_CALL_STATE_CHANGED = 6;
-
- /**
- * Event for changes to the data connection state (cellular).
- *
- * @see DataConnectionStateChangedListener#onDataConnectionStateChanged
- *
- * @hide
- */
- @SystemApi
- public static final int EVENT_DATA_CONNECTION_STATE_CHANGED = 7;
-
- /**
- * Event for changes to the direction of data traffic on the data
- * connection (cellular).
- *
- * Example: The status bar uses this to display the appropriate
- * data-traffic icon.
- *
- * @see DataActivityListener#onDataActivity
- *
- * @hide
- */
- @SystemApi
- public static final int EVENT_DATA_ACTIVITY_CHANGED = 8;
-
- /**
- * Event for changes to the network signal strengths (cellular).
- * <p>
- * Example: The status bar uses this to control the signal-strength
- * icon.
- *
- * @see SignalStrengthsChangedListener#onSignalStrengthsChanged
- *
- * @hide
- */
- @SystemApi
- public static final int EVENT_SIGNAL_STRENGTHS_CHANGED = 9;
-
- /**
- * Event for changes of the network signal strengths (cellular) always reported from modem,
- * even in some situations such as the screen of the device is off.
- *
- * @see AlwaysReportedSignalStrengthChangedListener#onSignalStrengthsChanged
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
- public static final int EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED = 10;
-
- /**
- * Event for changes to observed cell info.
- *
- * @see CellInfoChangedListener#onCellInfoChanged
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
- public static final int EVENT_CELL_INFO_CHANGED = 11;
-
- /**
- * Event for {@link android.telephony.Annotation.PreciseCallStates} of ringing,
- * background and foreground calls.
- *
- * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
- * or the calling app has carrier privileges
- * (see {@link TelephonyManager#hasCarrierPrivileges}).
- *
- * @see PreciseCallStateChangedListener#onPreciseCallStateChanged
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
- public static final int EVENT_PRECISE_CALL_STATE_CHANGED = 12;
-
- /**
- * Event for {@link PreciseDataConnectionState} on the data connection (cellular).
- *
- * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
- * or the calling app has carrier privileges
- * (see {@link TelephonyManager#hasCarrierPrivileges}).
- *
- * @see PreciseDataConnectionStateChangedListener#onPreciseDataConnectionStateChanged
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
- public static final int EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED = 13;
-
- /**
- * Event for real time info for all data connections (cellular)).
- *
- * @see #onDataConnectionRealTimeInfoChanged(DataConnectionRealTimeInfo)
- *
- * @deprecated Use {@link TelephonyManager#requestModemActivityInfo}
- * @hide
- */
- @Deprecated
- @SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
- public static final int EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED = 14;
-
- /**
- * Event for OEM hook raw event
- *
- * @see #onOemHookRawEvent
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public static final int EVENT_OEM_HOOK_RAW = 15;
-
- /**
- * Event for changes to the SRVCC state of the active call.
- *
- * @see SrvccStateChangedListener#onSrvccStateChanged
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public static final int EVENT_SRVCC_STATE_CHANGED = 16;
-
- /**
- * Event for carrier network changes indicated by a carrier app.
- *
- * @see android.service.carrier.CarrierService#notifyCarrierNetworkChange(boolean)
- * @see CarrierNetworkChangeListener#onCarrierNetworkChange
- *
- * @hide
- */
- @SystemApi
- public static final int EVENT_CARRIER_NETWORK_CHANGED = 17;
-
- /**
- * Event for changes to the sim voice activation state
- *
- * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING
- * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED
- * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED
- * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED
- * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN
- *
- * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates voice service has been
- * fully activated
- *
- * @see VoiceActivationStateChangedListener#onVoiceActivationStateChanged
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public static final int EVENT_VOICE_ACTIVATION_STATE_CHANGED = 18;
-
- /**
- * Event for changes to the sim data activation state
- * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING
- * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED
- * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED
- * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED
- * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN
- *
- * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates data service has been
- * fully activated
- *
- * @see DataActivationStateChangedListener#onDataActivationStateChanged
- * @hide
- */
- @SystemApi
- public static final int EVENT_DATA_ACTIVATION_STATE_CHANGED = 19;
-
- /**
- * Event for changes to the user mobile data state
- *
- * @see UserMobileDataStateChangedListener#onUserMobileDataStateChanged
- *
- * @hide
- */
- @SystemApi
- public static final int EVENT_USER_MOBILE_DATA_STATE_CHANGED = 20;
-
- /**
- * Event for display info changed event.
- *
- * @see DisplayInfoChangedListener#onDisplayInfoChanged
- *
- * @hide
- */
- @SystemApi
- public static final int EVENT_DISPLAY_INFO_CHANGED = 21;
-
- /**
- * Event for changes to the phone capability.
- *
- * @see PhoneCapabilityChangedListener#onPhoneCapabilityChanged
- *
- * @hide
- */
- @SystemApi
- public static final int EVENT_PHONE_CAPABILITY_CHANGED = 22;
-
- /**
- * Event for changes to active data subscription ID. Active data subscription is
- * the current subscription used to setup Cellular Internet data. For example,
- * it could be the current active opportunistic subscription in use, or the
- * subscription user selected as default data subscription in DSDS mode.
- *
- * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
- * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
- *
- * @see ActiveDataSubscriptionIdChangedListener#onActiveDataSubscriptionIdChanged
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public static final int EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED = 23;
-
- /**
- * Event for changes to the radio power state.
- *
- * @see RadioPowerStateChangedListener#onRadioPowerStateChanged
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public static final int EVENT_RADIO_POWER_STATE_CHANGED = 24;
-
- /**
- * Event for changes to emergency number list based on all active subscriptions.
- *
- * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
- * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
- *
- * @see EmergencyNumberListChangedListener#onEmergencyNumberListChanged
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public static final int EVENT_EMERGENCY_NUMBER_LIST_CHANGED = 25;
-
- /**
- * Event for call disconnect causes which contains {@link DisconnectCause} and
- * {@link PreciseDisconnectCause}.
- *
- * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
- * or the calling app has carrier privileges
- * (see {@link TelephonyManager#hasCarrierPrivileges}).
- *
- * @see CallDisconnectCauseChangedListener#onCallDisconnectCauseChanged
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
- public static final int EVENT_CALL_DISCONNECT_CAUSE_CHANGED = 26;
-
- /**
- * Event for changes to the call attributes of a currently active call.
- *
- * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
- * or the calling app has carrier privileges
- * (see {@link TelephonyManager#hasCarrierPrivileges}).
- *
- * @see CallAttributesChangedListener#onCallAttributesChanged
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
- public static final int EVENT_CALL_ATTRIBUTES_CHANGED = 27;
-
- /**
- * Event for IMS call disconnect causes which contains
- * {@link android.telephony.ims.ImsReasonInfo}
- *
- * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
- * or the calling app has carrier privileges
- * (see {@link TelephonyManager#hasCarrierPrivileges}).
- *
- * @see ImsCallDisconnectCauseChangedListener#onImsCallDisconnectCauseChanged(ImsReasonInfo)
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
- public static final int EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED = 28;
-
- /**
- * Event for the emergency number placed from an outgoing call.
- *
- * @see OutgoingEmergencyCallListener#onOutgoingEmergencyCall
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
- public static final int EVENT_OUTGOING_EMERGENCY_CALL = 29;
-
- /**
- * Event for the emergency number placed from an outgoing SMS.
- *
- * @see OutgoingEmergencySmsListener#onOutgoingEmergencySms
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
- public static final int EVENT_OUTGOING_EMERGENCY_SMS = 30;
-
- /**
- * Event for registration failures.
- *
- * Event for indications that a registration procedure has failed in either the CS or PS
- * domain. This indication does not necessarily indicate a change of service state, which should
- * be tracked via {@link #EVENT_SERVICE_STATE_CHANGED}.
- *
- * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or
- * the calling app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
- *
- * <p>Also requires the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission, regardless
- * of whether the calling app has carrier privileges.
- *
- * @see RegistrationFailedListener#onRegistrationFailed
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(allOf = {
- Manifest.permission.READ_PRECISE_PHONE_STATE,
- Manifest.permission.ACCESS_FINE_LOCATION
- })
- public static final int EVENT_REGISTRATION_FAILURE = 31;
-
- /**
- * Event for Barring Information for the current registered / camped cell.
- *
- * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or
- * the calling app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
- *
- * <p>Also requires the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission, regardless
- * of whether the calling app has carrier privileges.
- *
- * @see BarringInfoChangedListener#onBarringInfoChanged
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(allOf = {
- Manifest.permission.READ_PRECISE_PHONE_STATE,
- Manifest.permission.ACCESS_FINE_LOCATION
- })
- public static final int EVENT_BARRING_INFO_CHANGED = 32;
-
- /**
- * Event for changes to the physical channel configuration.
- *
- * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
- * or the calling app has carrier privileges
- * (see {@link TelephonyManager#hasCarrierPrivileges}).
- *
- * @see PhysicalChannelConfigChangedListener#onPhysicalChannelConfigChanged
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
- public static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 33;
-
-
- /**
- * Event for changes to the data enabled.
- *
- * Event for indications that the enabled status of current data has changed.
- *
- * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
- * or the calling app has carrier privileges
- * (see {@link TelephonyManager#hasCarrierPrivileges}).
- *
- * @see DataEnabledChangedListener#onDataEnabledChanged
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
- public static final int EVENT_DATA_ENABLED_CHANGED = 34;
-
- /**
- * Event for changes to allowed network list based on all active subscriptions.
- *
- * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
- * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
- *
- * @hide
- * @see AllowedNetworkTypesChangedListener#onAllowedNetworkTypesChanged
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public static final int EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED = 35;
-
- /** @hide */
- @IntDef(prefix = { "EVENT_" }, value = {
- EVENT_SERVICE_STATE_CHANGED,
- EVENT_SIGNAL_STRENGTH_CHANGED,
- EVENT_MESSAGE_WAITING_INDICATOR_CHANGED,
- EVENT_CALL_FORWARDING_INDICATOR_CHANGED,
- EVENT_CELL_LOCATION_CHANGED,
- EVENT_CALL_STATE_CHANGED,
- EVENT_DATA_CONNECTION_STATE_CHANGED,
- EVENT_DATA_ACTIVITY_CHANGED,
- EVENT_SIGNAL_STRENGTHS_CHANGED,
- EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED,
- EVENT_CELL_INFO_CHANGED,
- EVENT_PRECISE_CALL_STATE_CHANGED,
- EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED,
- EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED,
- EVENT_OEM_HOOK_RAW,
- EVENT_SRVCC_STATE_CHANGED,
- EVENT_CARRIER_NETWORK_CHANGED,
- EVENT_VOICE_ACTIVATION_STATE_CHANGED,
- EVENT_DATA_ACTIVATION_STATE_CHANGED,
- EVENT_USER_MOBILE_DATA_STATE_CHANGED,
- EVENT_DISPLAY_INFO_CHANGED,
- EVENT_PHONE_CAPABILITY_CHANGED,
- EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED,
- EVENT_RADIO_POWER_STATE_CHANGED,
- EVENT_EMERGENCY_NUMBER_LIST_CHANGED,
- EVENT_CALL_DISCONNECT_CAUSE_CHANGED,
- EVENT_CALL_ATTRIBUTES_CHANGED,
- EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED,
- EVENT_OUTGOING_EMERGENCY_CALL,
- EVENT_OUTGOING_EMERGENCY_SMS,
- EVENT_REGISTRATION_FAILURE,
- EVENT_BARRING_INFO_CHANGED,
- EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED,
- EVENT_DATA_ENABLED_CHANGED,
- EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface TelephonyEvent {}
-
/*
* Subscription used to listen to the phone state changes
* @hide
@@ -1085,19 +515,16 @@
/**
* @hide
*/
- //TODO: The maxTargetSdk should be S if the build time tool updates it.
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
@UnsupportedAppUsage(
maxTargetSdk = Build.VERSION_CODES.R,
- publicAlternatives = "Use {@code TelephonyManager#registerPhoneStateListener(" +
- "Executor, PhoneStateListener)} instead")
- public IPhoneStateListener callback;
+ publicAlternatives = "Use {@code TelephonyManager#registerTelephonyCallback(" +
+ "Executor, TelephonyCallback)} instead")
+ public final IPhoneStateListener callback;
/**
* Create a PhoneStateListener for the Phone with the default subscription.
- * If this is created for use with deprecated API
- * {@link TelephonyManager#listen(PhoneStateListener, int)}, then this class requires
- * Looper.myLooper() not return null.
+ * This class requires Looper.myLooper() not return null.
*/
public PhoneStateListener() {
this(null, Looper.myLooper());
@@ -1135,10 +562,7 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public PhoneStateListener(Integer subId, Looper looper) {
- if (looper != null) {
- setExecutor(new HandlerExecutor(new Handler(looper)));
- }
- mSubId = subId;
+ this(subId, new HandlerExecutor(new Handler(looper)));
if (subId != null && VMRuntime.getRuntime().getTargetSdkVersion()
>= Build.VERSION_CODES.Q) {
throw new IllegalArgumentException("PhoneStateListener with subId: "
@@ -1153,783 +577,18 @@
* The Executor must not be null.
*
* @param executor a non-null Executor that will execute callbacks for the PhoneStateListener.
- * @deprecated Use
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)} instead.
*/
@Deprecated
public PhoneStateListener(@NonNull Executor executor) {
- setExecutor(executor);
- mSubId = null;
+ this(null, executor);
}
- private @NonNull Executor mExecutor;
-
- /**
- * @hide
- */
- public void setExecutor(@NonNull @CallbackExecutor Executor executor) {
- if (executor == null) {
+ private PhoneStateListener(Integer subId, Executor e) {
+ if (e == null) {
throw new IllegalArgumentException("PhoneStateListener Executor must be non-null");
}
- mExecutor = executor;
- callback = new IPhoneStateListenerStub(this, mExecutor);
- }
-
- /**
- * @hide
- */
- public boolean isExecutorSet() {
- return mExecutor != null;
- }
-
- /**
- * Interface for service state listener.
- */
- public interface ServiceStateChangedListener {
- /**
- * Callback invoked when device service state changes on the registered subscription.
- * Note, the registration subscription ID comes from {@link TelephonyManager} object
- * which registers PhoneStateListener by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- *
- * The instance of {@link ServiceState} passed as an argument here will have various
- * levels of location information stripped from it depending on the location permissions
- * that your app holds.
- * Only apps holding the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission will
- * receive all the information in {@link ServiceState}.
- *
- * @see ServiceState#STATE_EMERGENCY_ONLY
- * @see ServiceState#STATE_IN_SERVICE
- * @see ServiceState#STATE_OUT_OF_SERVICE
- * @see ServiceState#STATE_POWER_OFF
- */
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void onServiceStateChanged(@NonNull ServiceState serviceState);
- }
-
- /**
- * Interface for message waiting indicator listener.
- */
- public interface MessageWaitingIndicatorChangedListener {
- /**
- * Callback invoked when the message-waiting indicator changes on the registered
- * subscription.
- * Note, the registration subscription ID comes from {@link TelephonyManager} object by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- */
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public void onMessageWaitingIndicatorChanged(boolean mwi);
- }
-
- /**
- * Interface for call-forwarding indicator listener.
- */
- public interface CallForwardingIndicatorChangedListener {
- /**
- * Callback invoked when the call-forwarding indicator changes on the registered
- * subscription.
- * Note, the registration subscription ID comes from {@link TelephonyManager} object
- * which registers PhoneStateListener by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- */
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public void onCallForwardingIndicatorChanged(boolean cfi);
- }
-
- /**
- * Interface for device cell location listener.
- */
- public interface CellLocationChangedListener {
- /**
- * Callback invoked when device cell location changes on the registered subscription.
- * Note, the registration subscription ID comes from {@link TelephonyManager} object
- * which registers PhoneStateListener by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
- public void onCellLocationChanged(@NonNull CellLocation location);
- }
-
- /**
- * Interface for call state listener.
- */
- public interface CallStateChangedListener {
- /**
- * Callback invoked when device call state changes.
- * <p>
- * Reports the state of Telephony (mobile) calls on the device for the registered s
- * ubscription.
- * <p>
- * Note: the registration subscription ID comes from {@link TelephonyManager} object
- * which registers PhoneStateListener by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- * <p>
- * Note: The state returned here may differ from that returned by
- * {@link TelephonyManager#getCallState()}. Receivers of this callback should be aware that
- * calling {@link TelephonyManager#getCallState()} from within this callback may return a
- * different state than the callback reports.
- *
- * @param state call state
- * @param phoneNumber call phone number. If application does not have
- * {@link android.Manifest.permission#READ_CALL_LOG} permission or carrier
- * privileges (see {@link TelephonyManager#hasCarrierPrivileges}), an empty string will be
- * passed as an argument.
- */
- @RequiresPermission(android.Manifest.permission.READ_CALL_LOG)
- public void onCallStateChanged(@CallState int state, @Nullable String phoneNumber);
- }
-
- /**
- * Interface for data connection state listener.
- */
- public interface DataConnectionStateChangedListener {
- /**
- * Callback invoked when connection state changes on the registered subscription.
- * Note, the registration subscription ID comes from {@link TelephonyManager} object
- * which registers PhoneStateListener by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- *
- * @see TelephonyManager#DATA_DISCONNECTED
- * @see TelephonyManager#DATA_CONNECTING
- * @see TelephonyManager#DATA_CONNECTED
- * @see TelephonyManager#DATA_SUSPENDED
- *
- * @param state is the current state of data connection.
- * @param networkType is the current network type of data connection.
- */
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void onDataConnectionStateChanged(@DataState int state,
- @NetworkType int networkType);
- }
-
- /**
- * Interface for data activity state listener.
- */
- public interface DataActivityListener {
- /**
- * Callback invoked when data activity state changes on the registered subscription.
- * Note, the registration subscription ID comes from {@link TelephonyManager} object
- * which registers PhoneStateListener by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- *
- * @see TelephonyManager#DATA_ACTIVITY_NONE
- * @see TelephonyManager#DATA_ACTIVITY_IN
- * @see TelephonyManager#DATA_ACTIVITY_OUT
- * @see TelephonyManager#DATA_ACTIVITY_INOUT
- * @see TelephonyManager#DATA_ACTIVITY_DORMANT
- */
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void onDataActivity(@DataActivityType int direction);
- }
-
- /**
- * Interface for network signal strengths listener.
- */
- public interface SignalStrengthsChangedListener {
- /**
- * Callback invoked when network signal strengths changes on the registered subscription.
- * Note, the registration subscription ID comes from {@link TelephonyManager} object
- * which registers PhoneStateListener by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- */
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength);
- }
-
- /**
- * Interface for network signal strengths listener which always reported from modem.
- */
- public interface AlwaysReportedSignalStrengthChangedListener {
- /**
- * Callback always invoked from modem when network signal strengths changes on the
- * registered subscription.
- * Note, the registration subscription ID comes from {@link TelephonyManager} object
- * which registers PhoneStateListener by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- */
- @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
- public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength);
- }
-
- /**
- * Interface for cell info listener.
- */
- public interface CellInfoChangedListener {
- /**
- * Callback invoked when a observed cell info has changed or new cells have been added
- * or removed on the registered subscription.
- * Note, the registration subscription ID s from {@link TelephonyManager} object
- * which registersPhoneStateListener by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- *
- * @param cellInfo is the list of currently visible cells.
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
- public void onCellInfoChanged(@NonNull List<CellInfo> cellInfo);
- }
-
- /**
- * Interface for precise device call state listener.
- *
- * @hide
- */
- @SystemApi
- public interface PreciseCallStateChangedListener {
- /**
- * Callback invoked when precise device call state changes on the registered subscription.
- * Note, the registration subscription ID comes from {@link TelephonyManager} object
- * which registers PhoneStateListener by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- *
- * @param callState {@link PreciseCallState}
- */
- @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
- public void onPreciseCallStateChanged(@NonNull PreciseCallState callState);
- }
-
- /**
- * Interface for call disconnect cause listener.
- */
- public interface CallDisconnectCauseChangedListener {
- /**
- * Callback invoked when call disconnect cause changes on the registered subscription.
- * Note, the registration subscription ID comes from {@link TelephonyManager} object
- * which registers PhoneStateListener by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- *
- * @param disconnectCause {@link DisconnectCause}.
- * @param preciseDisconnectCause {@link PreciseDisconnectCause}.
- */
- @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
- public void onCallDisconnectCauseChanged(@DisconnectCauses int disconnectCause,
- @PreciseDisconnectCauses int preciseDisconnectCause);
- }
-
- /**
- * Interface for IMS call disconnect cause listener.
- */
- public interface ImsCallDisconnectCauseChangedListener {
- /**
- * Callback invoked when IMS call disconnect cause changes on the registered subscription.
- * Note, the registration subscription ID comes from {@link TelephonyManager} object
- * which registers PhoneStateListener by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- *
- * @param imsReasonInfo {@link ImsReasonInfo} contains details on why IMS call failed.
- *
- */
- @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
- public void onImsCallDisconnectCauseChanged(@NonNull ImsReasonInfo imsReasonInfo);
- }
-
- /**
- * Interface for precise data connection state listener.
- */
- public interface PreciseDataConnectionStateChangedListener {
- /**
- * Callback providing update about the default/internet data connection on the registered
- * subscription.
- *
- * Note, the registration subscription ID comes from {@link TelephonyManager} object
- * which registers PhoneStateListener by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- *
- * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
- * or the calling app has carrier privileges
- * (see {@link TelephonyManager#hasCarrierPrivileges}).
- *
- * @param dataConnectionState {@link PreciseDataConnectionState}
- */
- @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
- public void onPreciseDataConnectionStateChanged(
- @NonNull PreciseDataConnectionState dataConnectionState);
- }
-
- /**
- * Interface for Single Radio Voice Call Continuity listener.
- *
- * @hide
- */
- @SystemApi
- public interface SrvccStateChangedListener {
- /**
- * Callback invoked when there has been a change in the Single Radio Voice Call Continuity
- * (SRVCC) state for the currently active call on the registered subscription.
- *
- * Note, the registration subscription ID comes from {@link TelephonyManager} object
- * which registers PhoneStateListener by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- */
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public void onSrvccStateChanged(@SrvccState int srvccState);
- }
-
- /**
- * Interface for SIM voice activation state listener.
- *
- * @hide
- */
- @SystemApi
- public interface VoiceActivationStateChangedListener {
- /**
- * Callback invoked when the SIM voice activation state has changed on the registered
- * subscription.
- * Note, the registration subscription ID comes from {@link TelephonyManager} object
- * which registers PhoneStateListener by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- *
- * @param state is the current SIM voice activation state
- */
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public void onVoiceActivationStateChanged(@SimActivationState int state);
-
- }
-
- /**
- * Interface for SIM data activation state listener.
- */
- public interface DataActivationStateChangedListener {
- /**
- * Callback invoked when the SIM data activation state has changed on the registered
- * subscription.
- * Note, the registration subscription ID comes from {@link TelephonyManager} object
- * which registers PhoneStateListener by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- *
- * @param state is the current SIM data activation state
- */
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void onDataActivationStateChanged(@SimActivationState int state);
- }
-
- /**
- * Interface for user mobile data state listener.
- */
- public interface UserMobileDataStateChangedListener {
- /**
- * Callback invoked when the user mobile data state has changed on the registered
- * subscription.
- * Note, the registration subscription ID comes from {@link TelephonyManager} object
- * which registers PhoneStateListener by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- *
- * @param enabled indicates whether the current user mobile data state is enabled or
- * disabled.
- */
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void onUserMobileDataStateChanged(boolean enabled);
- }
-
- /**
- * Interface for display info listener.
- */
- public interface DisplayInfoChangedListener {
- /**
- * Callback invoked when the display info has changed on the registered subscription.
- * <p> The {@link TelephonyDisplayInfo} contains status information shown to the user
- * based on carrier policy.
- *
- * @param telephonyDisplayInfo The display information.
- */
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo telephonyDisplayInfo);
- }
-
- /**
- * Interface for the current emergency number list listener.
- */
- public interface EmergencyNumberListChangedListener {
- /**
- * Callback invoked when the current emergency number list has changed on the registered
- * subscription.
- *
- * Note, the registered subscription is associated with {@link TelephonyManager} object
- * on which
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}
- * was called.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * given subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- *
- * @param emergencyNumberList Map associating all active subscriptions on the device with
- * the list of emergency numbers originating from that
- * subscription.
- * If there are no active subscriptions, the map will contain a
- * single entry with
- * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} as
- * the key and a list of emergency numbers as the value. If no
- * emergency number information is available, the value will be
- * empty.
- */
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public void onEmergencyNumberListChanged(
- @NonNull Map<Integer, List<EmergencyNumber>> emergencyNumberList);
- }
-
- /**
- * Interface for outgoing emergency call listener.
- *
- * @hide
- */
- @SystemApi
- public interface OutgoingEmergencyCallListener {
- /**
- * Callback invoked when an outgoing call is placed to an emergency number.
- *
- * This method will be called when an emergency call is placed on any subscription
- * (including the no-SIM case), regardless of which subscription this listener was
- * registered on.
- *
- * The default implementation of this method calls
- * {@link #onOutgoingEmergencyCall(EmergencyNumber)} for backwards compatibility purposes.
- * Do not call {@code super(...)} from within your implementation unless you want
- * {@link #onOutgoingEmergencyCall(EmergencyNumber)} to be called as well.
- *
- * @param placedEmergencyNumber The {@link EmergencyNumber} the emergency call was
- * placed to.
- * @param subscriptionId The subscription ID used to place the emergency call. If the
- * emergency call was placed without a valid subscription
- * (e.g. when there are no SIM cards in the device), this will be
- * equal to {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
- */
- @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
- public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber,
- int subscriptionId);
- }
-
- /**
- * Interface for outgoing emergency sms listener.
- *
- * @hide
- */
- @SystemApi
- public interface OutgoingEmergencySmsListener {
- /**
- * Smsback invoked when an outgoing sms is sent to an emergency number.
- *
- * This method will be called when an emergency sms is sent on any subscription,
- * regardless of which subscription this listener was registered on.
- *
- * The default implementation of this method calls
- * {@link #onOutgoingEmergencySms(EmergencyNumber)} for backwards compatibility purposes. Do
- * not call {@code super(...)} from within your implementation unless you want
- * {@link #onOutgoingEmergencySms(EmergencyNumber)} to be called as well.
- *
- * @param sentEmergencyNumber The {@link EmergencyNumber} the emergency sms was sent to.
- * @param subscriptionId The subscription ID used to send the emergency sms.
- */
- @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
- public void onOutgoingEmergencySms(@NonNull EmergencyNumber sentEmergencyNumber,
- int subscriptionId);
- }
-
- /**
- * Interface for phone capability listener.
- * @hide
- */
- @SystemApi
- public interface PhoneCapabilityChangedListener {
- /**
- * Callback invoked when phone capability changes.
- * Note, this callback triggers regardless of registered subscription.
- *
- * @param capability the new phone capability
- */
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void onPhoneCapabilityChanged(@NonNull PhoneCapability capability);
- }
-
- /**
- * Interface for active data subscription ID listener.
- */
- public interface ActiveDataSubscriptionIdChangedListener {
- /**
- * Callback invoked when active data subscription ID changes.
- * Note, this callback triggers regardless of registered subscription.
- *
- * @param subId current subscription used to setup Cellular Internet data.
- * For example, it could be the current active opportunistic subscription
- * in use, or the subscription user selected as default data subscription in
- * DSDS mode.
- */
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public void onActiveDataSubscriptionIdChanged(int subId);
- }
-
- /**
- * Interface for modem radio power state listener.
- *
- * @hide
- */
- @SystemApi
- public interface RadioPowerStateChangedListener {
- /**
- * Callback invoked when modem radio power state changes on the registered subscription.
- * Note, the registration subscription ID comes from {@link TelephonyManager} object
- * which registers PhoneStateListener by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- *
- * @param state the modem radio power state
- */
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public void onRadioPowerStateChanged(@RadioPowerState int state);
- }
-
- /**
- * Interface for carrier network listener.
- */
- public interface CarrierNetworkChangeListener {
- /**
- * Callback invoked when telephony has received notice from a carrier
- * app that a network action that could result in connectivity loss
- * has been requested by an app using
- * {@link android.service.carrier.CarrierService#notifyCarrierNetworkChange(boolean)}
- *
- * This is optional and is only used to allow the system to provide alternative UI while
- * telephony is performing an action that may result in intentional, temporary network
- * lack of connectivity.
- *
- * Note, this callback is pinned to the registered subscription and will be invoked when
- * the notifying carrier app has carrier privilege rule on the registered
- * subscription. {@link android.telephony.TelephonyManager#hasCarrierPrivileges}
- *
- * @param active If the carrier network change is or shortly will be active,
- * {@code true} indicate that showing alternative UI, {@code false} otherwise.
- */
- public void onCarrierNetworkChange(boolean active);
- }
-
- /**
- * Interface for registration failures listener.
- */
- public interface RegistrationFailedListener {
- /**
- * Report that Registration or a Location/Routing/Tracking Area update has failed.
- *
- * <p>Indicate whenever a registration procedure, including a location, routing, or tracking
- * area update fails. This includes procedures that do not necessarily result in a change of
- * the modem's registration status. If the modem's registration status changes, that is
- * reflected in the onNetworkStateChanged() and subsequent
- * get{Voice/Data}RegistrationState().
- *
- * <p>Because registration failures are ephemeral, this callback is not sticky.
- * Registrants will not receive the most recent past value when registering.
- *
- * @param cellIdentity the CellIdentity, which must include the globally unique identifier
- * for the cell (for example, all components of the CGI or ECGI).
- * @param chosenPlmn a 5 or 6 digit alphanumeric PLMN (MCC|MNC) among those broadcast by the
- * cell that was chosen for the failed registration attempt.
- * @param domain DOMAIN_CS, DOMAIN_PS or both in case of a combined procedure.
- * @param causeCode the primary failure cause code of the procedure.
- * For GSM/UMTS (MM), values are in TS 24.008 Sec 10.5.95
- * For GSM/UMTS (GMM), values are in TS 24.008 Sec 10.5.147
- * For LTE (EMM), cause codes are TS 24.301 Sec 9.9.3.9
- * For NR (5GMM), cause codes are TS 24.501 Sec 9.11.3.2
- * Integer.MAX_VALUE if this value is unused.
- * @param additionalCauseCode the cause code of any secondary/combined procedure
- * if appropriate. For UMTS, if a combined attach succeeds for
- * PS only, then the GMM cause code shall be included as an
- * additionalCauseCode. For LTE (ESM), cause codes are in
- * TS 24.301 9.9.4.4. Integer.MAX_VALUE if this value is unused.
- */
- @RequiresPermission(allOf = {
- Manifest.permission.READ_PRECISE_PHONE_STATE,
- Manifest.permission.ACCESS_FINE_LOCATION
- })
- public void onRegistrationFailed(@NonNull CellIdentity cellIdentity,
- @NonNull String chosenPlmn, @Domain int domain,
- int causeCode, int additionalCauseCode);
- }
-
- /**
- * Interface for the current allowed network type list listener. This list involves values of
- * allowed network type for each of reasons.
- *
- * @hide
- */
- @SystemApi
- public interface AllowedNetworkTypesChangedListener {
- /**
- * Callback invoked when the current allowed network type list has changed on the
- * registered subscription.
- * Note, the registered subscription is associated with {@link TelephonyManager} object
- * on which
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}
- * was called.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * given subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- *
- * @param allowedNetworkTypesList Map associating all allowed network type reasons
- * ({@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER},
- * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER},
- * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER}, and
- * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G}) with reason's allowed
- * network type values.
- * For example:
- * map{{TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER, long type value},
- * {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER, long type value},
- * {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER, long type value},
- * {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G, long type value}}
- */
- @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- void onAllowedNetworkTypesChanged(
- @NonNull Map<Integer, Long> allowedNetworkTypesList);
- }
-
- /**
- * Interface for call attributes listener.
- *
- * @hide
- */
- @SystemApi
- public interface CallAttributesChangedListener {
- /**
- * Callback invoked when the call attributes changes on the registered subscription.
- * Note, the registration subscription ID comes from {@link TelephonyManager} object
- * which registers PhoneStateListener by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
- * If this TelephonyManager object was created with
- * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subscription ID. Otherwise, this callback applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}.
- *
- * @param callAttributes the call attributes
- */
- @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
- void onCallAttributesChanged(@NonNull CallAttributes callAttributes);
- }
-
- /**
- * Interface for barring information listener.
- */
- public interface BarringInfoChangedListener {
- /**
- * Report updated barring information for the current camped/registered cell.
- *
- * <p>Barring info is provided for all services applicable to the current camped/registered
- * cell, for the registered PLMN and current access class/access category.
- *
- * @param barringInfo for all services on the current cell.
- * @see android.telephony.BarringInfo
- */
- @RequiresPermission(allOf = {
- Manifest.permission.READ_PRECISE_PHONE_STATE,
- Manifest.permission.ACCESS_FINE_LOCATION
- })
- public void onBarringInfoChanged(@NonNull BarringInfo barringInfo);
- }
-
- /**
- * Interface for current physical channel configuration listener.
- * @hide
- */
- @SystemApi
- public interface PhysicalChannelConfigChangedListener {
- /**
- * Callback invoked when the current physical channel configuration has changed
- *
- * @param configs List of the current {@link PhysicalChannelConfig}s
- */
- @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
- public void onPhysicalChannelConfigChanged(@NonNull List<PhysicalChannelConfig> configs);
- }
-
- /**
- * Interface for data enabled listener.
- *
- * @hide
- */
- @SystemApi
- public interface DataEnabledChangedListener {
- /**
- * Callback invoked when the data enabled changes.
- *
- * @param enabled {@code true} if data is enabled, otherwise disabled.
- * @param reason Reason for data enabled/disabled.
- * See {@link TelephonyManager.DataEnabledReason}.
- */
- @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
- public void onDataEnabledChanged(boolean enabled,
- @DataEnabledReason int reason);
+ mSubId = subId;
+ callback = new IPhoneStateListenerStub(this, e);
}
/**
@@ -1950,7 +609,9 @@
* @see ServiceState#STATE_IN_SERVICE
* @see ServiceState#STATE_OUT_OF_SERVICE
* @see ServiceState#STATE_POWER_OFF
+ * @deprecated Use {@link TelephonyCallback.ServiceStateListener} instead.
*/
+ @Deprecated
public void onServiceStateChanged(ServiceState serviceState) {
// default implementation empty
}
@@ -1983,7 +644,10 @@
* {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
* subId. Otherwise, this callback applies to
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @deprecated Use {@link TelephonyCallback.MessageWaitingIndicatorListener} instead.
*/
+ @Deprecated
public void onMessageWaitingIndicatorChanged(boolean mwi) {
// default implementation empty
}
@@ -1996,7 +660,10 @@
* {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
* subId. Otherwise, this callback applies to
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @deprecated Use {@link TelephonyCallback.CallForwardingIndicatorListener} instead.
*/
+ @Deprecated
public void onCallForwardingIndicatorChanged(boolean cfi) {
// default implementation empty
}
@@ -2009,7 +676,10 @@
* {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
* subId. Otherwise, this callback applies to
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @deprecated Use {@link TelephonyCallback.CellLocationListener} instead.
*/
+ @Deprecated
public void onCellLocationChanged(CellLocation location) {
// default implementation empty
}
@@ -2036,7 +706,10 @@
* {@link android.Manifest.permission#READ_CALL_LOG READ_CALL_LOG} permission or carrier
* privileges (see {@link TelephonyManager#hasCarrierPrivileges}), an empty string will be
* passed as an argument.
+ *
+ * @deprecated Use {@link TelephonyCallback.CallStateListener} instead.
*/
+ @Deprecated
public void onCallStateChanged(@CallState int state, String phoneNumber) {
// default implementation empty
}
@@ -2054,14 +727,19 @@
* @see TelephonyManager#DATA_CONNECTING
* @see TelephonyManager#DATA_CONNECTED
* @see TelephonyManager#DATA_SUSPENDED
+ * @deprecated Use {@link TelephonyCallback.DataConnectionStateListener} instead.
*/
+ @Deprecated
public void onDataConnectionStateChanged(int state) {
// default implementation empty
}
/**
* same as above, but with the network type. Both called.
+ *
+ * @deprecated Use {@link TelephonyCallback.DataConnectionStateListener} instead.
*/
+ @Deprecated
public void onDataConnectionStateChanged(int state, int networkType) {
// default implementation empty
}
@@ -2080,7 +758,9 @@
* @see TelephonyManager#DATA_ACTIVITY_OUT
* @see TelephonyManager#DATA_ACTIVITY_INOUT
* @see TelephonyManager#DATA_ACTIVITY_DORMANT
+ * @deprecated Use {@link TelephonyCallback.DataActivityListener} instead.
*/
+ @Deprecated
public void onDataActivity(int direction) {
// default implementation empty
}
@@ -2093,7 +773,10 @@
* {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
* subId. Otherwise, this callback applies to
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @deprecated Use {@link TelephonyCallback.SignalStrengthsListener} instead.
*/
+ @Deprecated
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
// default implementation empty
}
@@ -2109,7 +792,9 @@
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*
* @param cellInfo is the list of currently visible cells.
+ * @deprecated Use {@link TelephonyCallback.CellInfoListener} instead.
*/
+ @Deprecated
public void onCellInfoChanged(List<CellInfo> cellInfo) {
// default implementation empty
}
@@ -2122,11 +807,14 @@
* {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
* subId. Otherwise, this callback applies to
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
* @param callState {@link PreciseCallState}
* @hide
+ * @deprecated Use {@link TelephonyCallback.PreciseCallStateListener} instead.
*/
@RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
@SystemApi
+ @Deprecated
public void onPreciseCallStateChanged(@NonNull PreciseCallState callState) {
// default implementation empty
}
@@ -2142,9 +830,10 @@
*
* @param disconnectCause {@link DisconnectCause}.
* @param preciseDisconnectCause {@link PreciseDisconnectCause}.
- *
+ * @deprecated Use {@link TelephonyCallback.CallDisconnectCauseListener} instead.
*/
@RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ @Deprecated
public void onCallDisconnectCauseChanged(@DisconnectCauses int disconnectCause,
@PreciseDisconnectCauses int preciseDisconnectCause) {
// default implementation empty
@@ -2160,9 +849,10 @@
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*
* @param imsReasonInfo {@link ImsReasonInfo} contains details on why IMS call failed.
- *
+ * @deprecated Use {@link TelephonyCallback.ImsCallDisconnectCauseListener} instead.
*/
@RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ @Deprecated
public void onImsCallDisconnectCauseChanged(@NonNull ImsReasonInfo imsReasonInfo) {
// default implementation empty
}
@@ -2183,8 +873,10 @@
* (see {@link TelephonyManager#hasCarrierPrivileges}).
*
* @param dataConnectionState {@link PreciseDataConnectionState}
+ * @deprecated Use {@link TelephonyCallback.PreciseDataConnectionStateListener} instead.
*/
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @Deprecated
public void onPreciseDataConnectionStateChanged(
@NonNull PreciseDataConnectionState dataConnectionState) {
// default implementation empty
@@ -2200,8 +892,10 @@
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*
* @hide
+ * @deprecated Use {@link TelephonyManager#requestModemActivityInfo}
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Deprecated
public void onDataConnectionRealTimeInfoChanged(
DataConnectionRealTimeInfo dcRtInfo) {
// default implementation empty
@@ -2219,11 +913,12 @@
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*
* @hide
+ * @deprecated Use {@link TelephonyCallback.SrvccStateListener} instead.
*/
@SystemApi
+ @Deprecated
public void onSrvccStateChanged(@SrvccState int srvccState) {
// default implementation empty
-
}
/**
@@ -2238,8 +933,10 @@
*
* @param state is the current SIM voice activation state
* @hide
+ * @deprecated Use {@link TelephonyCallback.VoiceActivationStateListener} instead.
*/
@SystemApi
+ @Deprecated
public void onVoiceActivationStateChanged(@SimActivationState int state) {
// default implementation empty
}
@@ -2256,7 +953,9 @@
*
* @param state is the current SIM data activation state
* @hide
+ * @deprecated Use {@link TelephonyCallback.DataActivationStateListener} instead.
*/
+ @Deprecated
public void onDataActivationStateChanged(@SimActivationState int state) {
// default implementation empty
}
@@ -2271,7 +970,9 @@
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*
* @param enabled indicates whether the current user mobile data state is enabled or disabled.
+ * @deprecated Use {@link TelephonyCallback.UserMobileDataStateListener} instead.
*/
+ @Deprecated
public void onUserMobileDataStateChanged(boolean enabled) {
// default implementation empty
}
@@ -2285,8 +986,10 @@
* app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
*
* @param telephonyDisplayInfo The display information.
+ * @deprecated Use {@link TelephonyCallback.DisplayInfoListener} instead.
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @Deprecated
public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo telephonyDisplayInfo) {
// default implementation empty
}
@@ -2309,7 +1012,9 @@
* {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} as
* the key and a list of emergency numbers as the value. If no
* emergency number information is available, the value will be null.
+ * @deprecated Use {@link TelephonyCallback.EmergencyNumberListListener} instead.
*/
+ @Deprecated
public void onEmergencyNumberListChanged(
@NonNull Map<Integer, List<EmergencyNumber>> emergencyNumberList) {
// default implementation empty
@@ -2322,7 +1027,6 @@
* the no-SIM case), regardless of which subscription this listener was registered on.
*
* @param placedEmergencyNumber The {@link EmergencyNumber} the emergency call was placed to.
- *
* @deprecated Use {@link #onOutgoingEmergencyCall(EmergencyNumber, int)}.
* @hide
*/
@@ -2349,8 +1053,10 @@
* are no SIM cards in the device), this will be equal to
* {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
* @hide
+ * @deprecated Use {@link TelephonyCallback.OutgoingEmergencyCallListener} instead.
*/
@SystemApi
+ @Deprecated
public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber,
int subscriptionId) {
// Default implementation for backwards compatibility
@@ -2365,6 +1071,7 @@
*
* @deprecated Use {@link #onOutgoingEmergencySms(EmergencyNumber, int)}.
* @hide
+ * @deprecated Use {@link TelephonyCallback.OutgoingEmergencySmsListener} instead.
*/
@SystemApi
@Deprecated
@@ -2386,8 +1093,10 @@
* @param sentEmergencyNumber The {@link EmergencyNumber} the emergency sms was sent to.
* @param subscriptionId The subscription ID used to send the emergency sms.
* @hide
+ * @deprecated Use {@link TelephonyCallback.OutgoingEmergencySmsListener} instead.
*/
@SystemApi
+ @Deprecated
public void onOutgoingEmergencySms(@NonNull EmergencyNumber sentEmergencyNumber,
int subscriptionId) {
// Default implementation for backwards compatibility
@@ -2397,8 +1106,7 @@
/**
* Callback invoked when OEM hook raw event is received on the registered subscription.
* Note, the registration subId comes from {@link TelephonyManager} object which registers
- * PhoneStateListener by
- * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * PhoneStateListener by {@link TelephonyManager#listen(PhoneStateListener, int)}.
* If this TelephonyManager object was created with
* {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
* subId. Otherwise, this callback applies to
@@ -2407,8 +1115,10 @@
* Requires the READ_PRIVILEGED_PHONE_STATE permission.
* @param rawData is the byte array of the OEM hook raw data.
* @hide
+ * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Deprecated
public void onOemHookRawEvent(byte[] rawData) {
// default implementation empty
}
@@ -2419,7 +1129,9 @@
*
* @param capability the new phone capability
* @hide
+ * @deprecated Use {@link TelephonyCallback.PhoneCapabilityListener} instead.
*/
+ @Deprecated
public void onPhoneCapabilityChanged(@NonNull PhoneCapability capability) {
// default implementation empty
}
@@ -2432,7 +1144,9 @@
* @param subId current subscription used to setup Cellular Internet data.
* For example, it could be the current active opportunistic subscription in use,
* or the subscription user selected as default data subscription in DSDS mode.
+ * @deprecated Use {@link TelephonyCallback.ActiveDataSubscriptionIdListener} instead.
*/
+ @Deprecated
public void onActiveDataSubscriptionIdChanged(int subId) {
// default implementation empty
}
@@ -2449,8 +1163,10 @@
* Requires the READ_PRECISE_PHONE_STATE permission.
* @param callAttributes the call attributes
* @hide
+ * @deprecated Use {@link TelephonyCallback.CallAttributesListener} instead.
*/
@SystemApi
+ @Deprecated
public void onCallAttributesChanged(@NonNull CallAttributes callAttributes) {
// default implementation empty
}
@@ -2468,8 +1184,10 @@
*
* @param state the modem radio power state
* @hide
+ * @deprecated Use {@link TelephonyCallback.RadioPowerStateListener} instead.
*/
@SystemApi
+ @Deprecated
public void onRadioPowerStateChanged(@RadioPowerState int state) {
// default implementation empty
}
@@ -2487,9 +1205,10 @@
* @param active Whether the carrier network change is or shortly
* will be active. This value is true to indicate
* showing alternative UI and false to stop.
- *
* @hide
+ * @deprecated Use {@link TelephonyCallback.CarrierNetworkListener} instead.
*/
+ @Deprecated
public void onCarrierNetworkChange(boolean active) {
// default implementation empty
}
@@ -2520,7 +1239,9 @@
* For UMTS, if a combined attach succeeds for PS only, then the GMM cause code shall be
* included as an additionalCauseCode. For LTE (ESM), cause codes are in
* TS 24.301 9.9.4.4. Integer.MAX_VALUE if this value is unused.
+ * @deprecated Use {@link TelephonyCallback.RegistrationFailedListener} instead.
*/
+ @Deprecated
public void onRegistrationFailed(@NonNull CellIdentity cellIdentity, @NonNull String chosenPlmn,
int domain, int causeCode, int additionalCauseCode) {
// default implementation empty
@@ -2533,9 +1254,10 @@
* cell, for the registered PLMN and current access class/access category.
*
* @param barringInfo for all services on the current cell.
- *
* @see android.telephony.BarringInfo
+ * @deprecated Use {@link TelephonyCallback.BarringInfoListener} instead.
*/
+ @Deprecated
public void onBarringInfoChanged(@NonNull BarringInfo barringInfo) {
// default implementation empty
}
@@ -2831,7 +1553,7 @@
Binder.withCleanCallingIdentity(
() -> mExecutor.execute(() -> psl.onRegistrationFailed(
- cellIdentity, chosenPlmn, domain, causeCode, additionalCauseCode)));
+ cellIdentity, chosenPlmn, domain, causeCode, additionalCauseCode)));
// default implementation empty
}
@@ -2844,33 +1566,15 @@
}
public void onPhysicalChannelConfigChanged(List<PhysicalChannelConfig> configs) {
- PhysicalChannelConfigChangedListener listener =
- (PhysicalChannelConfigChangedListener) mPhoneStateListenerWeakRef.get();
- if (listener == null) return;
-
- Binder.withCleanCallingIdentity(
- () -> mExecutor.execute(() -> listener.onPhysicalChannelConfigChanged(
- configs)));
+ // default implementation empty
}
public void onDataEnabledChanged(boolean enabled, @DataEnabledReason int reason) {
- DataEnabledChangedListener listener =
- (DataEnabledChangedListener) mPhoneStateListenerWeakRef.get();
- if (listener == null) return;
-
- Binder.withCleanCallingIdentity(
- () -> mExecutor.execute(() -> listener.onDataEnabledChanged(
- enabled, reason)));
+ // default implementation empty
}
public void onAllowedNetworkTypesChanged(Map allowedNetworkTypesList) {
- AllowedNetworkTypesChangedListener listener =
- (AllowedNetworkTypesChangedListener) mPhoneStateListenerWeakRef.get();
- if (listener == null) return;
-
- Binder.withCleanCallingIdentity(
- () -> mExecutor.execute(
- () -> listener.onAllowedNetworkTypesChanged(allowedNetworkTypesList)));
+ // default implementation empty
}
}
diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java
new file mode 100644
index 0000000..a2584cae
--- /dev/null
+++ b/core/java/android/telephony/TelephonyCallback.java
@@ -0,0 +1,1710 @@
+/*
+ * Copyright (C) 2021 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 android.telephony;
+
+import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.os.Binder;
+import android.os.Build;
+import android.telephony.emergency.EmergencyNumber;
+import android.telephony.ims.ImsReasonInfo;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.IPhoneStateListener;
+
+import dalvik.system.VMRuntime;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+/**
+ * A callback class for monitoring changes in specific telephony states
+ * on the device, including service state, signal strength, message
+ * waiting indicator (voicemail), and others.
+ * <p>
+ * To register a callback, use a {@link TelephonyCallback} which implements interfaces regarding
+ * EVENT_*. For example,
+ * FakeServiceStateCallback extends {@link TelephonyCallback} implements
+ * {@link TelephonyCallback.ServiceStateListener}.
+ * <p>
+ * Then override the methods for the state that you wish to receive updates for, and
+ * pass the executor and your TelephonyCallback object to
+ * {@link TelephonyManager#registerTelephonyCallback}.
+ * Methods are called when the state changes, as well as once on initial registration.
+ * <p>
+ * Note that access to some telephony information is
+ * permission-protected. Your application won't receive updates for protected
+ * information unless it has the appropriate permissions declared in
+ * its manifest file. Where permissions apply, they are noted in the
+ * appropriate sub-interfaces.
+ */
+public class TelephonyCallback {
+
+ /**
+ * Experiment flag to set the per-pid registration limit for TelephonyCallback
+ *
+ * Limit on registrations of {@link TelephonyCallback}s on a per-pid basis. When this limit is
+ * exceeded, any calls to {@link TelephonyManager#registerTelephonyCallback} will fail with an
+ * {@link IllegalStateException}.
+ *
+ * {@link android.os.Process#PHONE_UID}, {@link android.os.Process#SYSTEM_UID}, and the uid that
+ * TelephonyRegistry runs under are exempt from this limit.
+ *
+ * If the value of the flag is less than 1, enforcement of the limit will be disabled.
+ * @hide
+ */
+ public static final String FLAG_PER_PID_REGISTRATION_LIMIT =
+ "phone_state_listener_per_pid_registration_limit";
+
+ /**
+ * Default value for the per-pid registration limit.
+ * See {@link #FLAG_PER_PID_REGISTRATION_LIMIT}.
+ * @hide
+ */
+ public static final int DEFAULT_PER_PID_REGISTRATION_LIMIT = 50;
+
+ /**
+ * This change enables a limit on the number of {@link TelephonyCallback} objects any process
+ * may register via {@link TelephonyManager#registerTelephonyCallback}. The default limit is 50,
+ * which may change via remote device config updates.
+ *
+ * This limit is enforced via an {@link IllegalStateException} thrown from
+ * {@link TelephonyManager#registerTelephonyCallback} when the offending process attempts to
+ * register one too many callbacks.
+ *
+ * @hide
+ */
+ @ChangeId
+ public static final long PHONE_STATE_LISTENER_LIMIT_CHANGE_ID = 150880553L;
+
+ /**
+ * Event for changes to the network service state (cellular).
+ *
+ * @hide
+ * @see ServiceStateListener#onServiceStateChanged
+ * @see ServiceState
+ */
+ @SystemApi
+ public static final int EVENT_SERVICE_STATE_CHANGED = 1;
+
+ /**
+ * Event for changes to the network signal strength (cellular).
+ *
+ * @hide
+ * @see SignalStrengthsListener#onSignalStrengthsChanged
+ */
+ @SystemApi
+ public static final int EVENT_SIGNAL_STRENGTH_CHANGED = 2;
+
+ /**
+ * Event for changes to the message-waiting indicator.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE} or that
+ * the calling app has carrier privileges (see
+ * {@link TelephonyManager#hasCarrierPrivileges}).
+ * <p>
+ * Example: The status bar uses this to determine when to display the
+ * voicemail icon.
+ *
+ * @hide
+ * @see MessageWaitingIndicatorListener#onMessageWaitingIndicatorChanged
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public static final int EVENT_MESSAGE_WAITING_INDICATOR_CHANGED = 3;
+
+ /**
+ * Event for changes to the call-forwarding indicator.
+ * <p>
+ * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE} or that
+ * the calling app has carrier privileges (see
+ * {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @hide
+ * @see CallForwardingIndicatorListener#onCallForwardingIndicatorChanged
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public static final int EVENT_CALL_FORWARDING_INDICATOR_CHANGED = 4;
+
+ /**
+ * Event for changes to the device's cell location. Note that
+ * this will result in frequent listeners to the listener.
+ * <p>
+ * If you need regular location updates but want more control over
+ * the update interval or location precision, you can set up a callback
+ * through the {@link android.location.LocationManager location manager}
+ * instead.
+ *
+ * @hide
+ * @see CellLocationListener#onCellLocationChanged
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
+ public static final int EVENT_CELL_LOCATION_CHANGED = 5;
+
+ /**
+ * Event for changes to the device call state.
+ *
+ * @hide
+ * @see CallStateListener#onCallStateChanged
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_CALL_LOG)
+ public static final int EVENT_CALL_STATE_CHANGED = 6;
+
+ /**
+ * Event for changes to the data connection state (cellular).
+ *
+ * @hide
+ * @see DataConnectionStateListener#onDataConnectionStateChanged
+ */
+ @SystemApi
+ public static final int EVENT_DATA_CONNECTION_STATE_CHANGED = 7;
+
+ /**
+ * Event for changes to the direction of data traffic on the data
+ * connection (cellular).
+ * <p>
+ * Example: The status bar uses this to display the appropriate
+ * data-traffic icon.
+ *
+ * @hide
+ * @see DataActivityListener#onDataActivity
+ */
+ @SystemApi
+ public static final int EVENT_DATA_ACTIVITY_CHANGED = 8;
+
+ /**
+ * Event for changes to the network signal strengths (cellular).
+ * <p>
+ * Example: The status bar uses this to control the signal-strength
+ * icon.
+ *
+ * @hide
+ * @see SignalStrengthsListener#onSignalStrengthsChanged
+ */
+ @SystemApi
+ public static final int EVENT_SIGNAL_STRENGTHS_CHANGED = 9;
+
+ /**
+ * Event for changes of the network signal strengths (cellular) always reported from modem,
+ * even in some situations such as the screen of the device is off.
+ *
+ * @hide
+ * @see AlwaysReportedSignalStrengthListener#onSignalStrengthsChanged
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
+ public static final int EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED = 10;
+
+ /**
+ * Event for changes to observed cell info.
+ *
+ * @hide
+ * @see CellInfoListener#onCellInfoChanged
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
+ public static final int EVENT_CELL_INFO_CHANGED = 11;
+
+ /**
+ * Event for {@link android.telephony.Annotation.PreciseCallStates} of ringing,
+ * background and foreground calls.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ * or the calling app has carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @hide
+ * @see PreciseCallStateListener#onPreciseCallStateChanged
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public static final int EVENT_PRECISE_CALL_STATE_CHANGED = 12;
+
+ /**
+ * Event for {@link PreciseDataConnectionState} on the data connection (cellular).
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ * or the calling app has carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @hide
+ * @see PreciseDataConnectionStateListener#onPreciseDataConnectionStateChanged
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public static final int EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED = 13;
+
+ /**
+ * Event for real time info for all data connections (cellular)).
+ *
+ * @hide
+ * @see PhoneStateListener#onDataConnectionRealTimeInfoChanged(DataConnectionRealTimeInfo)
+ * @deprecated Use {@link TelephonyManager#requestModemActivityInfo}
+ */
+ @Deprecated
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public static final int EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED = 14;
+
+ /**
+ * Event for OEM hook raw event
+ *
+ * @hide
+ * @see PhoneStateListener#onOemHookRawEvent
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public static final int EVENT_OEM_HOOK_RAW = 15;
+
+ /**
+ * Event for changes to the SRVCC state of the active call.
+ *
+ * @hide
+ * @see SrvccStateListener#onSrvccStateChanged
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public static final int EVENT_SRVCC_STATE_CHANGED = 16;
+
+ /**
+ * Event for carrier network changes indicated by a carrier app.
+ *
+ * @hide
+ * @see android.service.carrier.CarrierService#notifyCarrierNetworkChange(boolean)
+ * @see CarrierNetworkListener#onCarrierNetworkChange
+ */
+ @SystemApi
+ public static final int EVENT_CARRIER_NETWORK_CHANGED = 17;
+
+ /**
+ * Event for changes to the sim voice activation state
+ *
+ * @hide
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN
+ * <p>
+ * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates voice service has been
+ * fully activated
+ * @see VoiceActivationStateListener#onVoiceActivationStateChanged
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public static final int EVENT_VOICE_ACTIVATION_STATE_CHANGED = 18;
+
+ /**
+ * Event for changes to the sim data activation state
+ *
+ * @hide
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN
+ * <p>
+ * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates data service has been
+ * fully activated
+ * @see DataActivationStateListener#onDataActivationStateChanged
+ */
+ @SystemApi
+ public static final int EVENT_DATA_ACTIVATION_STATE_CHANGED = 19;
+
+ /**
+ * Event for changes to the user mobile data state
+ *
+ * @hide
+ * @see UserMobileDataStateListener#onUserMobileDataStateChanged
+ */
+ @SystemApi
+ public static final int EVENT_USER_MOBILE_DATA_STATE_CHANGED = 20;
+
+ /**
+ * Event for display info changed event.
+ *
+ * @hide
+ * @see DisplayInfoListener#onDisplayInfoChanged
+ */
+ @SystemApi
+ public static final int EVENT_DISPLAY_INFO_CHANGED = 21;
+
+ /**
+ * Event for changes to the phone capability.
+ *
+ * @hide
+ * @see PhoneCapabilityListener#onPhoneCapabilityChanged
+ */
+ @SystemApi
+ public static final int EVENT_PHONE_CAPABILITY_CHANGED = 22;
+
+ /**
+ * Event for changes to active data subscription ID. Active data subscription is
+ * the current subscription used to setup Cellular Internet data. For example,
+ * it could be the current active opportunistic subscription in use, or the
+ * subscription user selected as default data subscription in DSDS mode.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
+ * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @hide
+ * @see ActiveDataSubscriptionIdListener#onActiveDataSubscriptionIdChanged
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public static final int EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED = 23;
+
+ /**
+ * Event for changes to the radio power state.
+ *
+ * @hide
+ * @see RadioPowerStateListener#onRadioPowerStateChanged
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public static final int EVENT_RADIO_POWER_STATE_CHANGED = 24;
+
+ /**
+ * Event for changes to emergency number list based on all active subscriptions.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
+ * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @hide
+ * @see EmergencyNumberListListener#onEmergencyNumberListChanged
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public static final int EVENT_EMERGENCY_NUMBER_LIST_CHANGED = 25;
+
+ /**
+ * Event for call disconnect causes which contains {@link DisconnectCause} and
+ * {@link PreciseDisconnectCause}.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ * or the calling app has carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @hide
+ * @see CallDisconnectCauseListener#onCallDisconnectCauseChanged
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public static final int EVENT_CALL_DISCONNECT_CAUSE_CHANGED = 26;
+
+ /**
+ * Event for changes to the call attributes of a currently active call.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ * or the calling app has carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @hide
+ * @see CallAttributesListener#onCallAttributesChanged
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public static final int EVENT_CALL_ATTRIBUTES_CHANGED = 27;
+
+ /**
+ * Event for IMS call disconnect causes which contains
+ * {@link android.telephony.ims.ImsReasonInfo}
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ * or the calling app has carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @hide
+ * @see ImsCallDisconnectCauseListener#onImsCallDisconnectCauseChanged(ImsReasonInfo)
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public static final int EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED = 28;
+
+ /**
+ * Event for the emergency number placed from an outgoing call.
+ *
+ * @hide
+ * @see OutgoingEmergencyCallListener#onOutgoingEmergencyCall
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
+ public static final int EVENT_OUTGOING_EMERGENCY_CALL = 29;
+
+ /**
+ * Event for the emergency number placed from an outgoing SMS.
+ *
+ * @hide
+ * @see OutgoingEmergencySmsListener#onOutgoingEmergencySms
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
+ public static final int EVENT_OUTGOING_EMERGENCY_SMS = 30;
+
+ /**
+ * Event for registration failures.
+ * <p>
+ * Event for indications that a registration procedure has failed in either the CS or PS
+ * domain. This indication does not necessarily indicate a change of service state, which should
+ * be tracked via {@link #EVENT_SERVICE_STATE_CHANGED}.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or
+ * the calling app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * <p>Also requires the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission, regardless
+ * of whether the calling app has carrier privileges.
+ *
+ * @hide
+ * @see RegistrationFailedListener#onRegistrationFailed
+ */
+ @SystemApi
+ @RequiresPermission(allOf = {
+ Manifest.permission.READ_PRECISE_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ })
+ public static final int EVENT_REGISTRATION_FAILURE = 31;
+
+ /**
+ * Event for Barring Information for the current registered / camped cell.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or
+ * the calling app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * <p>Also requires the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission, regardless
+ * of whether the calling app has carrier privileges.
+ *
+ * @hide
+ * @see BarringInfoListener#onBarringInfoChanged
+ */
+ @SystemApi
+ @RequiresPermission(allOf = {
+ Manifest.permission.READ_PRECISE_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ })
+ public static final int EVENT_BARRING_INFO_CHANGED = 32;
+
+ /**
+ * Event for changes to the physical channel configuration.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ * or the calling app has carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @hide
+ * @see PhysicalChannelConfigListener#onPhysicalChannelConfigChanged
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 33;
+
+
+ /**
+ * Event for changes to the data enabled.
+ * <p>
+ * Event for indications that the enabled status of current data has changed.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ * or the calling app has carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @hide
+ * @see DataEnabledListener#onDataEnabledChanged
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public static final int EVENT_DATA_ENABLED_CHANGED = 34;
+
+ /**
+ * Event for changes to allowed network list based on all active subscriptions.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
+ * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @hide
+ * @see AllowedNetworkTypesListener#onAllowedNetworkTypesChanged
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public static final int EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED = 35;
+
+ /**
+ * @hide
+ */
+ @IntDef(prefix = {"EVENT_"}, value = {
+ EVENT_SERVICE_STATE_CHANGED,
+ EVENT_SIGNAL_STRENGTH_CHANGED,
+ EVENT_MESSAGE_WAITING_INDICATOR_CHANGED,
+ EVENT_CALL_FORWARDING_INDICATOR_CHANGED,
+ EVENT_CELL_LOCATION_CHANGED,
+ EVENT_CALL_STATE_CHANGED,
+ EVENT_DATA_CONNECTION_STATE_CHANGED,
+ EVENT_DATA_ACTIVITY_CHANGED,
+ EVENT_SIGNAL_STRENGTHS_CHANGED,
+ EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED,
+ EVENT_CELL_INFO_CHANGED,
+ EVENT_PRECISE_CALL_STATE_CHANGED,
+ EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED,
+ EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED,
+ EVENT_OEM_HOOK_RAW,
+ EVENT_SRVCC_STATE_CHANGED,
+ EVENT_CARRIER_NETWORK_CHANGED,
+ EVENT_VOICE_ACTIVATION_STATE_CHANGED,
+ EVENT_DATA_ACTIVATION_STATE_CHANGED,
+ EVENT_USER_MOBILE_DATA_STATE_CHANGED,
+ EVENT_DISPLAY_INFO_CHANGED,
+ EVENT_PHONE_CAPABILITY_CHANGED,
+ EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED,
+ EVENT_RADIO_POWER_STATE_CHANGED,
+ EVENT_EMERGENCY_NUMBER_LIST_CHANGED,
+ EVENT_CALL_DISCONNECT_CAUSE_CHANGED,
+ EVENT_CALL_ATTRIBUTES_CHANGED,
+ EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED,
+ EVENT_OUTGOING_EMERGENCY_CALL,
+ EVENT_OUTGOING_EMERGENCY_SMS,
+ EVENT_REGISTRATION_FAILURE,
+ EVENT_BARRING_INFO_CHANGED,
+ EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED,
+ EVENT_DATA_ENABLED_CHANGED,
+ EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TelephonyEvent {
+ }
+
+ /**
+ * @hide
+ */
+ //TODO: The maxTargetSdk should be S if the build time tool updates it.
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public IPhoneStateListener callback;
+
+ /**
+ * @hide
+ */
+ public void init(@NonNull @CallbackExecutor Executor executor) {
+ if (executor == null) {
+ throw new IllegalArgumentException("TelephonyCallback Executor must be non-null");
+ }
+ callback = new IPhoneStateListenerStub(this, executor);
+ }
+
+ /**
+ * Interface for service state listener.
+ */
+ public interface ServiceStateListener {
+ /**
+ * Callback invoked when device service state changes on the registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers TelephonyCallback by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ * <p>
+ * The instance of {@link ServiceState} passed as an argument here will have various
+ * levels of location information stripped from it depending on the location permissions
+ * that your app holds.
+ * Only apps holding the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission will
+ * receive all the information in {@link ServiceState}.
+ *
+ * @see ServiceState#STATE_EMERGENCY_ONLY
+ * @see ServiceState#STATE_IN_SERVICE
+ * @see ServiceState#STATE_OUT_OF_SERVICE
+ * @see ServiceState#STATE_POWER_OFF
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void onServiceStateChanged(@NonNull ServiceState serviceState);
+ }
+
+ /**
+ * Interface for message waiting indicator listener.
+ */
+ public interface MessageWaitingIndicatorListener {
+ /**
+ * Callback invoked when the message-waiting indicator changes on the registered
+ * subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public void onMessageWaitingIndicatorChanged(boolean mwi);
+ }
+
+ /**
+ * Interface for call-forwarding indicator listener.
+ */
+ public interface CallForwardingIndicatorListener {
+ /**
+ * Callback invoked when the call-forwarding indicator changes on the registered
+ * subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers TelephonyCallback by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public void onCallForwardingIndicatorChanged(boolean cfi);
+ }
+
+ /**
+ * Interface for device cell location listener.
+ */
+ public interface CellLocationListener {
+ /**
+ * Callback invoked when device cell location changes on the registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers TelephonyCallback by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
+ public void onCellLocationChanged(@NonNull CellLocation location);
+ }
+
+ /**
+ * Interface for call state listener.
+ */
+ public interface CallStateListener {
+ /**
+ * Callback invoked when device call state changes.
+ * <p>
+ * Reports the state of Telephony (mobile) calls on the device for the registered
+ * subscription.
+ * <p>
+ * Note: the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers TelephonyCallback by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ * <p>
+ * Note: The state returned here may differ from that returned by
+ * {@link TelephonyManager#getCallState()}. Receivers of this callback should be aware that
+ * calling {@link TelephonyManager#getCallState()} from within this callback may return a
+ * different state than the callback reports.
+ *
+ * @param state call state
+ * @param phoneNumber call phone number. If application does not have
+ * {@link android.Manifest.permission#READ_CALL_LOG} permission or
+ * carrier
+ * privileges (see {@link TelephonyManager#hasCarrierPrivileges}), an
+ * empty string will be
+ * passed as an argument.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_CALL_LOG)
+ public void onCallStateChanged(@Annotation.CallState int state,
+ @Nullable String phoneNumber);
+ }
+
+ /**
+ * Interface for data connection state listener.
+ */
+ public interface DataConnectionStateListener {
+ /**
+ * Callback invoked when connection state changes on the registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers TelephonyCallback by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param state is the current state of data connection.
+ * @param networkType is the current network type of data connection.
+ * @see TelephonyManager#DATA_DISCONNECTED
+ * @see TelephonyManager#DATA_CONNECTING
+ * @see TelephonyManager#DATA_CONNECTED
+ * @see TelephonyManager#DATA_SUSPENDED
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void onDataConnectionStateChanged(@TelephonyManager.DataState int state,
+ @Annotation.NetworkType int networkType);
+ }
+
+ /**
+ * Interface for data activity state listener.
+ */
+ public interface DataActivityListener {
+ /**
+ * Callback invoked when data activity state changes on the registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers TelephonyCallback by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @see TelephonyManager#DATA_ACTIVITY_NONE
+ * @see TelephonyManager#DATA_ACTIVITY_IN
+ * @see TelephonyManager#DATA_ACTIVITY_OUT
+ * @see TelephonyManager#DATA_ACTIVITY_INOUT
+ * @see TelephonyManager#DATA_ACTIVITY_DORMANT
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void onDataActivity(@Annotation.DataActivityType int direction);
+ }
+
+ /**
+ * Interface for network signal strengths listener.
+ */
+ public interface SignalStrengthsListener {
+ /**
+ * Callback invoked when network signal strengths changes on the registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers TelephonyCallback by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength);
+ }
+
+ /**
+ * Interface for network signal strengths callback which always reported from modem.
+ */
+ public interface AlwaysReportedSignalStrengthListener {
+ /**
+ * Callback always invoked from modem when network signal strengths changes on the
+ * registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers TelephonyCallback by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ */
+ @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
+ public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength);
+ }
+
+ /**
+ * Interface for cell info listener.
+ */
+ public interface CellInfoListener {
+ /**
+ * Callback invoked when a observed cell info has changed or new cells have been added
+ * or removed on the registered subscription.
+ * Note, the registration subscription ID s from {@link TelephonyManager} object
+ * which registers TelephonyCallback by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param cellInfo is the list of currently visible cells.
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
+ public void onCellInfoChanged(@NonNull List<CellInfo> cellInfo);
+ }
+
+ /**
+ * Interface for precise device call state listener.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface PreciseCallStateListener {
+ /**
+ * Callback invoked when precise device call state changes on the registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers TelephonyCallback by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param callState {@link PreciseCallState}
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public void onPreciseCallStateChanged(@NonNull PreciseCallState callState);
+ }
+
+ /**
+ * Interface for call disconnect cause listener.
+ */
+ public interface CallDisconnectCauseListener {
+ /**
+ * Callback invoked when call disconnect cause changes on the registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers TelephonyCallback by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param disconnectCause {@link DisconnectCause}.
+ * @param preciseDisconnectCause {@link PreciseDisconnectCause}.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public void onCallDisconnectCauseChanged(@Annotation.DisconnectCauses int disconnectCause,
+ @Annotation.PreciseDisconnectCauses int preciseDisconnectCause);
+ }
+
+ /**
+ * Interface for IMS call disconnect cause listener.
+ */
+ public interface ImsCallDisconnectCauseListener {
+ /**
+ * Callback invoked when IMS call disconnect cause changes on the registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers TelephonyCallback by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param imsReasonInfo {@link ImsReasonInfo} contains details on why IMS call failed.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public void onImsCallDisconnectCauseChanged(@NonNull ImsReasonInfo imsReasonInfo);
+ }
+
+ /**
+ * Interface for precise data connection state listener.
+ */
+ public interface PreciseDataConnectionStateListener {
+ /**
+ * Callback providing update about the default/internet data connection on the registered
+ * subscription.
+ * <p>
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers TelephonyCallback by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ * or the calling app has carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @param dataConnectionState {@link PreciseDataConnectionState}
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public void onPreciseDataConnectionStateChanged(
+ @NonNull PreciseDataConnectionState dataConnectionState);
+ }
+
+ /**
+ * Interface for Single Radio Voice Call Continuity listener.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface SrvccStateListener {
+ /**
+ * Callback invoked when there has been a change in the Single Radio Voice Call Continuity
+ * (SRVCC) state for the currently active call on the registered subscription.
+ * <p>
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers TelephonyCallback by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public void onSrvccStateChanged(@Annotation.SrvccState int srvccState);
+ }
+
+ /**
+ * Interface for SIM voice activation state listener.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface VoiceActivationStateListener {
+ /**
+ * Callback invoked when the SIM voice activation state has changed on the registered
+ * subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers TelephonyCallback by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param state is the current SIM voice activation state
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public void onVoiceActivationStateChanged(@Annotation.SimActivationState int state);
+
+ }
+
+ /**
+ * Interface for SIM data activation state listener.
+ */
+ public interface DataActivationStateListener {
+ /**
+ * Callback invoked when the SIM data activation state has changed on the registered
+ * subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers TelephonyCallback by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param state is the current SIM data activation state
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void onDataActivationStateChanged(@Annotation.SimActivationState int state);
+ }
+
+ /**
+ * Interface for user mobile data state listener.
+ */
+ public interface UserMobileDataStateListener {
+ /**
+ * Callback invoked when the user mobile data state has changed on the registered
+ * subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers TelephonyCallback by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param enabled indicates whether the current user mobile data state is enabled or
+ * disabled.
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void onUserMobileDataStateChanged(boolean enabled);
+ }
+
+ /**
+ * Interface for display info listener.
+ */
+ public interface DisplayInfoListener {
+ /**
+ * Callback invoked when the display info has changed on the registered subscription.
+ * <p> The {@link TelephonyDisplayInfo} contains status information shown to the user
+ * based on carrier policy.
+ *
+ * @param telephonyDisplayInfo The display information.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo telephonyDisplayInfo);
+ }
+
+ /**
+ * Interface for the current emergency number list listener.
+ */
+ public interface EmergencyNumberListListener {
+ /**
+ * Callback invoked when the current emergency number list has changed on the registered
+ * subscription.
+ * <p>
+ * Note, the registered subscription is associated with {@link TelephonyManager} object
+ * on which
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}
+ * was called.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * given subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param emergencyNumberList Map associating all active subscriptions on the device with
+ * the list of emergency numbers originating from that
+ * subscription.
+ * If there are no active subscriptions, the map will contain a
+ * single entry with
+ * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} as
+ * the key and a list of emergency numbers as the value. If no
+ * emergency number information is available, the value will be
+ * empty.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public void onEmergencyNumberListChanged(
+ @NonNull Map<Integer, List<EmergencyNumber>> emergencyNumberList);
+ }
+
+ /**
+ * Interface for outgoing emergency call listener.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface OutgoingEmergencyCallListener {
+ /**
+ * Callback invoked when an outgoing call is placed to an emergency number.
+ * <p>
+ * This method will be called when an emergency call is placed on any subscription
+ * (including the no-SIM case), regardless of which subscription this callback was
+ * registered on.
+ * <p>
+ *
+ * @param placedEmergencyNumber The {@link EmergencyNumber} the emergency call was
+ * placed to.
+ * @param subscriptionId The subscription ID used to place the emergency call. If the
+ * emergency call was placed without a valid subscription
+ * (e.g. when there are no SIM cards in the device), this
+ * will be
+ * equal to
+ * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
+ */
+ @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
+ public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber,
+ int subscriptionId);
+ }
+
+ /**
+ * Interface for outgoing emergency sms listener.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface OutgoingEmergencySmsListener {
+ /**
+ * Smsback invoked when an outgoing sms is sent to an emergency number.
+ * <p>
+ * This method will be called when an emergency sms is sent on any subscription,
+ * regardless of which subscription this callback was registered on.
+ *
+ * @param sentEmergencyNumber The {@link EmergencyNumber} the emergency sms was sent to.
+ * @param subscriptionId The subscription ID used to send the emergency sms.
+ */
+ @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
+ public void onOutgoingEmergencySms(@NonNull EmergencyNumber sentEmergencyNumber,
+ int subscriptionId);
+ }
+
+ /**
+ * Interface for phone capability listener.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface PhoneCapabilityListener {
+ /**
+ * Callback invoked when phone capability changes.
+ * Note, this callback triggers regardless of registered subscription.
+ *
+ * @param capability the new phone capability
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void onPhoneCapabilityChanged(@NonNull PhoneCapability capability);
+ }
+
+ /**
+ * Interface for active data subscription ID listener.
+ */
+ public interface ActiveDataSubscriptionIdListener {
+ /**
+ * Callback invoked when active data subscription ID changes.
+ * Note, this callback triggers regardless of registered subscription.
+ *
+ * @param subId current subscription used to setup Cellular Internet data.
+ * For example, it could be the current active opportunistic subscription
+ * in use, or the subscription user selected as default data subscription in
+ * DSDS mode.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public void onActiveDataSubscriptionIdChanged(int subId);
+ }
+
+ /**
+ * Interface for modem radio power state listener.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface RadioPowerStateListener {
+ /**
+ * Callback invoked when modem radio power state changes on the registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers TelephonyCallback by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param state the modem radio power state
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public void onRadioPowerStateChanged(@Annotation.RadioPowerState int state);
+ }
+
+ /**
+ * Interface for carrier network listener.
+ */
+ public interface CarrierNetworkListener {
+ /**
+ * Callback invoked when telephony has received notice from a carrier
+ * app that a network action that could result in connectivity loss
+ * has been requested by an app using
+ * {@link android.service.carrier.CarrierService#notifyCarrierNetworkChange(boolean)}
+ * <p>
+ * This is optional and is only used to allow the system to provide alternative UI while
+ * telephony is performing an action that may result in intentional, temporary network
+ * lack of connectivity.
+ * <p>
+ * Note, this callback is pinned to the registered subscription and will be invoked when
+ * the notifying carrier app has carrier privilege rule on the registered
+ * subscription. {@link android.telephony.TelephonyManager#hasCarrierPrivileges}
+ *
+ * @param active If the carrier network change is or shortly will be active,
+ * {@code true} indicate that showing alternative UI, {@code false} otherwise.
+ */
+ public void onCarrierNetworkChange(boolean active);
+ }
+
+ /**
+ * Interface for registration failures listener.
+ */
+ public interface RegistrationFailedListener {
+ /**
+ * Report that Registration or a Location/Routing/Tracking Area update has failed.
+ *
+ * <p>Indicate whenever a registration procedure, including a location, routing, or tracking
+ * area update fails. This includes procedures that do not necessarily result in a change of
+ * the modem's registration status. If the modem's registration status changes, that is
+ * reflected in the onNetworkStateChanged() and subsequent
+ * get{Voice/Data}RegistrationState().
+ *
+ * <p>Because registration failures are ephemeral, this callback is not sticky.
+ * Registrants will not receive the most recent past value when registering.
+ *
+ * @param cellIdentity the CellIdentity, which must include the globally unique
+ * identifier
+ * for the cell (for example, all components of the CGI or ECGI).
+ * @param chosenPlmn a 5 or 6 digit alphanumeric PLMN (MCC|MNC) among those
+ * broadcast by the
+ * cell that was chosen for the failed registration attempt.
+ * @param domain DOMAIN_CS, DOMAIN_PS or both in case of a combined procedure.
+ * @param causeCode the primary failure cause code of the procedure.
+ * For GSM/UMTS (MM), values are in TS 24.008 Sec 10.5.95
+ * For GSM/UMTS (GMM), values are in TS 24.008 Sec 10.5.147
+ * For LTE (EMM), cause codes are TS 24.301 Sec 9.9.3.9
+ * For NR (5GMM), cause codes are TS 24.501 Sec 9.11.3.2
+ * Integer.MAX_VALUE if this value is unused.
+ * @param additionalCauseCode the cause code of any secondary/combined procedure
+ * if appropriate. For UMTS, if a combined attach succeeds for
+ * PS only, then the GMM cause code shall be included as an
+ * additionalCauseCode. For LTE (ESM), cause codes are in
+ * TS 24.301 9.9.4.4. Integer.MAX_VALUE if this value is unused.
+ */
+ @RequiresPermission(allOf = {
+ Manifest.permission.READ_PRECISE_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ })
+ public void onRegistrationFailed(@NonNull CellIdentity cellIdentity,
+ @NonNull String chosenPlmn, @NetworkRegistrationInfo.Domain int domain, int causeCode,
+ int additionalCauseCode);
+ }
+
+ /**
+ * Interface for the current allowed network type list listener. This list involves values of
+ * allowed network type for each of reasons.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface AllowedNetworkTypesListener {
+ /**
+ * Callback invoked when the current allowed network type list has changed on the
+ * registered subscription.
+ * Note, the registered subscription is associated with {@link TelephonyManager} object
+ * on which
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}
+ * was called.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * given subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param allowedNetworkTypesList Map associating all allowed network type reasons
+ * ({@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER},
+ * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER},
+ * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER}, and
+ * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G}) with reason's allowed
+ * network type values.
+ * For example:
+ * map{{TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER, long type value},
+ * {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER, long type value},
+ * {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER, long type value},
+ * {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G, long type value}}
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ void onAllowedNetworkTypesChanged(@NonNull Map<Integer, Long> allowedNetworkTypesList);
+ }
+
+ /**
+ * Interface for call attributes listener.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface CallAttributesListener {
+ /**
+ * Callback invoked when the call attributes changes on the registered subscription.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers TelephonyCallback by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @param callAttributes the call attributes
+ */
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+ void onCallAttributesChanged(@NonNull CallAttributes callAttributes);
+ }
+
+ /**
+ * Interface for barring information listener.
+ */
+ public interface BarringInfoListener {
+ /**
+ * Report updated barring information for the current camped/registered cell.
+ *
+ * <p>Barring info is provided for all services applicable to the current camped/registered
+ * cell, for the registered PLMN and current access class/access category.
+ *
+ * @param barringInfo for all services on the current cell.
+ * @see android.telephony.BarringInfo
+ */
+ @RequiresPermission(allOf = {
+ Manifest.permission.READ_PRECISE_PHONE_STATE,
+ Manifest.permission.ACCESS_FINE_LOCATION
+ })
+ public void onBarringInfoChanged(@NonNull BarringInfo barringInfo);
+ }
+
+ /**
+ * Interface for current physical channel configuration listener.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface PhysicalChannelConfigListener {
+ /**
+ * Callback invoked when the current physical channel configuration has changed
+ *
+ * @param configs List of the current {@link PhysicalChannelConfig}s
+ */
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public void onPhysicalChannelConfigChanged(@NonNull List<PhysicalChannelConfig> configs);
+ }
+
+ /**
+ * Interface for data enabled listener.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface DataEnabledListener {
+ /**
+ * Callback invoked when the data enabled changes.
+ *
+ * @param enabled {@code true} if data is enabled, otherwise disabled.
+ * @param reason Reason for data enabled/disabled.
+ * See {@link TelephonyManager.DataEnabledReason}.
+ */
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+ public void onDataEnabledChanged(boolean enabled,
+ @TelephonyManager.DataEnabledReason int reason);
+ }
+
+
+ /**
+ * The callback methods need to be called on the handler thread where
+ * this object was created. If the binder did that for us it'd be nice.
+ * <p>
+ * Using a static class and weak reference here to avoid memory leak caused by the
+ * IPhoneState.Stub callback retaining references to the outside TelephonyCallback:
+ * even caller has been destroyed and "un-registered" the TelephonyCallback, it is still not
+ * eligible for GC given the references coming from:
+ * Native Stack --> TelephonyCallback --> Context (Activity).
+ * memory of caller's context will be collected after GC from service side get triggered
+ */
+ private static class IPhoneStateListenerStub extends IPhoneStateListener.Stub {
+ private WeakReference<TelephonyCallback> mTelephonyCallbackWeakRef;
+ private Executor mExecutor;
+
+ IPhoneStateListenerStub(TelephonyCallback telephonyCallback, Executor executor) {
+ mTelephonyCallbackWeakRef = new WeakReference<TelephonyCallback>(telephonyCallback);
+ mExecutor = executor;
+ }
+
+ public void onServiceStateChanged(ServiceState serviceState) {
+ ServiceStateListener listener = (ServiceStateListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onServiceStateChanged(serviceState)));
+ }
+
+ public void onSignalStrengthChanged(int asu) {
+ // default implementation empty
+ }
+
+ public void onMessageWaitingIndicatorChanged(boolean mwi) {
+ MessageWaitingIndicatorListener listener =
+ (MessageWaitingIndicatorListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onMessageWaitingIndicatorChanged(mwi)));
+ }
+
+ public void onCallForwardingIndicatorChanged(boolean cfi) {
+ CallForwardingIndicatorListener listener =
+ (CallForwardingIndicatorListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onCallForwardingIndicatorChanged(cfi)));
+ }
+
+ public void onCellLocationChanged(CellIdentity cellIdentity) {
+ // There is no system/public API to create an CellIdentity in system server,
+ // so the server pass a null to indicate an empty initial location.
+ CellLocation location =
+ cellIdentity == null ? CellLocation.getEmpty() : cellIdentity.asCellLocation();
+ CellLocationListener listener = (CellLocationListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onCellLocationChanged(location)));
+ }
+
+ public void onCallStateChanged(int state, String incomingNumber) {
+ CallStateListener listener = (CallStateListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onCallStateChanged(state,
+ incomingNumber)));
+ }
+
+ public void onDataConnectionStateChanged(int state, int networkType) {
+ DataConnectionStateListener listener =
+ (DataConnectionStateListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ if (state == TelephonyManager.DATA_DISCONNECTING
+ && VMRuntime.getRuntime().getTargetSdkVersion() < Build.VERSION_CODES.R) {
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() ->
+ listener.onDataConnectionStateChanged(
+ TelephonyManager.DATA_CONNECTED, networkType)));
+ } else {
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() ->
+ listener.onDataConnectionStateChanged(state, networkType)));
+ }
+ }
+
+ public void onDataActivity(int direction) {
+ DataActivityListener listener = (DataActivityListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onDataActivity(direction)));
+ }
+
+ public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+ SignalStrengthsListener listener =
+ (SignalStrengthsListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onSignalStrengthsChanged(
+ signalStrength)));
+ }
+
+ public void onCellInfoChanged(List<CellInfo> cellInfo) {
+ CellInfoListener listener = (CellInfoListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onCellInfoChanged(cellInfo)));
+ }
+
+ public void onPreciseCallStateChanged(PreciseCallState callState) {
+ PreciseCallStateListener listener =
+ (PreciseCallStateListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onPreciseCallStateChanged(callState)));
+ }
+
+ public void onCallDisconnectCauseChanged(int disconnectCause, int preciseDisconnectCause) {
+ CallDisconnectCauseListener listener =
+ (CallDisconnectCauseListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onCallDisconnectCauseChanged(
+ disconnectCause, preciseDisconnectCause)));
+ }
+
+ public void onPreciseDataConnectionStateChanged(
+ PreciseDataConnectionState dataConnectionState) {
+ PreciseDataConnectionStateListener listener =
+ (PreciseDataConnectionStateListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(
+ () -> listener.onPreciseDataConnectionStateChanged(
+ dataConnectionState)));
+ }
+
+ public void onDataConnectionRealTimeInfoChanged(DataConnectionRealTimeInfo dcRtInfo) {
+ // default implementation empty
+ }
+
+ public void onSrvccStateChanged(int state) {
+ SrvccStateListener listener = (SrvccStateListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onSrvccStateChanged(state)));
+ }
+
+ public void onVoiceActivationStateChanged(int activationState) {
+ VoiceActivationStateListener listener =
+ (VoiceActivationStateListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(
+ () -> listener.onVoiceActivationStateChanged(activationState)));
+ }
+
+ public void onDataActivationStateChanged(int activationState) {
+ DataActivationStateListener listener =
+ (DataActivationStateListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(
+ () -> listener.onDataActivationStateChanged(activationState)));
+ }
+
+ public void onUserMobileDataStateChanged(boolean enabled) {
+ UserMobileDataStateListener listener =
+ (UserMobileDataStateListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(
+ () -> listener.onUserMobileDataStateChanged(enabled)));
+ }
+
+ public void onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo) {
+ DisplayInfoListener listener = (DisplayInfoListener)mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(
+ () -> listener.onDisplayInfoChanged(telephonyDisplayInfo)));
+ }
+
+ public void onOemHookRawEvent(byte[] rawData) {
+ // default implementation empty
+ }
+
+ public void onCarrierNetworkChange(boolean active) {
+ CarrierNetworkListener listener =
+ (CarrierNetworkListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onCarrierNetworkChange(active)));
+ }
+
+ public void onEmergencyNumberListChanged(Map emergencyNumberList) {
+ EmergencyNumberListListener listener =
+ (EmergencyNumberListListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(
+ () -> listener.onEmergencyNumberListChanged(emergencyNumberList)));
+ }
+
+ public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber,
+ int subscriptionId) {
+ OutgoingEmergencyCallListener listener =
+ (OutgoingEmergencyCallListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(
+ () -> listener.onOutgoingEmergencyCall(placedEmergencyNumber,
+ subscriptionId)));
+ }
+
+ public void onOutgoingEmergencySms(@NonNull EmergencyNumber sentEmergencyNumber,
+ int subscriptionId) {
+ OutgoingEmergencySmsListener listener =
+ (OutgoingEmergencySmsListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(
+ () -> listener.onOutgoingEmergencySms(sentEmergencyNumber,
+ subscriptionId)));
+ }
+
+ public void onPhoneCapabilityChanged(PhoneCapability capability) {
+ PhoneCapabilityListener listener =
+ (PhoneCapabilityListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onPhoneCapabilityChanged(capability)));
+ }
+
+ public void onRadioPowerStateChanged(@Annotation.RadioPowerState int state) {
+ RadioPowerStateListener listener =
+ (RadioPowerStateListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onRadioPowerStateChanged(state)));
+ }
+
+ public void onCallAttributesChanged(CallAttributes callAttributes) {
+ CallAttributesListener listener =
+ (CallAttributesListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onCallAttributesChanged(
+ callAttributes)));
+ }
+
+ public void onActiveDataSubIdChanged(int subId) {
+ ActiveDataSubscriptionIdListener listener =
+ (ActiveDataSubscriptionIdListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onActiveDataSubscriptionIdChanged(
+ subId)));
+ }
+
+ public void onImsCallDisconnectCauseChanged(ImsReasonInfo disconnectCause) {
+ ImsCallDisconnectCauseListener listener =
+ (ImsCallDisconnectCauseListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(
+ () -> listener.onImsCallDisconnectCauseChanged(disconnectCause)));
+ }
+
+ public void onRegistrationFailed(@NonNull CellIdentity cellIdentity,
+ @NonNull String chosenPlmn, int domain, int causeCode, int additionalCauseCode) {
+ RegistrationFailedListener listener =
+ (RegistrationFailedListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onRegistrationFailed(
+ cellIdentity, chosenPlmn, domain, causeCode, additionalCauseCode)));
+ // default implementation empty
+ }
+
+ public void onBarringInfoChanged(BarringInfo barringInfo) {
+ BarringInfoListener listener = (BarringInfoListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onBarringInfoChanged(barringInfo)));
+ }
+
+ public void onPhysicalChannelConfigChanged(List<PhysicalChannelConfig> configs) {
+ PhysicalChannelConfigListener listener =
+ (PhysicalChannelConfigListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onPhysicalChannelConfigChanged(
+ configs)));
+ }
+
+ public void onDataEnabledChanged(boolean enabled,
+ @TelephonyManager.DataEnabledReason int reason) {
+ DataEnabledListener listener =
+ (DataEnabledListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(() -> listener.onDataEnabledChanged(
+ enabled, reason)));
+ }
+
+ public void onAllowedNetworkTypesChanged(Map allowedNetworkTypesList) {
+ AllowedNetworkTypesListener listener =
+ (AllowedNetworkTypesListener) mTelephonyCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(
+ () -> listener.onAllowedNetworkTypesChanged(allowedNetworkTypesList)));
+ }
+ }
+}
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 3c355d4..459c6e9 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -209,7 +209,7 @@
}
/**
- * To check the SDK version for {@link #listenWithEventList}.
+ * To check the SDK version for {@link #listenFromListener}.
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.P)
@@ -221,24 +221,49 @@
* @param pkg Package name
* @param featureId Feature ID
* @param listener Listener providing callback
- * @param events List events
+ * @param events Events
* @param notifyNow Whether to notify instantly
*/
- public void listenWithEventList(int subId, @NonNull String pkg, @NonNull String featureId,
- @NonNull PhoneStateListener listener, @NonNull int[] events, boolean notifyNow) {
+ public void listenFromListener(int subId, @NonNull String pkg, @NonNull String featureId,
+ @NonNull PhoneStateListener listener, @NonNull int events, boolean notifyNow) {
+ if (listener == null) {
+ throw new IllegalStateException("telephony service is null.");
+ }
+
try {
+ int[] eventsList = getEventsFromBitmask(events).stream().mapToInt(i -> i).toArray();
// subId from PhoneStateListener is deprecated Q on forward, use the subId from
// TelephonyManager instance. Keep using subId from PhoneStateListener for pre-Q.
if (Compatibility.isChangeEnabled(LISTEN_CODE_CHANGE)) {
// Since mSubId in PhoneStateListener is deprecated from Q on forward, this is
// the only place to set mSubId and its for "informational" only.
- listener.mSubId = (events.length == 0)
+ listener.mSubId = (eventsList.length == 0)
? SubscriptionManager.INVALID_SUBSCRIPTION_ID : subId;
} else if (listener.mSubId != null) {
subId = listener.mSubId;
}
sRegistry.listenWithEventList(
- subId, pkg, featureId, listener.callback, events, notifyNow);
+ subId, pkg, featureId, listener.callback, eventsList, notifyNow);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Listen for incoming subscriptions
+ * @param subId Subscription ID
+ * @param pkg Package name
+ * @param featureId Feature ID
+ * @param telephonyCallback Listener providing callback
+ * @param events List events
+ * @param notifyNow Whether to notify instantly
+ */
+ private void listenFromCallback(int subId, @NonNull String pkg, @NonNull String featureId,
+ @NonNull TelephonyCallback telephonyCallback, @NonNull int[] events,
+ boolean notifyNow) {
+ try {
+ sRegistry.listenWithEventList(
+ subId, pkg, featureId, telephonyCallback.callback, events, notifyNow);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -815,136 +840,137 @@
}
}
- public @NonNull Set<Integer> getEventsFromListener(@NonNull PhoneStateListener listener) {
+ public @NonNull Set<Integer> getEventsFromCallback(
+ @NonNull TelephonyCallback telephonyCallback) {
Set<Integer> eventList = new ArraySet<>();
- if (listener instanceof PhoneStateListener.ServiceStateChangedListener) {
- eventList.add(PhoneStateListener.EVENT_SERVICE_STATE_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.ServiceStateListener) {
+ eventList.add(TelephonyCallback.EVENT_SERVICE_STATE_CHANGED);
}
- if (listener instanceof PhoneStateListener.MessageWaitingIndicatorChangedListener) {
- eventList.add(PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.MessageWaitingIndicatorListener) {
+ eventList.add(TelephonyCallback.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED);
}
- if (listener instanceof PhoneStateListener.CallForwardingIndicatorChangedListener) {
- eventList.add(PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.CallForwardingIndicatorListener) {
+ eventList.add(TelephonyCallback.EVENT_CALL_FORWARDING_INDICATOR_CHANGED);
}
- if (listener instanceof PhoneStateListener.CellLocationChangedListener) {
- eventList.add(PhoneStateListener.EVENT_CELL_LOCATION_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.CellLocationListener) {
+ eventList.add(TelephonyCallback.EVENT_CELL_LOCATION_CHANGED);
}
- if (listener instanceof PhoneStateListener.CallStateChangedListener) {
- eventList.add(PhoneStateListener.EVENT_CALL_STATE_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.CallStateListener) {
+ eventList.add(TelephonyCallback.EVENT_CALL_STATE_CHANGED);
}
- if (listener instanceof PhoneStateListener.DataConnectionStateChangedListener) {
- eventList.add(PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.DataConnectionStateListener) {
+ eventList.add(TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED);
}
- if (listener instanceof PhoneStateListener.DataActivityListener) {
- eventList.add(PhoneStateListener.EVENT_DATA_ACTIVITY_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.DataActivityListener) {
+ eventList.add(TelephonyCallback.EVENT_DATA_ACTIVITY_CHANGED);
}
- if (listener instanceof PhoneStateListener.SignalStrengthsChangedListener) {
- eventList.add(PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.SignalStrengthsListener) {
+ eventList.add(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED);
}
- if (listener instanceof PhoneStateListener.AlwaysReportedSignalStrengthChangedListener) {
- eventList.add(PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.AlwaysReportedSignalStrengthListener) {
+ eventList.add(TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED);
}
- if (listener instanceof PhoneStateListener.CellInfoChangedListener) {
- eventList.add(PhoneStateListener.EVENT_CELL_INFO_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.CellInfoListener) {
+ eventList.add(TelephonyCallback.EVENT_CELL_INFO_CHANGED);
}
- if (listener instanceof PhoneStateListener.PreciseCallStateChangedListener) {
- eventList.add(PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.PreciseCallStateListener) {
+ eventList.add(TelephonyCallback.EVENT_PRECISE_CALL_STATE_CHANGED);
}
- if (listener instanceof PhoneStateListener.CallDisconnectCauseChangedListener) {
- eventList.add(PhoneStateListener.EVENT_CALL_DISCONNECT_CAUSE_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.CallDisconnectCauseListener) {
+ eventList.add(TelephonyCallback.EVENT_CALL_DISCONNECT_CAUSE_CHANGED);
}
- if (listener instanceof PhoneStateListener.ImsCallDisconnectCauseChangedListener) {
- eventList.add(PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.ImsCallDisconnectCauseListener) {
+ eventList.add(TelephonyCallback.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED);
}
- if (listener instanceof PhoneStateListener.PreciseDataConnectionStateChangedListener) {
- eventList.add(PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.PreciseDataConnectionStateListener) {
+ eventList.add(TelephonyCallback.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED);
}
- if (listener instanceof PhoneStateListener.SrvccStateChangedListener) {
- eventList.add(PhoneStateListener.EVENT_SRVCC_STATE_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.SrvccStateListener) {
+ eventList.add(TelephonyCallback.EVENT_SRVCC_STATE_CHANGED);
}
- if (listener instanceof PhoneStateListener.VoiceActivationStateChangedListener) {
- eventList.add(PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.VoiceActivationStateListener) {
+ eventList.add(TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED);
}
- if (listener instanceof PhoneStateListener.DataActivationStateChangedListener) {
- eventList.add(PhoneStateListener.EVENT_DATA_ACTIVATION_STATE_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.DataActivationStateListener) {
+ eventList.add(TelephonyCallback.EVENT_DATA_ACTIVATION_STATE_CHANGED);
}
- if (listener instanceof PhoneStateListener.UserMobileDataStateChangedListener) {
- eventList.add(PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.UserMobileDataStateListener) {
+ eventList.add(TelephonyCallback.EVENT_USER_MOBILE_DATA_STATE_CHANGED);
}
- if (listener instanceof PhoneStateListener.DisplayInfoChangedListener) {
- eventList.add(PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.DisplayInfoListener) {
+ eventList.add(TelephonyCallback.EVENT_DISPLAY_INFO_CHANGED);
}
- if (listener instanceof PhoneStateListener.EmergencyNumberListChangedListener) {
- eventList.add(PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.EmergencyNumberListListener) {
+ eventList.add(TelephonyCallback.EVENT_EMERGENCY_NUMBER_LIST_CHANGED);
}
- if (listener instanceof PhoneStateListener.OutgoingEmergencyCallListener) {
- eventList.add(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_CALL);
+ if (telephonyCallback instanceof TelephonyCallback.OutgoingEmergencyCallListener) {
+ eventList.add(TelephonyCallback.EVENT_OUTGOING_EMERGENCY_CALL);
}
- if (listener instanceof PhoneStateListener.OutgoingEmergencySmsListener) {
- eventList.add(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_SMS);
+ if (telephonyCallback instanceof TelephonyCallback.OutgoingEmergencySmsListener) {
+ eventList.add(TelephonyCallback.EVENT_OUTGOING_EMERGENCY_SMS);
}
- if (listener instanceof PhoneStateListener.PhoneCapabilityChangedListener) {
- eventList.add(PhoneStateListener.EVENT_PHONE_CAPABILITY_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.PhoneCapabilityListener) {
+ eventList.add(TelephonyCallback.EVENT_PHONE_CAPABILITY_CHANGED);
}
- if (listener instanceof PhoneStateListener.ActiveDataSubscriptionIdChangedListener) {
- eventList.add(PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.ActiveDataSubscriptionIdListener) {
+ eventList.add(TelephonyCallback.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED);
}
- if (listener instanceof PhoneStateListener.RadioPowerStateChangedListener) {
- eventList.add(PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.RadioPowerStateListener) {
+ eventList.add(TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED);
}
- if (listener instanceof PhoneStateListener.CarrierNetworkChangeListener) {
- eventList.add(PhoneStateListener.EVENT_CARRIER_NETWORK_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.CarrierNetworkListener) {
+ eventList.add(TelephonyCallback.EVENT_CARRIER_NETWORK_CHANGED);
}
- if (listener instanceof PhoneStateListener.RegistrationFailedListener) {
- eventList.add(PhoneStateListener.EVENT_REGISTRATION_FAILURE);
+ if (telephonyCallback instanceof TelephonyCallback.RegistrationFailedListener) {
+ eventList.add(TelephonyCallback.EVENT_REGISTRATION_FAILURE);
}
- if (listener instanceof PhoneStateListener.CallAttributesChangedListener) {
- eventList.add(PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.CallAttributesListener) {
+ eventList.add(TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED);
}
- if (listener instanceof PhoneStateListener.BarringInfoChangedListener) {
- eventList.add(PhoneStateListener.EVENT_BARRING_INFO_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.BarringInfoListener) {
+ eventList.add(TelephonyCallback.EVENT_BARRING_INFO_CHANGED);
}
- if (listener instanceof PhoneStateListener.PhysicalChannelConfigChangedListener) {
- eventList.add(PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.PhysicalChannelConfigListener) {
+ eventList.add(TelephonyCallback.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED);
}
- if (listener instanceof PhoneStateListener.DataEnabledChangedListener) {
- eventList.add(PhoneStateListener.EVENT_DATA_ENABLED_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.DataEnabledListener) {
+ eventList.add(TelephonyCallback.EVENT_DATA_ENABLED_CHANGED);
}
- if (listener instanceof PhoneStateListener.AllowedNetworkTypesChangedListener) {
- eventList.add(PhoneStateListener.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED);
+ if (telephonyCallback instanceof TelephonyCallback.AllowedNetworkTypesListener) {
+ eventList.add(TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED);
}
return eventList;
@@ -955,200 +981,183 @@
Set<Integer> eventList = new ArraySet<>();
if ((eventMask & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
- eventList.add(PhoneStateListener.EVENT_SERVICE_STATE_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_SERVICE_STATE_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
- eventList.add(PhoneStateListener.EVENT_SIGNAL_STRENGTH_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_SIGNAL_STRENGTH_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
- eventList.add(PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
- eventList.add(PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_CALL_FORWARDING_INDICATOR_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
- eventList.add(PhoneStateListener.EVENT_CELL_LOCATION_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_CELL_LOCATION_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
- eventList.add(PhoneStateListener.EVENT_CALL_STATE_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_CALL_STATE_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
- eventList.add(PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
- eventList.add(PhoneStateListener.EVENT_DATA_ACTIVITY_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_DATA_ACTIVITY_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
- eventList.add(PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) {
- eventList.add(PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_CELL_INFO) != 0) {
- eventList.add(PhoneStateListener.EVENT_CELL_INFO_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_CELL_INFO_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
- eventList.add(PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_PRECISE_CALL_STATE_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
- eventList.add(PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO) != 0) {
- eventList.add(PhoneStateListener.EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT) != 0) {
- eventList.add(PhoneStateListener.EVENT_OEM_HOOK_RAW);
+ eventList.add(TelephonyCallback.EVENT_OEM_HOOK_RAW);
}
if ((eventMask & PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED) != 0) {
- eventList.add(PhoneStateListener.EVENT_SRVCC_STATE_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_SRVCC_STATE_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE) != 0) {
- eventList.add(PhoneStateListener.EVENT_CARRIER_NETWORK_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_CARRIER_NETWORK_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) != 0) {
- eventList.add(PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE) != 0) {
- eventList.add(PhoneStateListener.EVENT_DATA_ACTIVATION_STATE_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_DATA_ACTIVATION_STATE_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) != 0) {
- eventList.add(PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_USER_MOBILE_DATA_STATE_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED) != 0) {
- eventList.add(PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_DISPLAY_INFO_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_PHONE_CAPABILITY_CHANGE) != 0) {
- eventList.add(PhoneStateListener.EVENT_PHONE_CAPABILITY_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_PHONE_CAPABILITY_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE) != 0) {
- eventList.add(PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED) != 0) {
- eventList.add(PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST) != 0) {
- eventList.add(PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_EMERGENCY_NUMBER_LIST_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES) != 0) {
- eventList.add(PhoneStateListener.EVENT_CALL_DISCONNECT_CAUSE_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_CALL_DISCONNECT_CAUSE_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED) != 0) {
- eventList.add(PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES) != 0) {
- eventList.add(PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED);
}
if ((eventMask & PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL) != 0) {
- eventList.add(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_CALL);
+ eventList.add(TelephonyCallback.EVENT_OUTGOING_EMERGENCY_CALL);
}
if ((eventMask & PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS) != 0) {
- eventList.add(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_SMS);
+ eventList.add(TelephonyCallback.EVENT_OUTGOING_EMERGENCY_SMS);
}
if ((eventMask & PhoneStateListener.LISTEN_REGISTRATION_FAILURE) != 0) {
- eventList.add(PhoneStateListener.EVENT_REGISTRATION_FAILURE);
+ eventList.add(TelephonyCallback.EVENT_REGISTRATION_FAILURE);
}
if ((eventMask & PhoneStateListener.LISTEN_BARRING_INFO) != 0) {
- eventList.add(PhoneStateListener.EVENT_BARRING_INFO_CHANGED);
+ eventList.add(TelephonyCallback.EVENT_BARRING_INFO_CHANGED);
}
return eventList;
}
/**
- * Registers a listener object to receive notification of changes
- * in specified telephony states.
+ * Registers a callback object to receive notification of changes in specified telephony states.
* <p>
- * To register a listener, pass a {@link PhoneStateListener} which implements
+ * To register a callback, pass a {@link TelephonyCallback} which implements
* interfaces of events. For example,
- * FakeServiceStateChangedListener extends {@link PhoneStateListener} implements
- * {@link PhoneStateListener.ServiceStateChangedListener}.
+ * FakeServiceStateCallback extends {@link TelephonyCallback} implements
+ * {@link TelephonyCallback.ServiceStateListener}.
*
* At registration, and when a specified telephony state changes, the telephony manager invokes
- * the appropriate callback method on the listener object and passes the current (updated)
+ * the appropriate callback method on the callback object and passes the current (updated)
* values.
* <p>
*
* If this TelephonyManager object has been created with
* {@link TelephonyManager#createForSubscriptionId}, applies to the given subId.
* Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}.
- * To listen events for multiple subIds, pass a separate listener object to
+ * To register events for multiple subIds, pass a separate callback object to
* each TelephonyManager object created with {@link TelephonyManager#createForSubscriptionId}.
*
* Note: if you call this method while in the middle of a binder transaction, you <b>must</b>
* call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A
* {@link SecurityException} will be thrown otherwise.
*
- * This API should be used sparingly -- large numbers of listeners will cause system
- * instability. If a process has registered too many listeners without unregistering them, it
- * may encounter an {@link IllegalStateException} when trying to register more listeners.
+ * This API should be used sparingly -- large numbers of callbacks will cause system
+ * instability. If a process has registered too many callbacks without unregistering them, it
+ * may encounter an {@link IllegalStateException} when trying to register more callbacks.
*
- * @param listener The {@link PhoneStateListener} object to register.
+ * @param callback The {@link TelephonyCallback} object to register.
*/
- public void registerPhoneStateListener(@NonNull @CallbackExecutor Executor executor, int subId,
- String pkgName, String attributionTag, @NonNull PhoneStateListener listener,
+ public void registerTelephonyCallback(@NonNull @CallbackExecutor Executor executor,
+ int subId, String pkgName, String attributionTag, @NonNull TelephonyCallback callback,
boolean notifyNow) {
- listener.setExecutor(executor);
- registerPhoneStateListener(subId, pkgName, attributionTag, listener,
- getEventsFromListener(listener), notifyNow);
- }
-
- public void registerPhoneStateListenerWithEvents(int subId, String pkgName,
- String attributionTag, @NonNull PhoneStateListener listener, int events,
- boolean notifyNow) {
- registerPhoneStateListener(
- subId, pkgName, attributionTag, listener, getEventsFromBitmask(events), notifyNow);
- }
-
- private void registerPhoneStateListener(int subId,
- String pkgName, String attributionTag, @NonNull PhoneStateListener listener,
- @NonNull Set<Integer> events, boolean notifyNow) {
- if (listener == null) {
+ if (callback == null) {
throw new IllegalStateException("telephony service is null.");
}
-
- listenWithEventList(subId, pkgName, attributionTag, listener,
- events.stream().mapToInt(i -> i).toArray(), notifyNow);
+ callback.init(executor);
+ listenFromCallback(subId, pkgName, attributionTag, callback,
+ getEventsFromCallback(callback).stream().mapToInt(i -> i).toArray(), notifyNow);
}
/**
- * Unregister an existing {@link PhoneStateListener}.
+ * Unregister an existing {@link TelephonyCallback}.
*
- * @param listener The {@link PhoneStateListener} object to unregister.
+ * @param callback The {@link TelephonyCallback} object to unregister.
*/
- public void unregisterPhoneStateListener(int subId, String pkgName, String attributionTag,
- @NonNull PhoneStateListener listener,
- boolean notifyNow) {
- listenWithEventList(subId, pkgName, attributionTag, listener, new int[0], notifyNow);
+ public void unregisterTelephonyCallback(int subId, String pkgName, String attributionTag,
+ @NonNull TelephonyCallback callback, boolean notifyNow) {
+ listenFromCallback(subId, pkgName, attributionTag, callback, new int[0], notifyNow);
}
}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 2b577d0..3a33024 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -68,7 +68,7 @@
DEFAULT_FLAGS.put(SETTINGS_DO_NOT_RESTORE_PRESERVED, "true");
DEFAULT_FLAGS.put("settings_tether_all_in_one", "false");
- DEFAULT_FLAGS.put("settings_silky_home", "false");
+ DEFAULT_FLAGS.put("settings_silky_home", "true");
DEFAULT_FLAGS.put("settings_contextual_home", "false");
DEFAULT_FLAGS.put(SETTINGS_PROVIDER_MODEL, "false");
DEFAULT_FLAGS.put(SETTINGS_USE_NEW_BACKUP_ELIGIBILITY_RULES, "false");
diff --git a/core/java/android/util/SizeF.java b/core/java/android/util/SizeF.java
index 2edc4a7f..c77a0243 100644
--- a/core/java/android/util/SizeF.java
+++ b/core/java/android/util/SizeF.java
@@ -16,8 +16,12 @@
package android.util;
-import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.Preconditions.checkArgumentFinite;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
/**
* Immutable class for describing width and height dimensions in some arbitrary
@@ -26,7 +30,7 @@
* Width and height are finite values stored as a floating point representation.
* </p>
*/
-public final class SizeF {
+public final class SizeF implements Parcelable {
/**
* Create a new immutable SizeF instance.
*
@@ -161,4 +165,43 @@
private final float mWidth;
private final float mHeight;
+
+ /**
+ * Parcelable interface methods
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Write this size to the specified parcel. To restore a size from a parcel, use the
+ * {@link #CREATOR}.
+ * @param out The parcel to write the point's coordinates into
+ */
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeFloat(mWidth);
+ out.writeFloat(mHeight);
+ }
+
+ public static final @NonNull Creator<SizeF> CREATOR = new Creator<SizeF>() {
+ /**
+ * Return a new size from the data in the specified parcel.
+ */
+ @Override
+ public @NonNull SizeF createFromParcel(@NonNull Parcel in) {
+ float width = in.readFloat();
+ float height = in.readFloat();
+ return new SizeF(width, height);
+ }
+
+ /**
+ * Return an array of sizes of the specified size.
+ */
+ @Override
+ public @NonNull SizeF[] newArray(int size) {
+ return new SizeF[size];
+ }
+ };
}
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 09452828..e5a137c 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -86,6 +86,12 @@
// accessibility from hanging
private static final long REQUEST_PREPARER_TIMEOUT_MS = 500;
+ // Callbacks should have the same configuration of the flags below to allow satisfying a pending
+ // node request on prefetch
+ private static final int FLAGS_AFFECTING_REPORTED_DATA =
+ AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
+ | AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS;
+
private final ArrayList<AccessibilityNodeInfo> mTempAccessibilityNodeInfoList =
new ArrayList<AccessibilityNodeInfo>();
@@ -114,6 +120,9 @@
private AddNodeInfosForViewId mAddNodeInfosForViewId;
@GuardedBy("mLock")
+ private ArrayList<Message> mPendingFindNodeByIdMessages;
+
+ @GuardedBy("mLock")
private int mNumActiveRequestPreparers;
@GuardedBy("mLock")
private List<MessageHolder> mMessagesWaitingForRequestPreparer;
@@ -128,6 +137,7 @@
mViewRootImpl = viewRootImpl;
mPrefetcher = new AccessibilityNodePrefetcher();
mA11yManager = mViewRootImpl.mContext.getSystemService(AccessibilityManager.class);
+ mPendingFindNodeByIdMessages = new ArrayList<>();
}
private void scheduleMessage(Message message, int interrogatingPid, long interrogatingTid,
@@ -177,7 +187,11 @@
args.arg4 = arguments;
message.obj = args;
- scheduleMessage(message, interrogatingPid, interrogatingTid, CONSIDER_REQUEST_PREPARERS);
+ synchronized (mLock) {
+ mPendingFindNodeByIdMessages.add(message);
+ scheduleMessage(message, interrogatingPid, interrogatingTid,
+ CONSIDER_REQUEST_PREPARERS);
+ }
}
/**
@@ -315,6 +329,9 @@
}
private void findAccessibilityNodeInfoByAccessibilityIdUiThread(Message message) {
+ synchronized (mLock) {
+ mPendingFindNodeByIdMessages.remove(message);
+ }
final int flags = message.arg1;
SomeArgs args = (SomeArgs) message.obj;
@@ -329,22 +346,58 @@
args.recycle();
- List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
- infos.clear();
+ View rootView = null;
+ AccessibilityNodeInfo rootNode = null;
try {
if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) {
return;
}
mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags;
- final View root = findViewByAccessibilityId(accessibilityViewId);
- if (root != null && isShown(root)) {
- mPrefetcher.prefetchAccessibilityNodeInfos(
- root, virtualDescendantId, flags, infos, arguments);
+ rootView = findViewByAccessibilityId(accessibilityViewId);
+ if (rootView != null && isShown(rootView)) {
+ rootNode = populateAccessibilityNodeInfoForView(
+ rootView, arguments, virtualDescendantId);
}
} finally {
- updateInfosForViewportAndReturnFindNodeResult(
- infos, callback, interactionId, spec, interactiveRegion);
+ updateInfoForViewportAndReturnFindNodeResult(
+ rootNode == null ? null : AccessibilityNodeInfo.obtain(rootNode),
+ callback, interactionId, spec, interactiveRegion);
}
+ ArrayList<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
+ infos.clear();
+ mPrefetcher.prefetchAccessibilityNodeInfos(
+ rootView, rootNode == null ? null : AccessibilityNodeInfo.obtain(rootNode),
+ virtualDescendantId, flags, infos);
+ mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
+ updateInfosForViewPort(infos, spec, interactiveRegion);
+ returnPrefetchResult(interactionId, infos, callback);
+ returnPendingFindAccessibilityNodeInfosInPrefetch(rootNode, infos, flags);
+ }
+
+ private AccessibilityNodeInfo populateAccessibilityNodeInfoForView(
+ View view, Bundle arguments, int virtualViewId) {
+ AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
+ // Determine if we'll be populating extra data
+ final String extraDataRequested = (arguments == null) ? null
+ : arguments.getString(EXTRA_DATA_REQUESTED_KEY);
+ AccessibilityNodeInfo root = null;
+ if (provider == null) {
+ root = view.createAccessibilityNodeInfo();
+ if (root != null) {
+ if (extraDataRequested != null) {
+ view.addExtraDataToAccessibilityNodeInfo(root, extraDataRequested, arguments);
+ }
+ }
+ } else {
+ root = provider.createAccessibilityNodeInfo(virtualViewId);
+ if (root != null) {
+ if (extraDataRequested != null) {
+ provider.addExtraDataToAccessibilityNodeInfo(
+ virtualViewId, root, extraDataRequested, arguments);
+ }
+ }
+ }
+ return root;
}
public void findAccessibilityNodeInfosByViewIdClientThread(long accessibilityNodeId,
@@ -403,6 +456,7 @@
mAddNodeInfosForViewId.reset();
}
} finally {
+ mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
updateInfosForViewportAndReturnFindNodeResult(
infos, callback, interactionId, spec, interactiveRegion);
}
@@ -485,6 +539,7 @@
}
}
} finally {
+ mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
updateInfosForViewportAndReturnFindNodeResult(
infos, callback, interactionId, spec, interactiveRegion);
}
@@ -576,6 +631,7 @@
}
}
} finally {
+ mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
updateInfoForViewportAndReturnFindNodeResult(
focused, callback, interactionId, spec, interactiveRegion);
}
@@ -630,6 +686,7 @@
}
}
} finally {
+ mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
updateInfoForViewportAndReturnFindNodeResult(
next, callback, interactionId, spec, interactiveRegion);
}
@@ -786,33 +843,6 @@
}
}
- private void applyAppScaleAndMagnificationSpecIfNeeded(List<AccessibilityNodeInfo> infos,
- MagnificationSpec spec) {
- if (infos == null) {
- return;
- }
- final float applicationScale = mViewRootImpl.mAttachInfo.mApplicationScale;
- if (shouldApplyAppScaleAndMagnificationSpec(applicationScale, spec)) {
- final int infoCount = infos.size();
- for (int i = 0; i < infoCount; i++) {
- AccessibilityNodeInfo info = infos.get(i);
- applyAppScaleAndMagnificationSpecIfNeeded(info, spec);
- }
- }
- }
-
- private void adjustIsVisibleToUserIfNeeded(List<AccessibilityNodeInfo> infos,
- Region interactiveRegion) {
- if (interactiveRegion == null || infos == null) {
- return;
- }
- final int infoCount = infos.size();
- for (int i = 0; i < infoCount; i++) {
- AccessibilityNodeInfo info = infos.get(i);
- adjustIsVisibleToUserIfNeeded(info, interactiveRegion);
- }
- }
-
private void adjustIsVisibleToUserIfNeeded(AccessibilityNodeInfo info,
Region interactiveRegion) {
if (interactiveRegion == null || info == null) {
@@ -833,17 +863,6 @@
return false;
}
- private void adjustBoundsInScreenIfNeeded(List<AccessibilityNodeInfo> infos) {
- if (infos == null || shouldBypassAdjustBoundsInScreen()) {
- return;
- }
- final int infoCount = infos.size();
- for (int i = 0; i < infoCount; i++) {
- final AccessibilityNodeInfo info = infos.get(i);
- adjustBoundsInScreenIfNeeded(info);
- }
- }
-
private void adjustBoundsInScreenIfNeeded(AccessibilityNodeInfo info) {
if (info == null || shouldBypassAdjustBoundsInScreen()) {
return;
@@ -891,17 +910,6 @@
return screenMatrix == null || screenMatrix.isIdentity();
}
- private void associateLeashedParentIfNeeded(List<AccessibilityNodeInfo> infos) {
- if (infos == null || shouldBypassAssociateLeashedParent()) {
- return;
- }
- final int infoCount = infos.size();
- for (int i = 0; i < infoCount; i++) {
- final AccessibilityNodeInfo info = infos.get(i);
- associateLeashedParentIfNeeded(info);
- }
- }
-
private void associateLeashedParentIfNeeded(AccessibilityNodeInfo info) {
if (info == null || shouldBypassAssociateLeashedParent()) {
return;
@@ -975,18 +983,46 @@
return (appScale != 1.0f || (spec != null && !spec.isNop()));
}
+ private void updateInfosForViewPort(List<AccessibilityNodeInfo> infos, MagnificationSpec spec,
+ Region interactiveRegion) {
+ for (int i = 0; i < infos.size(); i++) {
+ updateInfoForViewPort(infos.get(i), spec, interactiveRegion);
+ }
+ }
+
+ private void updateInfoForViewPort(AccessibilityNodeInfo info, MagnificationSpec spec,
+ Region interactiveRegion) {
+ associateLeashedParentIfNeeded(info);
+ applyScreenMatrixIfNeeded(info);
+ adjustBoundsInScreenIfNeeded(info);
+ // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node,
+ // then impact the visibility result, we need to adjust visibility before apply scale.
+ adjustIsVisibleToUserIfNeeded(info, interactiveRegion);
+ applyAppScaleAndMagnificationSpecIfNeeded(info, spec);
+ }
+
private void updateInfosForViewportAndReturnFindNodeResult(List<AccessibilityNodeInfo> infos,
IAccessibilityInteractionConnectionCallback callback, int interactionId,
MagnificationSpec spec, Region interactiveRegion) {
+ if (infos != null) {
+ updateInfosForViewPort(infos, spec, interactiveRegion);
+ }
+ returnFindNodesResult(infos, callback, interactionId);
+ }
+
+ private void returnFindNodeResult(AccessibilityNodeInfo info,
+ IAccessibilityInteractionConnectionCallback callback,
+ int interactionId) {
try {
- mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
- associateLeashedParentIfNeeded(infos);
- applyScreenMatrixIfNeeded(infos);
- adjustBoundsInScreenIfNeeded(infos);
- // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node,
- // then impact the visibility result, we need to adjust visibility before apply scale.
- adjustIsVisibleToUserIfNeeded(infos, interactiveRegion);
- applyAppScaleAndMagnificationSpecIfNeeded(infos, spec);
+ callback.setFindAccessibilityNodeInfoResult(info, interactionId);
+ } catch (RemoteException re) {
+ /* ignore - the other side will time out */
+ }
+ }
+
+ private void returnFindNodesResult(List<AccessibilityNodeInfo> infos,
+ IAccessibilityInteractionConnectionCallback callback, int interactionId) {
+ try {
callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
if (infos != null) {
infos.clear();
@@ -996,22 +1032,80 @@
}
}
+ private void returnPendingFindAccessibilityNodeInfosInPrefetch(AccessibilityNodeInfo rootNode,
+ List<AccessibilityNodeInfo> infos, int flags) {
+
+ AccessibilityNodeInfo satisfiedPendingRequestPrefetchedNode = null;
+ IAccessibilityInteractionConnectionCallback satisfiedPendingRequestCallback = null;
+ int satisfiedPendingRequestInteractionId = AccessibilityInteractionClient.NO_ID;
+
+ synchronized (mLock) {
+ for (int i = 0; i < mPendingFindNodeByIdMessages.size(); i++) {
+ final Message pendingMessage = mPendingFindNodeByIdMessages.get(i);
+ final int pendingFlags = pendingMessage.arg1;
+ if ((pendingFlags & FLAGS_AFFECTING_REPORTED_DATA)
+ != (flags & FLAGS_AFFECTING_REPORTED_DATA)) {
+ continue;
+ }
+ SomeArgs args = (SomeArgs) pendingMessage.obj;
+ final int accessibilityViewId = args.argi1;
+ final int virtualDescendantId = args.argi2;
+
+ satisfiedPendingRequestPrefetchedNode = nodeWithIdFromList(rootNode,
+ infos, AccessibilityNodeInfo.makeNodeId(
+ accessibilityViewId, virtualDescendantId));
+
+ if (satisfiedPendingRequestPrefetchedNode != null) {
+ satisfiedPendingRequestCallback =
+ (IAccessibilityInteractionConnectionCallback) args.arg1;
+ satisfiedPendingRequestInteractionId = args.argi3;
+ mHandler.removeMessages(
+ PrivateHandler.MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID,
+ pendingMessage.obj);
+ args.recycle();
+ break;
+ }
+ }
+ mPendingFindNodeByIdMessages.clear();
+ }
+
+ if (satisfiedPendingRequestPrefetchedNode != null) {
+ returnFindNodeResult(
+ AccessibilityNodeInfo.obtain(satisfiedPendingRequestPrefetchedNode),
+ satisfiedPendingRequestCallback, satisfiedPendingRequestInteractionId);
+ }
+ }
+
+ private AccessibilityNodeInfo nodeWithIdFromList(AccessibilityNodeInfo rootNode,
+ List<AccessibilityNodeInfo> infos, long nodeId) {
+ if (rootNode != null && rootNode.getSourceNodeId() == nodeId) {
+ return rootNode;
+ }
+ for (int j = 0; j < infos.size(); j++) {
+ AccessibilityNodeInfo info = infos.get(j);
+ if (info.getSourceNodeId() == nodeId) {
+ return info;
+ }
+ }
+ return null;
+ }
+
+ private void returnPrefetchResult(int interactionId, List<AccessibilityNodeInfo> infos,
+ IAccessibilityInteractionConnectionCallback callback) {
+ if (infos.size() > 0) {
+ try {
+ callback.setPrefetchAccessibilityNodeInfoResult(infos, interactionId);
+ } catch (RemoteException re) {
+ /* ignore - other side isn't too bothered if this doesn't arrive */
+ }
+ }
+ }
+
private void updateInfoForViewportAndReturnFindNodeResult(AccessibilityNodeInfo info,
IAccessibilityInteractionConnectionCallback callback, int interactionId,
MagnificationSpec spec, Region interactiveRegion) {
- try {
- mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
- associateLeashedParentIfNeeded(info);
- applyScreenMatrixIfNeeded(info);
- adjustBoundsInScreenIfNeeded(info);
- // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node,
- // then impact the visibility result, we need to adjust visibility before apply scale.
- adjustIsVisibleToUserIfNeeded(info, interactiveRegion);
- applyAppScaleAndMagnificationSpecIfNeeded(info, spec);
- callback.setFindAccessibilityNodeInfoResult(info, interactionId);
- } catch (RemoteException re) {
- /* ignore - the other side will time out */
- }
+ updateInfoForViewPort(info, spec, interactiveRegion);
+ returnFindNodeResult(info, callback, interactionId);
}
private boolean handleClickableSpanActionUiThread(
@@ -1054,56 +1148,45 @@
private final ArrayList<View> mTempViewList = new ArrayList<View>();
- public void prefetchAccessibilityNodeInfos(View view, int virtualViewId, int fetchFlags,
- List<AccessibilityNodeInfo> outInfos, Bundle arguments) {
+ public void prefetchAccessibilityNodeInfos(View view, AccessibilityNodeInfo root,
+ int virtualViewId, int fetchFlags, List<AccessibilityNodeInfo> outInfos) {
+ if (root == null) {
+ return;
+ }
AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
- // Determine if we'll be populating extra data
- final String extraDataRequested = (arguments == null) ? null
- : arguments.getString(EXTRA_DATA_REQUESTED_KEY);
if (provider == null) {
- AccessibilityNodeInfo root = view.createAccessibilityNodeInfo();
- if (root != null) {
- if (extraDataRequested != null) {
- view.addExtraDataToAccessibilityNodeInfo(
- root, extraDataRequested, arguments);
- }
- outInfos.add(root);
- if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
- prefetchPredecessorsOfRealNode(view, outInfos);
- }
- if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0) {
- prefetchSiblingsOfRealNode(view, outInfos);
- }
- if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) {
- prefetchDescendantsOfRealNode(view, outInfos);
- }
+ if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
+ prefetchPredecessorsOfRealNode(view, outInfos);
+ }
+ if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0) {
+ prefetchSiblingsOfRealNode(view, outInfos);
+ }
+ if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) {
+ prefetchDescendantsOfRealNode(view, outInfos);
}
} else {
- final AccessibilityNodeInfo root =
- provider.createAccessibilityNodeInfo(virtualViewId);
- if (root != null) {
- if (extraDataRequested != null) {
- provider.addExtraDataToAccessibilityNodeInfo(
- virtualViewId, root, extraDataRequested, arguments);
- }
- outInfos.add(root);
- if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
- prefetchPredecessorsOfVirtualNode(root, view, provider, outInfos);
- }
- if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0) {
- prefetchSiblingsOfVirtualNode(root, view, provider, outInfos);
- }
- if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) {
- prefetchDescendantsOfVirtualNode(root, provider, outInfos);
- }
+ if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
+ prefetchPredecessorsOfVirtualNode(root, view, provider, outInfos);
+ }
+ if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0) {
+ prefetchSiblingsOfVirtualNode(root, view, provider, outInfos);
+ }
+ if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) {
+ prefetchDescendantsOfVirtualNode(root, provider, outInfos);
}
}
if (ENFORCE_NODE_TREE_CONSISTENT) {
- enforceNodeTreeConsistent(outInfos);
+ enforceNodeTreeConsistent(root, outInfos);
}
}
- private void enforceNodeTreeConsistent(List<AccessibilityNodeInfo> nodes) {
+ private boolean shouldStopPrefetching(List prefetchededInfos) {
+ return mHandler.hasUserInteractiveMessagesWaiting()
+ || prefetchededInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE;
+ }
+
+ private void enforceNodeTreeConsistent(
+ AccessibilityNodeInfo root, List<AccessibilityNodeInfo> nodes) {
LongSparseArray<AccessibilityNodeInfo> nodeMap =
new LongSparseArray<AccessibilityNodeInfo>();
final int nodeCount = nodes.size();
@@ -1114,7 +1197,6 @@
// If the nodes are a tree it does not matter from
// which node we start to search for the root.
- AccessibilityNodeInfo root = nodeMap.valueAt(0);
AccessibilityNodeInfo parent = root;
while (parent != null) {
root = parent;
@@ -1181,9 +1263,11 @@
private void prefetchPredecessorsOfRealNode(View view,
List<AccessibilityNodeInfo> outInfos) {
+ if (shouldStopPrefetching(outInfos)) {
+ return;
+ }
ViewParent parent = view.getParentForAccessibility();
- while (parent instanceof View
- && outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+ while (parent instanceof View && !shouldStopPrefetching(outInfos)) {
View parentView = (View) parent;
AccessibilityNodeInfo info = parentView.createAccessibilityNodeInfo();
if (info != null) {
@@ -1195,6 +1279,9 @@
private void prefetchSiblingsOfRealNode(View current,
List<AccessibilityNodeInfo> outInfos) {
+ if (shouldStopPrefetching(outInfos)) {
+ return;
+ }
ViewParent parent = current.getParentForAccessibility();
if (parent instanceof ViewGroup) {
ViewGroup parentGroup = (ViewGroup) parent;
@@ -1204,7 +1291,7 @@
parentGroup.addChildrenForAccessibility(children);
final int childCount = children.size();
for (int i = 0; i < childCount; i++) {
- if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+ if (shouldStopPrefetching(outInfos)) {
return;
}
View child = children.get(i);
@@ -1232,7 +1319,7 @@
private void prefetchDescendantsOfRealNode(View root,
List<AccessibilityNodeInfo> outInfos) {
- if (!(root instanceof ViewGroup)) {
+ if (shouldStopPrefetching(outInfos) || !(root instanceof ViewGroup)) {
return;
}
HashMap<View, AccessibilityNodeInfo> addedChildren =
@@ -1243,7 +1330,7 @@
root.addChildrenForAccessibility(children);
final int childCount = children.size();
for (int i = 0; i < childCount; i++) {
- if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+ if (shouldStopPrefetching(outInfos)) {
return;
}
View child = children.get(i);
@@ -1268,7 +1355,7 @@
} finally {
children.clear();
}
- if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+ if (!shouldStopPrefetching(outInfos)) {
for (Map.Entry<View, AccessibilityNodeInfo> entry : addedChildren.entrySet()) {
View addedChild = entry.getKey();
AccessibilityNodeInfo virtualRoot = entry.getValue();
@@ -1290,7 +1377,7 @@
long parentNodeId = root.getParentNodeId();
int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(parentNodeId);
while (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
- if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+ if (shouldStopPrefetching(outInfos)) {
return;
}
final int virtualDescendantId =
@@ -1335,7 +1422,7 @@
if (parent != null) {
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
- if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+ if (shouldStopPrefetching(outInfos)) {
return;
}
final long childNodeId = parent.getChildId(i);
@@ -1360,7 +1447,7 @@
final int initialOutInfosSize = outInfos.size();
final int childCount = root.getChildCount();
for (int i = 0; i < childCount; i++) {
- if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+ if (shouldStopPrefetching(outInfos)) {
return;
}
final long childNodeId = root.getChildId(i);
@@ -1370,7 +1457,7 @@
outInfos.add(child);
}
}
- if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+ if (!shouldStopPrefetching(outInfos)) {
final int addedChildCount = outInfos.size() - initialOutInfosSize;
for (int i = 0; i < addedChildCount; i++) {
AccessibilityNodeInfo child = outInfos.get(initialOutInfosSize + i);
@@ -1479,6 +1566,10 @@
boolean hasAccessibilityCallback(Message message) {
return message.what < FIRST_NO_ACCESSIBILITY_CALLBACK_MSG ? true : false;
}
+
+ boolean hasUserInteractiveMessagesWaiting() {
+ return hasMessagesOrCallbacks();
+ }
}
private final class AddNodeInfosForViewId implements Predicate<View> {
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 59299f6..5c65c65 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -744,7 +744,10 @@
}
try {
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW,
+ "Choreographer#doFrame " + vsyncEventData.id);
+ }
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
mFrameInfo.markInputHandlingStart();
diff --git a/core/java/android/view/InputEventAssigner.java b/core/java/android/view/InputEventAssigner.java
new file mode 100644
index 0000000..c159a12
--- /dev/null
+++ b/core/java/android/view/InputEventAssigner.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2021 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 android.view;
+
+import static android.os.IInputConstants.INVALID_INPUT_EVENT_ID;
+import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
+
+/**
+ * Process input events and assign input event id to a specific frame.
+ *
+ * The assigned input event id is determined by where the current gesture is relative to the vsync.
+ * In the middle of the gesture (we already processed some input events, and already received at
+ * least 1 vsync), the latest InputEvent is assigned to the next frame.
+ * If a gesture just started, then the ACTION_DOWN event will be assigned to the next frame.
+ *
+ * Consider the following sequence:
+ * DOWN -> VSYNC 1 -> MOVE 1 -> MOVE 2 -> VSYNC 2.
+ *
+ * For VSYNC 1, we will assign the "DOWN" input event.
+ * For VSYNC 2, we will assign the "MOVE 2" input event.
+ *
+ * Consider another sequence:
+ * DOWN -> MOVE 1 -> MOVE 2 -> VSYNC 1 -> MOVE 3 -> VSYNC 2.
+ *
+ * For VSYNC 1, we will still assign the "DOWN" input event. That means that "MOVE 1" and "MOVE 2"
+ * events are not attributed to any frame.
+ * For VSYNC 2, the "MOVE 3" input event will be assigned.
+ *
+ * @hide
+ */
+public class InputEventAssigner {
+ private static final String TAG = "InputEventAssigner";
+ private boolean mHasUnprocessedDown = false;
+ private int mEventId = INVALID_INPUT_EVENT_ID;
+
+ /**
+ * Notify InputEventAssigner that the Choreographer callback has been processed. This will reset
+ * the 'down' state to assign the latest input event to the current frame.
+ */
+ public void onChoreographerCallback() {
+ // Mark completion of this frame. Use newest input event from now on.
+ mHasUnprocessedDown = false;
+ }
+
+ /**
+ * Process the provided input event to determine which event id to assign to the current frame.
+ * @param event the input event currently being processed
+ * @return the id of the input event to use for the current frame
+ */
+ public int processEvent(InputEvent event) {
+ if (event instanceof KeyEvent) {
+ // We will not do any special handling for key events
+ return event.getId();
+ }
+
+ if (event instanceof MotionEvent) {
+ MotionEvent motionEvent = (MotionEvent) event;
+ final int action = motionEvent.getActionMasked();
+
+ if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
+ mHasUnprocessedDown = false;
+ }
+ if (motionEvent.isFromSource(SOURCE_TOUCHSCREEN) && action == MotionEvent.ACTION_DOWN) {
+ mHasUnprocessedDown = true;
+ mEventId = event.getId();
+ // This will remain 'true' even if we receive a MOVE event, as long as choreographer
+ // hasn't invoked the 'CALLBACK_INPUT' callback.
+ }
+ // Don't update the event id if we haven't processed DOWN yet.
+ if (!mHasUnprocessedDown) {
+ mEventId = event.getId();
+ }
+ return mEventId;
+ }
+
+ throw new IllegalArgumentException("Received unexpected " + event);
+ }
+}
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index d67439c..6801c27 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -3589,6 +3589,7 @@
msg.append(", deviceId=").append(getDeviceId());
msg.append(", source=0x").append(Integer.toHexString(getSource()));
msg.append(", displayId=").append(getDisplayId());
+ msg.append(", eventId=").append(getId());
}
msg.append(" }");
return msg.toString();
diff --git a/core/java/android/view/SurfaceControlFpsListener.java b/core/java/android/view/SurfaceControlFpsListener.java
index 517b0fb..20a511a 100644
--- a/core/java/android/view/SurfaceControlFpsListener.java
+++ b/core/java/android/view/SurfaceControlFpsListener.java
@@ -57,14 +57,14 @@
public abstract void onFpsReported(float fps);
/**
- * Registers the sampling listener.
+ * Registers the sampling listener for a particular task ID
*/
- public void register(@NonNull SurfaceControl layer) {
+ public void register(int taskId) {
if (mNativeListener == 0) {
return;
}
- nativeRegister(mNativeListener, layer.mNativeObject);
+ nativeRegister(mNativeListener, taskId);
}
/**
@@ -82,12 +82,13 @@
*
* Called from native code on a binder thread.
*/
- private static void dispatchOnFpsReported(SurfaceControlFpsListener listener, float fps) {
+ private static void dispatchOnFpsReported(
+ @NonNull SurfaceControlFpsListener listener, float fps) {
listener.onFpsReported(fps);
}
private static native long nativeCreate(SurfaceControlFpsListener thiz);
private static native void nativeDestroy(long ptr);
- private static native void nativeRegister(long ptr, long layerObject);
+ private static native void nativeRegister(long ptr, int taskId);
private static native void nativeUnregister(long ptr);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index ebef464..ab7732b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -22188,9 +22188,6 @@
* and hardware acceleration.
*/
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
- // Clear the overscroll effect:
- // TODO: Use internal API instead of overriding the existing RenderEffect
- setRenderEffect(null);
final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated();
/* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList.
diff --git a/core/java/android/view/ViewFrameInfo.java b/core/java/android/view/ViewFrameInfo.java
index d4aaa61..36bf532 100644
--- a/core/java/android/view/ViewFrameInfo.java
+++ b/core/java/android/view/ViewFrameInfo.java
@@ -17,6 +17,7 @@
package android.view;
import android.graphics.FrameInfo;
+import android.os.IInputConstants;
/**
* The timing information of events taking place in ViewRootImpl
@@ -24,32 +25,14 @@
*/
public class ViewFrameInfo {
public long drawStart;
- public long oldestInputEventTime; // the time of the oldest input event consumed for this frame
- public long newestInputEventTime; // the time of the newest input event consumed for this frame
+
+
// Various flags set to provide extra metadata about the current frame. See flag definitions
// inside FrameInfo.
// @see android.graphics.FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED
public long flags;
- /**
- * Update the oldest event time.
- * @param eventTime the time of the input event
- */
- public void updateOldestInputEvent(long eventTime) {
- if (oldestInputEventTime == 0 || eventTime < oldestInputEventTime) {
- oldestInputEventTime = eventTime;
- }
- }
-
- /**
- * Update the newest event time.
- * @param eventTime the time of the input event
- */
- public void updateNewestInputEvent(long eventTime) {
- if (newestInputEventTime == 0 || eventTime > newestInputEventTime) {
- newestInputEventTime = eventTime;
- }
- }
+ private int mInputEventId;
/**
* Populate the missing fields using the data from ViewFrameInfo
@@ -58,8 +41,7 @@
public void populateFrameInfo(FrameInfo frameInfo) {
frameInfo.frameInfo[FrameInfo.FLAGS] |= flags;
frameInfo.frameInfo[FrameInfo.DRAW_START] = drawStart;
- // TODO(b/169866723): Use InputEventAssigner
- frameInfo.frameInfo[FrameInfo.INPUT_EVENT_ID] = newestInputEventTime;
+ frameInfo.frameInfo[FrameInfo.INPUT_EVENT_ID] = mInputEventId;
}
/**
@@ -67,8 +49,7 @@
*/
public void reset() {
drawStart = 0;
- oldestInputEventTime = 0;
- newestInputEventTime = 0;
+ mInputEventId = IInputConstants.INVALID_INPUT_EVENT_ID;
flags = 0;
}
@@ -78,4 +59,12 @@
public void markDrawStart() {
drawStart = System.nanoTime();
}
+
+ /**
+ * Assign the value for input event id
+ * @param eventId the id of the input event
+ */
+ public void setInputEvent(int eventId) {
+ mInputEventId = eventId;
+ }
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index f8e65bd..390e3ae 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -457,6 +457,7 @@
FallbackEventHandler mFallbackEventHandler;
final Choreographer mChoreographer;
protected final ViewFrameInfo mViewFrameInfo = new ViewFrameInfo();
+ private final InputEventAssigner mInputEventAssigner = new InputEventAssigner();
/**
* Update the Choreographer's FrameInfo object with the timing information for the current
@@ -8352,16 +8353,7 @@
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
mPendingInputEventCount);
- long eventTime = q.mEvent.getEventTimeNano();
- long oldestEventTime = eventTime;
- if (q.mEvent instanceof MotionEvent) {
- MotionEvent me = (MotionEvent)q.mEvent;
- if (me.getHistorySize() > 0) {
- oldestEventTime = me.getHistoricalEventTimeNano(0);
- }
- }
- mViewFrameInfo.updateOldestInputEvent(oldestEventTime);
- mViewFrameInfo.updateNewestInputEvent(eventTime);
+ mViewFrameInfo.setInputEvent(mInputEventAssigner.processEvent(q.mEvent));
deliverInputEvent(q);
}
@@ -8497,6 +8489,11 @@
consumedBatches = false;
}
doProcessInputEvents();
+ if (consumedBatches) {
+ // Must be done after we processed the input events, to mark the completion of the frame
+ // from the input point of view
+ mInputEventAssigner.onChoreographerCallback();
+ }
return consumedBatches;
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 1819da4..7e9a850 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -613,6 +613,10 @@
* For example, for activities in multi-window mode, the metrics returned are based on the
* current bounds that the user has selected for the {@link android.app.Activity Activity}'s
* task.
+ * <p>
+ * In most scenarios, {@link #getCurrentWindowMetrics()} rather than
+ * {@link #getMaximumWindowMetrics()} is the correct API to use, since it ensures values reflect
+ * window size when the app is not fullscreen.
*
* @see #getMaximumWindowMetrics()
* @see WindowMetrics
@@ -624,26 +628,27 @@
/**
* Returns the largest {@link WindowMetrics} an app may expect in the current system state.
* <p>
- * The metrics describe the size of the largest potential area the window might occupy with
- * {@link LayoutParams#MATCH_PARENT MATCH_PARENT} width and height, and the {@link WindowInsets}
- * such a window would have.
- * <p>
* The value of this is based on the largest <b>potential</b> windowing state of the system.
*
* For example, for activities in multi-window mode, the metrics returned are based on the
* what the bounds would be if the user expanded the {@link android.app.Activity Activity}'s
* task to cover the entire screen.
- *
+ * <p>
+ * The metrics describe the size of the largest potential area the window might occupy with
+ * {@link LayoutParams#MATCH_PARENT MATCH_PARENT} width and height, and the {@link WindowInsets}
+ * such a window would have.
+ * <p>
* Note that this might still be smaller than the size of the physical display if certain areas
* of the display are not available to windows created in this {@link Context}.
- * <p>
+ *
* For example, given that there's a device which have a multi-task mode to limit activities
* to a half screen. In this case, {@link #getMaximumWindowMetrics()} reports the bounds of
- * the half screen which the activity is located, while {@link Display#getRealSize(Point)} still
- * reports the bounds of the whole physical display.
- *
- * Despite this, {@link #getMaximumWindowMetrics()} and {@link Display#getRealSize(Point)}
- * reports the same bounds in general.
+ * the half screen which the activity is located.
+ * <p>
+ * <b>Generally {@link #getCurrentWindowMetrics()} is the correct API to use</b> for choosing
+ * UI layouts. {@link #getMaximumWindowMetrics()} are only appropriate when the application
+ * needs to know the largest possible size it can occupy if the user expands/maximizes it on the
+ * screen.
*
* @see #getCurrentWindowMetrics()
* @see WindowMetrics
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 7cc2db1..72d403e 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -149,8 +149,15 @@
if (((attrs.inputFeatures &
WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0)) {
try {
- mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, attrs.flags,
+ if(mRealWm instanceof IWindowSession.Stub) {
+ mRealWm.grantInputChannel(displayId,
+ new SurfaceControl(sc, "WindowlessWindowManager.addToDisplay"),
+ window, mHostInputToken, attrs.flags, attrs.privateFlags, attrs.type,
+ outInputChannel);
+ } else {
+ mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, attrs.flags,
attrs.privateFlags, attrs.type, outInputChannel);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Failed to grant input to surface: ", e);
}
@@ -293,8 +300,14 @@
if ((attrChanges & WindowManager.LayoutParams.FLAGS_CHANGED) != 0
&& state.mInputChannelToken != null) {
try {
- mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId, sc,
- attrs.flags, attrs.privateFlags, state.mInputRegion);
+ if(mRealWm instanceof IWindowSession.Stub) {
+ mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId,
+ new SurfaceControl(sc, "WindowlessWindowManager.relayout"),
+ attrs.flags, attrs.privateFlags, state.mInputRegion);
+ } else {
+ mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId, sc,
+ attrs.flags, attrs.privateFlags, state.mInputRegion);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Failed to update surface input channel: ", e);
}
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index f63749b..8d1271d 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -23,7 +23,9 @@
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
@@ -113,6 +115,8 @@
private final Object mInstanceLock = new Object();
+ private Handler mMainHandler;
+
private volatile int mInteractionId = -1;
private AccessibilityNodeInfo mFindAccessibilityNodeInfoResult;
@@ -123,6 +127,11 @@
private Message mSameThreadMessage;
+ private int mInteractionIdWaitingForPrefetchResult;
+ private int mConnectionIdWaitingForPrefetchResult;
+ private String[] mPackageNamesForNextPrefetchResult;
+ private Runnable mPrefetchResultRunnable;
+
/**
* @return The client for the current thread.
*/
@@ -197,6 +206,10 @@
private AccessibilityInteractionClient() {
/* reducing constructor visibility */
+ Looper mainLooper = Looper.getMainLooper();
+ if (mainLooper != null) {
+ mMainHandler = new Handler(mainLooper);
+ }
}
/**
@@ -451,16 +464,16 @@
Binder.restoreCallingIdentity(identityToken);
}
if (packageNames != null) {
- List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
- interactionId);
- finalizeAndCacheAccessibilityNodeInfos(infos, connectionId,
- bypassCache, packageNames);
- if (infos != null && !infos.isEmpty()) {
- for (int i = 1; i < infos.size(); i++) {
- infos.get(i).recycle();
- }
- return infos.get(0);
+ AccessibilityNodeInfo info =
+ getFindAccessibilityNodeInfoResultAndClear(interactionId);
+ if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_MASK) != 0
+ && info != null) {
+ setInteractionWaitingForPrefetchResult(interactionId, connectionId,
+ packageNames);
}
+ finalizeAndCacheAccessibilityNodeInfo(info, connectionId,
+ bypassCache, packageNames);
+ return info;
}
} else {
if (DEBUG) {
@@ -474,6 +487,15 @@
return null;
}
+ private void setInteractionWaitingForPrefetchResult(int interactionId, int connectionId,
+ String[] packageNames) {
+ synchronized (mInstanceLock) {
+ mInteractionIdWaitingForPrefetchResult = interactionId;
+ mConnectionIdWaitingForPrefetchResult = connectionId;
+ mPackageNamesForNextPrefetchResult = packageNames;
+ }
+ }
+
private static String idToString(int accessibilityWindowId, long accessibilityNodeId) {
return accessibilityWindowId + "/"
+ AccessibilityNodeInfo.idToString(accessibilityNodeId);
@@ -829,6 +851,59 @@
}
/**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setPrefetchAccessibilityNodeInfoResult(@NonNull List<AccessibilityNodeInfo> infos,
+ int interactionId) {
+ List<AccessibilityNodeInfo> infosCopy = null;
+ int mConnectionIdWaitingForPrefetchResultCopy = -1;
+ String[] mPackageNamesForNextPrefetchResultCopy = null;
+
+ synchronized (mInstanceLock) {
+ if (!infos.isEmpty() && mInteractionIdWaitingForPrefetchResult == interactionId) {
+ if (mMainHandler != null) {
+ if (mPrefetchResultRunnable != null) {
+ mMainHandler.removeCallbacks(mPrefetchResultRunnable);
+ mPrefetchResultRunnable = null;
+ }
+ /**
+ * TODO(b/180957109): AccessibilityCache is prone to deadlocks
+ * We post caching the prefetched nodes in the main thread. Using the binder
+ * thread results in "Long monitor contention with owner main" logs where
+ * service response times may exceed 5 seconds. This is due to the cache calling
+ * out to the system when refreshing nodes with the lock held.
+ */
+ mPrefetchResultRunnable = () -> finalizeAndCacheAccessibilityNodeInfos(
+ infos, mConnectionIdWaitingForPrefetchResult, false,
+ mPackageNamesForNextPrefetchResult);
+ mMainHandler.post(mPrefetchResultRunnable);
+
+ } else {
+ for (AccessibilityNodeInfo info : infos) {
+ infosCopy.add(new AccessibilityNodeInfo(info));
+ }
+ mConnectionIdWaitingForPrefetchResultCopy =
+ mConnectionIdWaitingForPrefetchResult;
+ mPackageNamesForNextPrefetchResultCopy =
+ new String[mPackageNamesForNextPrefetchResult.length];
+ for (int i = 0; i < mPackageNamesForNextPrefetchResult.length; i++) {
+ mPackageNamesForNextPrefetchResultCopy[i] =
+ mPackageNamesForNextPrefetchResult[i];
+ }
+ }
+ }
+
+ }
+
+ if (infosCopy != null) {
+ finalizeAndCacheAccessibilityNodeInfos(
+ infosCopy, mConnectionIdWaitingForPrefetchResultCopy, false,
+ mPackageNamesForNextPrefetchResultCopy);
+ }
+ }
+
+ /**
* Gets the result of a request to perform an accessibility action.
*
* @param interactionId The interaction id to match the result with the request.
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
index 049bb31..231e75a 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
@@ -47,6 +47,15 @@
int interactionId);
/**
+ * Sets the result of a prefetch request that returns {@link AccessibilityNodeInfo}s.
+ *
+ * @param root The {@link AccessibilityNodeInfo} for which the prefetching is based off of.
+ * @param infos The result {@link AccessibilityNodeInfo}s.
+ */
+ void setPrefetchAccessibilityNodeInfoResult(
+ in List<AccessibilityNodeInfo> infos, int interactionId);
+
+ /**
* Sets the result of a request to perform an accessibility action.
*
* @param Whether the action was performed.
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 4f0c568..208cd96 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -249,6 +249,18 @@
public static final String EXTRA_CLIENT_STATE =
"android.view.autofill.extra.CLIENT_STATE";
+ /**
+ * Intent extra: the {@link android.view.inputmethod.InlineSuggestionsRequest} in the
+ * autofill request.
+ *
+ * <p>This is filled in the authentication intent so the
+ * {@link android.service.autofill.AutofillService} can use it to create the inline
+ * suggestion {@link android.service.autofill.Dataset} in the response, if the original autofill
+ * request contains the {@link android.view.inputmethod.InlineSuggestionsRequest}.
+ */
+ public static final String EXTRA_INLINE_SUGGESTIONS_REQUEST =
+ "android.view.autofill.extra.INLINE_SUGGESTIONS_REQUEST";
+
/** @hide */
public static final String EXTRA_RESTORE_SESSION_TOKEN =
"android.view.autofill.extra.RESTORE_SESSION_TOKEN";
diff --git a/core/java/android/view/displayhash/DisplayHashResultCallback.java b/core/java/android/view/displayhash/DisplayHashResultCallback.java
index 15b29ad..04d29ee 100644
--- a/core/java/android/view/displayhash/DisplayHashResultCallback.java
+++ b/core/java/android/view/displayhash/DisplayHashResultCallback.java
@@ -66,12 +66,19 @@
*/
int DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN = -4;
+ /**
+ * The hash algorithm sent to generate the hash was invalid. This means the value is not one
+ * of the supported values in {@link DisplayHashManager#getSupportedHashAlgorithms()}
+ */
+ int DISPLAY_HASH_ERROR_INVALID_HASH_ALGORITHM = -5;
+
/** @hide */
@IntDef(prefix = {"DISPLAY_HASH_ERROR_"}, value = {
DISPLAY_HASH_ERROR_UNKNOWN,
DISPLAY_HASH_ERROR_INVALID_BOUNDS,
DISPLAY_HASH_ERROR_MISSING_WINDOW,
- DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN
+ DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN,
+ DISPLAY_HASH_ERROR_INVALID_HASH_ALGORITHM
})
@Retention(RetentionPolicy.SOURCE)
@interface DisplayHashErrorCode {
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 1b62266..dc42ad5 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -29,7 +29,6 @@
import android.graphics.Paint;
import android.graphics.RecordingCanvas;
import android.graphics.Rect;
-import android.graphics.RenderEffect;
import android.graphics.RenderNode;
import android.os.Build;
import android.util.AttributeSet;
@@ -83,6 +82,8 @@
public @interface EdgeEffectType {
}
+ private static final float DEFAULT_MAX_STRETCH_INTENSITY = 1.5f;
+
@SuppressWarnings("UnusedDeclaration")
private static final String TAG = "EdgeEffect";
@@ -128,6 +129,8 @@
private long mStartTime;
private float mDuration;
+ private float mStretchIntensity = DEFAULT_MAX_STRETCH_INTENSITY;
+ private float mStretchDistance = -1f;
private final Interpolator mInterpolator;
@@ -146,6 +149,8 @@
private float mPullDistance;
private final Rect mBounds = new Rect();
+ private float mWidth;
+ private float mHeight;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769450)
private final Paint mPaint = new Paint();
private float mRadius;
@@ -202,6 +207,19 @@
mBaseGlowScale = h > 0 ? Math.min(oh / h, 1.f) : 1.f;
mBounds.set(mBounds.left, mBounds.top, width, (int) Math.min(height, h));
+
+ mWidth = width;
+ mHeight = height;
+ }
+
+ /**
+ * Configure the distance in pixels to stretch the content. This is only consumed as part
+ * if {@link #setType(int)} is set to {@link #TYPE_STRETCH}
+ * @param stretchDistance Stretch distance in pixels when the target View is overscrolled
+ * @hide
+ */
+ public void setStretchDistance(float stretchDistance) {
+ mStretchDistance = stretchDistance;
}
/**
@@ -437,6 +455,13 @@
}
/**
+ * @hide
+ */
+ public void setMaxStretchIntensity(float stretchIntensity) {
+ mStretchIntensity = stretchIntensity;
+ }
+
+ /**
* Set or clear the blend mode. A blend mode defines how source pixels
* (generated by a drawing command) are composited with the destination pixels
* (content of the render target).
@@ -520,23 +545,55 @@
RecordingCanvas recordingCanvas = (RecordingCanvas) canvas;
if (mTmpMatrix == null) {
mTmpMatrix = new Matrix();
- mTmpPoints = new float[4];
+ mTmpPoints = new float[12];
}
//noinspection deprecation
recordingCanvas.getMatrix(mTmpMatrix);
- mTmpPoints[0] = mBounds.width() * mDisplacement;
- mTmpPoints[1] = mDistance * mBounds.height();
- mTmpPoints[2] = mTmpPoints[0];
- mTmpPoints[3] = 0;
+
+ mTmpPoints[0] = 0;
+ mTmpPoints[1] = 0; // top-left
+ mTmpPoints[2] = mWidth;
+ mTmpPoints[3] = 0; // top-right
+ mTmpPoints[4] = mWidth;
+ mTmpPoints[5] = mHeight; // bottom-right
+ mTmpPoints[6] = 0;
+ mTmpPoints[7] = mHeight; // bottom-left
+ mTmpPoints[8] = mWidth * mDisplacement;
+ mTmpPoints[9] = 0; // drag start point
+ mTmpPoints[10] = mWidth * mDisplacement;
+ mTmpPoints[11] = mHeight * mDistance; // drag point
mTmpMatrix.mapPoints(mTmpPoints);
- float x = mTmpPoints[0] - mTmpPoints[2];
- float y = mTmpPoints[1] - mTmpPoints[3];
RenderNode renderNode = recordingCanvas.mNode;
- // TODO: use stretchy RenderEffect and use internal API when it is ready
- // TODO: wrap existing RenderEffect
- renderNode.setRenderEffect(RenderEffect.createOffsetEffect(x, y));
+ float left = renderNode.getLeft()
+ + min(mTmpPoints[0], mTmpPoints[2], mTmpPoints[4], mTmpPoints[6]);
+ float top = renderNode.getTop()
+ + min(mTmpPoints[1], mTmpPoints[3], mTmpPoints[5], mTmpPoints[7]);
+ float right = renderNode.getLeft()
+ + max(mTmpPoints[0], mTmpPoints[2], mTmpPoints[4], mTmpPoints[6]);
+ float bottom = renderNode.getTop()
+ + max(mTmpPoints[1], mTmpPoints[3], mTmpPoints[5], mTmpPoints[7]);
+ // assume rotations of increments of 90 degrees
+ float x = mTmpPoints[10] - mTmpPoints[8];
+ float width = right - left;
+ float vecX = Math.max(-1f, Math.min(1f, x / width));
+ float y = mTmpPoints[11] - mTmpPoints[9];
+ float height = bottom - top;
+ float vecY = Math.max(-1f, Math.min(1f, y / height));
+ renderNode.stretch(
+ left,
+ top,
+ right,
+ bottom,
+ vecX * mStretchIntensity,
+ vecY * mStretchIntensity,
+ // TODO (njawad/mount) figure out proper stretch distance from UX
+ // for now leverage placeholder logic if no stretch distance is provided to
+ // consume the displacement ratio times the minimum of the width or height
+ mStretchDistance > 0 ? mStretchDistance :
+ (mDisplacement * Math.min(mWidth, mHeight))
+ );
}
boolean oneLastFrame = false;
@@ -548,6 +605,18 @@
return mState != STATE_IDLE || oneLastFrame;
}
+ private float min(float f1, float f2, float f3, float f4) {
+ float min = Math.min(f1, f2);
+ min = Math.min(min, f3);
+ return Math.min(min, f4);
+ }
+
+ private float max(float f1, float f2, float f3, float f4) {
+ float max = Math.max(f1, f2);
+ max = Math.max(max, f3);
+ return Math.max(max, f4);
+ }
+
/**
* Return the maximum height that the edge effect will be drawn at given the original
* {@link #setSize(int, int) input size}.
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 23915e0..bf552e2 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -249,6 +249,26 @@
}
/**
+ * API used for prototyping stretch effect parameters in framework sample apps
+ * @hide
+ */
+ public void setEdgeEffectIntensity(float intensity) {
+ mEdgeGlowLeft.setMaxStretchIntensity(intensity);
+ mEdgeGlowRight.setMaxStretchIntensity(intensity);
+ invalidate();
+ }
+
+ /**
+ * API used for prototyping stretch effect parameters in the framework sample apps
+ * @hide
+ */
+ public void setStretchDistance(float distance) {
+ mEdgeGlowLeft.setStretchDistance(distance);
+ mEdgeGlowRight.setStretchDistance(distance);
+ invalidate();
+ }
+
+ /**
* Sets the right edge effect color.
*
* @param color The color for the right edge effect.
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 2cf50bb..dfb2263 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -51,7 +51,6 @@
import android.graphics.Bitmap;
import android.graphics.BlendMode;
import android.graphics.Outline;
-import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -76,6 +75,7 @@
import android.util.IntArray;
import android.util.Log;
import android.util.Pair;
+import android.util.SizeF;
import android.util.SparseIntArray;
import android.util.TypedValue;
import android.util.TypedValue.ComplexDimensionUnit;
@@ -353,7 +353,7 @@
* Only to be used on children views used in a {@link RemoteViews} with
* {@link RemoteViews#hasSizedRemoteViews()}.
*/
- private PointF mIdealSize = null;
+ private SizeF mIdealSize = null;
@ApplyFlags
private int mApplyFlags = 0;
@@ -3042,11 +3042,11 @@
return mSizedRemoteViews != null;
}
- private @Nullable PointF getIdealSize() {
+ private @Nullable SizeF getIdealSize() {
return mIdealSize;
}
- private void setIdealSize(@Nullable PointF size) {
+ private void setIdealSize(@Nullable SizeF size) {
mIdealSize = size;
}
@@ -3094,13 +3094,18 @@
* Create a new RemoteViews object that will inflate the layout with the closest size
* specification.
*
- * The default remote views in that case is always the smallest one provided.
+ * The default remote views in that case is always the one with the smallest area.
+ *
+ * If the {@link RemoteViews} host provides the size of the view, the layout with the largest
+ * area that fits entirely in the provided size will be used (i.e. the width and height of
+ * the layout must be less than the size of the view, with a 1dp margin to account for
+ * rounding). If no layout fits in the view, the layout with the smallest area will be used.
*
* @param remoteViews Mapping of size to layout.
* @throws IllegalArgumentException if the map is empty, there are more than
* MAX_INIT_VIEW_COUNT layouts or the remote views are not all from the same application.
*/
- public RemoteViews(@NonNull Map<PointF, RemoteViews> remoteViews) {
+ public RemoteViews(@NonNull Map<SizeF, RemoteViews> remoteViews) {
if (remoteViews.isEmpty()) {
throw new IllegalArgumentException("The set of RemoteViews cannot be empty");
}
@@ -3135,8 +3140,8 @@
RemoteViews smallestView = null;
while (remoteViews.hasNext()) {
RemoteViews view = remoteViews.next();
- PointF size = view.getIdealSize();
- float newViewArea = size.x * size.y;
+ SizeF size = view.getIdealSize();
+ float newViewArea = size.getWidth() * size.getHeight();
if (smallestView != null && !view.hasSameAppInfo(smallestView.mApplication)) {
throw new IllegalArgumentException(
"All RemoteViews must share the same package and user");
@@ -3239,7 +3244,7 @@
if (mode == MODE_NORMAL) {
mApplication = parcel.readInt() == 0 ? info :
ApplicationInfo.CREATOR.createFromParcel(parcel);
- mIdealSize = parcel.readInt() == 0 ? null : PointF.CREATOR.createFromParcel(parcel);
+ mIdealSize = parcel.readInt() == 0 ? null : SizeF.CREATOR.createFromParcel(parcel);
mLayoutId = parcel.readInt();
mLightBackgroundLayoutId = parcel.readInt();
@@ -4625,9 +4630,9 @@
*
* This is particularly useful when we only care about the ordering of the distances.
*/
- private static float squareDistance(PointF p1, PointF p2) {
- float dx = p1.x - p2.x;
- float dy = p1.y - p2.y;
+ private static float squareDistance(SizeF p1, SizeF p2) {
+ float dx = p1.getWidth() - p2.getWidth();
+ float dy = p1.getHeight() - p2.getHeight();
return dx * dx + dy * dy;
}
@@ -4637,31 +4642,17 @@
* A layout fits on a widget if the widget size is known (i.e. not null) and both dimensions
* are smaller than the ones of the widget, adding some padding to account for rounding errors.
*/
- private static boolean fitsIn(PointF sizeLayout, @Nullable PointF sizeWidget) {
- return sizeWidget != null && (Math.ceil(sizeWidget.x) + 1 > sizeLayout.x)
- && (Math.ceil(sizeWidget.y) + 1 > sizeLayout.y);
+ private static boolean fitsIn(SizeF sizeLayout, @Nullable SizeF sizeWidget) {
+ return sizeWidget != null && (Math.ceil(sizeWidget.getWidth()) + 1 > sizeLayout.getWidth())
+ && (Math.ceil(sizeWidget.getHeight()) + 1 > sizeLayout.getHeight());
}
- /**
- * Returns the most appropriate {@link RemoteViews} given the context and, if not null, the
- * size of the widget.
- *
- * If {@link RemoteViews#hasSizedRemoteViews()} returns true, the most appropriate view is
- * the one that fits in the widget (according to {@link RemoteViews#fitsIn}) and has the
- * diagonal the most similar to the widget. If no layout fits or the size of the widget is
- * not specified, the one with the smallest area will be chosen.
- */
- private RemoteViews getRemoteViewsToApply(@NonNull Context context,
- @Nullable PointF widgetSize) {
- if (!hasSizedRemoteViews()) {
- // If there isn't multiple remote views, fall back on the previous methods.
- return getRemoteViewsToApply(context);
- }
+ private RemoteViews findBestFitLayout(@NonNull SizeF widgetSize) {
// Find the better remote view
RemoteViews bestFit = null;
float bestSqDist = Float.MAX_VALUE;
for (RemoteViews layout : mSizedRemoteViews) {
- PointF layoutSize = layout.getIdealSize();
+ SizeF layoutSize = layout.getIdealSize();
if (fitsIn(layoutSize, widgetSize)) {
if (bestFit == null) {
bestFit = layout;
@@ -4682,6 +4673,46 @@
return bestFit;
}
+ /**
+ * Returns the most appropriate {@link RemoteViews} given the context and, if not null, the
+ * size of the widget.
+ *
+ * If {@link RemoteViews#hasSizedRemoteViews()} returns true, the most appropriate view is
+ * the one that fits in the widget (according to {@link RemoteViews#fitsIn}) and has the
+ * diagonal the most similar to the widget. If no layout fits or the size of the widget is
+ * not specified, the one with the smallest area will be chosen.
+ *
+ * @hide
+ */
+ public RemoteViews getRemoteViewsToApply(@NonNull Context context,
+ @Nullable SizeF widgetSize) {
+ if (!hasSizedRemoteViews()) {
+ // If there isn't multiple remote views, fall back on the previous methods.
+ return getRemoteViewsToApply(context);
+ }
+ return findBestFitLayout(widgetSize);
+ }
+
+ /**
+ * Checks whether the change of size will lead to using a different {@link RemoteViews}.
+ *
+ * @hide
+ */
+ @Nullable
+ public RemoteViews getRemoteViewsToApplyIfDifferent(@Nullable SizeF oldSize,
+ @NonNull SizeF newSize) {
+ if (!hasSizedRemoteViews()) {
+ return null;
+ }
+ RemoteViews oldBestFit = oldSize == null ? findSmallestRemoteView() : findBestFitLayout(
+ oldSize);
+ RemoteViews newBestFit = findBestFitLayout(newSize);
+ if (oldBestFit != newBestFit) {
+ return newBestFit;
+ }
+ return null;
+ }
+
/**
* Inflates the view hierarchy represented by this object and applies
@@ -4705,7 +4736,7 @@
/** @hide */
public View apply(@NonNull Context context, @NonNull ViewGroup parent,
- @Nullable InteractionHandler handler, @Nullable PointF size) {
+ @Nullable InteractionHandler handler, @Nullable SizeF size) {
RemoteViews rvToApply = getRemoteViewsToApply(context, size);
View result = inflateView(context, rvToApply, parent);
@@ -4722,7 +4753,7 @@
/** @hide */
public View applyWithTheme(@NonNull Context context, @NonNull ViewGroup parent,
@Nullable InteractionHandler handler, @StyleRes int applyThemeResId,
- @Nullable PointF size) {
+ @Nullable SizeF size) {
RemoteViews rvToApply = getRemoteViewsToApply(context, size);
View result = inflateView(context, rvToApply, parent, applyThemeResId, null);
@@ -4732,7 +4763,7 @@
/** @hide */
public View apply(Context context, ViewGroup parent, InteractionHandler handler,
- @NonNull PointF size, @Nullable ColorResources colorResources) {
+ @NonNull SizeF size, @Nullable ColorResources colorResources) {
RemoteViews rvToApply = getRemoteViewsToApply(context, size);
View result = inflateView(context, rvToApply, parent, 0, colorResources);
@@ -4828,21 +4859,21 @@
/** @hide */
public CancellationSignal applyAsync(Context context, ViewGroup parent,
Executor executor, OnViewAppliedListener listener, InteractionHandler handler,
- PointF size) {
+ SizeF size) {
return getAsyncApplyTask(context, parent, listener, handler, size, null /* themeColors */)
.startTaskOnExecutor(executor);
}
/** @hide */
public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor,
- OnViewAppliedListener listener, InteractionHandler handler, PointF size,
+ OnViewAppliedListener listener, InteractionHandler handler, SizeF size,
ColorResources colorResources) {
return getAsyncApplyTask(context, parent, listener, handler, size, colorResources)
.startTaskOnExecutor(executor);
}
private AsyncApplyTask getAsyncApplyTask(Context context, ViewGroup parent,
- OnViewAppliedListener listener, InteractionHandler handler, PointF size,
+ OnViewAppliedListener listener, InteractionHandler handler, SizeF size,
ColorResources colorResources) {
return new AsyncApplyTask(getRemoteViewsToApply(context, size), parent, context, listener,
handler, colorResources, null /* result */);
@@ -4968,7 +4999,7 @@
}
/** @hide */
- public void reapply(Context context, View v, InteractionHandler handler, PointF size,
+ public void reapply(Context context, View v, InteractionHandler handler, SizeF size,
ColorResources colorResources) {
RemoteViews rvToApply = getRemoteViewsToApply(context, size);
@@ -5012,7 +5043,7 @@
/** @hide */
public CancellationSignal reapplyAsync(Context context, View v, Executor executor,
- OnViewAppliedListener listener, InteractionHandler handler, PointF size,
+ OnViewAppliedListener listener, InteractionHandler handler, SizeF size,
ColorResources colorResources) {
RemoteViews rvToApply = getRemoteViewsToApply(context, size);
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 65f3da7..3006729 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -281,6 +281,26 @@
}
/**
+ * API used for prototyping stretch effect parameters in framework sample apps
+ * @hide
+ */
+ public void setEdgeEffectIntensity(float intensity) {
+ mEdgeGlowTop.setMaxStretchIntensity(intensity);
+ mEdgeGlowBottom.setMaxStretchIntensity(intensity);
+ invalidate();
+ }
+
+ /**
+ * API used for prototyping stretch effect parameters in the framework sample apps
+ * @hide
+ */
+ public void setStretchDistance(float distance) {
+ mEdgeGlowTop.setStretchDistance(distance);
+ mEdgeGlowBottom.setStretchDistance(distance);
+ invalidate();
+ }
+
+ /**
* Sets the bottom edge effect color.
*
* @param color The color for the bottom edge effect.
diff --git a/core/java/android/window/TransitionFilter.java b/core/java/android/window/TransitionFilter.java
index 4421f06..141f47b 100644
--- a/core/java/android/window/TransitionFilter.java
+++ b/core/java/android/window/TransitionFilter.java
@@ -139,8 +139,8 @@
boolean matches(@NonNull TransitionInfo info) {
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
- if (change.getParent() != null) {
- // Only look at the top animating windows.
+ if (!TransitionInfo.isIndependent(change, info)) {
+ // Only look at independent animating windows.
continue;
}
if (mActivityType != ACTIVITY_TYPE_UNDEFINED) {
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index d1d49b6..499ce25 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -246,6 +246,33 @@
return sb.toString();
}
+ /**
+ * Indication that `change` is independent of parents (ie. it has a different type of
+ * transition vs. "going along for the ride")
+ */
+ public static boolean isIndependent(TransitionInfo.Change change, TransitionInfo info) {
+ // If the change has no parent (it is root), then it is independent
+ if (change.getParent() == null) return true;
+
+ // non-visibility changes will just be folded into the parent change, so they aren't
+ // independent either.
+ if (change.getMode() == TRANSIT_CHANGE) return false;
+
+ TransitionInfo.Change parentChg = info.getChange(change.getParent());
+ while (parentChg != null) {
+ // If the parent is a visibility change, it will include the results of all child
+ // changes into itself, so none of its children can be independent.
+ if (parentChg.getMode() != TRANSIT_CHANGE) return false;
+
+ // If there are no more parents left, then all the parents, so far, have not been
+ // visibility changes which means this change is indpendent.
+ if (parentChg.getParent() == null) return true;
+
+ parentChg = info.getChange(parentChg.getParent());
+ }
+ return false;
+ }
+
/** Represents the change a WindowContainer undergoes during a transition */
public static final class Change implements Parcelable {
private final WindowContainerToken mContainer;
diff --git a/core/java/com/android/internal/graphics/palette/WuQuantizer.java b/core/java/com/android/internal/graphics/palette/WuQuantizer.java
index 01e45f6..66206bf 100644
--- a/core/java/com/android/internal/graphics/palette/WuQuantizer.java
+++ b/core/java/com/android/internal/graphics/palette/WuQuantizer.java
@@ -16,7 +16,6 @@
package com.android.internal.graphics.palette;
-
import java.util.ArrayList;
import java.util.List;
@@ -120,7 +119,11 @@
}
}
- for (k = 0; k < mMaxColors; ++k) {
+ // If extraction is run on a set of pixels whose count is less than the
+ // number of max colors, then colors.length < max colors, and accesses
+ // to colors[index] inside the for loop throw an ArrayOutOfBoundsException.
+ int numColorsToCreate = (int) Math.min(mMaxColors, colors.length);
+ for (k = 0; k < numColorsToCreate; ++k) {
weight = getVolume(cube[k], mWt);
if (weight > 0) {
red = (int) (getVolume(cube[k], mMr) / weight);
diff --git a/core/java/com/android/internal/inputmethod/CallbackUtils.java b/core/java/com/android/internal/inputmethod/CallbackUtils.java
index 2113173..3958b9e 100644
--- a/core/java/com/android/internal/inputmethod/CallbackUtils.java
+++ b/core/java/com/android/internal/inputmethod/CallbackUtils.java
@@ -225,4 +225,31 @@
callback.onResult();
} catch (RemoteException ignored) { }
}
+
+ /**
+ * A utility method using given {@link IIInputContentUriTokenResultCallback} to callback the
+ * result.
+ *
+ * @param callback {@link IIInputContentUriTokenResultCallback} to be called back.
+ * @param resultSupplier the supplier from which the result is provided.
+ */
+ public static void onResult(@NonNull IIInputContentUriTokenResultCallback callback,
+ @NonNull Supplier<IInputContentUriToken> resultSupplier) {
+ IInputContentUriToken result = null;
+ Throwable exception = null;
+
+ try {
+ result = resultSupplier.get();
+ } catch (Throwable throwable) {
+ exception = throwable;
+ }
+
+ try {
+ if (exception != null) {
+ callback.onError(ThrowableHolder.of(exception));
+ return;
+ }
+ callback.onResult(result);
+ } catch (RemoteException ignored) { }
+ }
}
diff --git a/core/java/com/android/internal/inputmethod/Completable.java b/core/java/com/android/internal/inputmethod/Completable.java
index d6a4663..ba3a343 100644
--- a/core/java/com/android/internal/inputmethod/Completable.java
+++ b/core/java/com/android/internal/inputmethod/Completable.java
@@ -444,6 +444,13 @@
}
/**
+ * @return an instance of {@link Completable.IInputContentUriToken}.
+ */
+ public static Completable.IInputContentUriToken createIInputContentUriToken() {
+ return new Completable.IInputContentUriToken();
+ }
+
+ /**
* @return an instance of {@link Completable.Void}.
*/
public static Completable.Void createVoid() {
@@ -497,6 +504,12 @@
extends Values<List<android.view.inputmethod.InputMethodInfo>> { }
/**
+ * Completable object of {@link IInputContentUriToken>}.
+ */
+ public static final class IInputContentUriToken
+ extends Values<com.android.internal.inputmethod.IInputContentUriToken> { }
+
+ /**
* Await the result by the {@link Completable.Values}.
*
* @return the result once {@link ValueBase#onComplete()}.
diff --git a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl b/core/java/com/android/internal/inputmethod/IIInputContentUriTokenResultCallback.aidl
similarity index 65%
copy from core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl
copy to core/java/com/android/internal/inputmethod/IIInputContentUriTokenResultCallback.aidl
index ddb5ef8..2e6d224 100644
--- a/core/java/android/content/pm/verify/domain/DomainVerificationUserSelection.aidl
+++ b/core/java/com/android/internal/inputmethod/IIInputContentUriTokenResultCallback.aidl
@@ -14,6 +14,12 @@
* limitations under the License.
*/
-package android.content.pm.verify.domain;
+package com.android.internal.inputmethod;
-parcelable DomainVerificationUserSelection;
+import com.android.internal.inputmethod.IInputContentUriToken;
+import com.android.internal.inputmethod.ThrowableHolder;
+
+oneway interface IIInputContentUriTokenResultCallback {
+ void onResult(in IInputContentUriToken result);
+ void onError(in ThrowableHolder exception);
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
index f0e26cf..e4dd7b0 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
@@ -19,25 +19,31 @@
import android.net.Uri;
import android.view.inputmethod.InputMethodSubtype;
+import com.android.internal.inputmethod.IBooleanResultCallback;
import com.android.internal.inputmethod.IInputContentUriToken;
+import com.android.internal.inputmethod.IIInputContentUriTokenResultCallback;
+import com.android.internal.inputmethod.IVoidResultCallback;
/**
* Defines priviledged operations that only the current IME is allowed to call.
* Actual operations are implemented and handled by InputMethodManagerService.
*/
-interface IInputMethodPrivilegedOperations {
- void setImeWindowStatus(int vis, int backDisposition);
- void reportStartInput(in IBinder startInputToken);
- IInputContentUriToken createInputContentUriToken(in Uri contentUri, in String packageName);
- void reportFullscreenMode(boolean fullscreen);
- void setInputMethod(String id);
- void setInputMethodAndSubtype(String id, in InputMethodSubtype subtype);
- void hideMySoftInput(int flags);
- void showMySoftInput(int flags);
- void updateStatusIcon(String packageName, int iconId);
- boolean switchToPreviousInputMethod();
- boolean switchToNextInputMethod(boolean onlyCurrentIme);
- boolean shouldOfferSwitchingToNextInputMethod();
- void notifyUserAction();
- void applyImeVisibility(IBinder showOrHideInputToken, boolean setVisible);
+oneway interface IInputMethodPrivilegedOperations {
+ void setImeWindowStatus(int vis, int backDisposition, in IVoidResultCallback resultCallback);
+ void reportStartInput(in IBinder startInputToken, in IVoidResultCallback resultCallback);
+ void createInputContentUriToken(in Uri contentUri, in String packageName,
+ in IIInputContentUriTokenResultCallback resultCallback);
+ void reportFullscreenMode(boolean fullscreen, in IVoidResultCallback resultCallback);
+ void setInputMethod(String id, in IVoidResultCallback resultCallback);
+ void setInputMethodAndSubtype(String id, in InputMethodSubtype subtype,
+ in IVoidResultCallback resultCallback);
+ void hideMySoftInput(int flags, in IVoidResultCallback resultCallback);
+ void showMySoftInput(int flags, in IVoidResultCallback resultCallback);
+ void updateStatusIcon(String packageName, int iconId, in IVoidResultCallback resultCallback);
+ void switchToPreviousInputMethod(in IBooleanResultCallback resultCallback);
+ void switchToNextInputMethod(boolean onlyCurrentIme, in IBooleanResultCallback resultCallback);
+ void shouldOfferSwitchingToNextInputMethod(in IBooleanResultCallback resultCallback);
+ void notifyUserAction(in IVoidResultCallback resultCallback);
+ void applyImeVisibility(IBinder showOrHideInputToken, boolean setVisible,
+ in IVoidResultCallback resultCallback);
}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index d6730e8..04cf3f3 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -95,7 +95,8 @@
}
/**
- * Calls {@link IInputMethodPrivilegedOperations#setImeWindowStatus(int, int)}.
+ * Calls {@link IInputMethodPrivilegedOperations#setImeWindowStatus(int, int,
+ * IVoidResultCallback)}.
*
* @param vis visibility flags
* @param backDisposition disposition flags
@@ -112,14 +113,17 @@
return;
}
try {
- ops.setImeWindowStatus(vis, backDisposition);
+ final Completable.Void value = Completable.createVoid();
+ ops.setImeWindowStatus(vis, backDisposition, ResultCallbacks.of(value));
+ Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Calls {@link IInputMethodPrivilegedOperations#reportStartInput(IBinder)}.
+ * Calls {@link IInputMethodPrivilegedOperations#reportStartInput(IBinder,
+ * IVoidResultCallback)}.
*
* @param startInputToken {@link IBinder} token to distinguish startInput session
*/
@@ -130,14 +134,17 @@
return;
}
try {
- ops.reportStartInput(startInputToken);
+ final Completable.Void value = Completable.createVoid();
+ ops.reportStartInput(startInputToken, ResultCallbacks.of(value));
+ Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Calls {@link IInputMethodPrivilegedOperations#createInputContentUriToken(Uri, String)}.
+ * Calls {@link IInputMethodPrivilegedOperations#createInputContentUriToken(Uri, String,
+ * IIInputContentUriTokenResultCallback)}.
*
* @param contentUri Content URI to which a temporary read permission should be granted
* @param packageName Indicates what package needs to have a temporary read permission
@@ -151,7 +158,10 @@
return null;
}
try {
- return ops.createInputContentUriToken(contentUri, packageName);
+ final Completable.IInputContentUriToken value =
+ Completable.createIInputContentUriToken();
+ ops.createInputContentUriToken(contentUri, packageName, ResultCallbacks.of(value));
+ return Completable.getResult(value);
} catch (RemoteException e) {
// For historical reasons, this error was silently ignored.
// Note that the caller already logs error so we do not need additional Log.e() here.
@@ -161,7 +171,8 @@
}
/**
- * Calls {@link IInputMethodPrivilegedOperations#reportFullscreenMode(boolean)}.
+ * Calls {@link IInputMethodPrivilegedOperations#reportFullscreenMode(boolean,
+ * IVoidResultCallback)}.
*
* @param fullscreen {@code true} if the IME enters full screen mode
*/
@@ -172,14 +183,17 @@
return;
}
try {
- ops.reportFullscreenMode(fullscreen);
+ final Completable.Void value = Completable.createVoid();
+ ops.reportFullscreenMode(fullscreen, ResultCallbacks.of(value));
+ Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Calls {@link IInputMethodPrivilegedOperations#updateStatusIcon(String, int)}.
+ * Calls {@link IInputMethodPrivilegedOperations#updateStatusIcon(String, int,
+ * IVoidResultCallback)}.
*
* @param packageName package name from which the status icon should be loaded
* @param iconResId resource ID of the icon to be loaded
@@ -191,14 +205,16 @@
return;
}
try {
- ops.updateStatusIcon(packageName, iconResId);
+ final Completable.Void value = Completable.createVoid();
+ ops.updateStatusIcon(packageName, iconResId, ResultCallbacks.of(value));
+ Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Calls {@link IInputMethodPrivilegedOperations#setInputMethod(String)}.
+ * Calls {@link IInputMethodPrivilegedOperations#setInputMethod(String, IVoidResultCallback)}.
*
* @param id IME ID of the IME to switch to
* @see android.view.inputmethod.InputMethodInfo#getId()
@@ -210,7 +226,9 @@
return;
}
try {
- ops.setInputMethod(id);
+ final Completable.Void value = Completable.createVoid();
+ ops.setInputMethod(id, ResultCallbacks.of(value));
+ Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -218,7 +236,7 @@
/**
* Calls {@link IInputMethodPrivilegedOperations#setInputMethodAndSubtype(String,
- * InputMethodSubtype)}
+ * InputMethodSubtype, IVoidResultCallback)}
*
* @param id IME ID of the IME to switch to
* @param subtype {@link InputMethodSubtype} to switch to
@@ -231,14 +249,16 @@
return;
}
try {
- ops.setInputMethodAndSubtype(id, subtype);
+ final Completable.Void value = Completable.createVoid();
+ ops.setInputMethodAndSubtype(id, subtype, ResultCallbacks.of(value));
+ Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Calls {@link IInputMethodPrivilegedOperations#hideMySoftInput(int)}
+ * Calls {@link IInputMethodPrivilegedOperations#hideMySoftInput(int, IVoidResultCallback)}
*
* @param flags additional operating flags
* @see android.view.inputmethod.InputMethodManager#HIDE_IMPLICIT_ONLY
@@ -251,14 +271,16 @@
return;
}
try {
- ops.hideMySoftInput(flags);
+ final Completable.Void value = Completable.createVoid();
+ ops.hideMySoftInput(flags, ResultCallbacks.of(value));
+ Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Calls {@link IInputMethodPrivilegedOperations#showMySoftInput(int)}
+ * Calls {@link IInputMethodPrivilegedOperations#showMySoftInput(int, IVoidResultCallback)}
*
* @param flags additional operating flags
* @see android.view.inputmethod.InputMethodManager#SHOW_IMPLICIT
@@ -271,14 +293,17 @@
return;
}
try {
- ops.showMySoftInput(flags);
+ final Completable.Void value = Completable.createVoid();
+ ops.showMySoftInput(flags, ResultCallbacks.of(value));
+ Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Calls {@link IInputMethodPrivilegedOperations#switchToPreviousInputMethod()}
+ * Calls {@link IInputMethodPrivilegedOperations#switchToPreviousInputMethod(
+ * IBooleanResultCallback)}
*
* @return {@code true} if handled
*/
@@ -289,14 +314,17 @@
return false;
}
try {
- return ops.switchToPreviousInputMethod();
+ final Completable.Boolean value = Completable.createBoolean();
+ ops.switchToPreviousInputMethod(ResultCallbacks.of(value));
+ return Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Calls {@link IInputMethodPrivilegedOperations#switchToNextInputMethod(boolean)}
+ * Calls {@link IInputMethodPrivilegedOperations#switchToNextInputMethod(boolean,
+ * IBooleanResultCallback)}
*
* @param onlyCurrentIme {@code true} to switch to a {@link InputMethodSubtype} within the same
* IME
@@ -309,14 +337,17 @@
return false;
}
try {
- return ops.switchToNextInputMethod(onlyCurrentIme);
+ final Completable.Boolean value = Completable.createBoolean();
+ ops.switchToNextInputMethod(onlyCurrentIme, ResultCallbacks.of(value));
+ return Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Calls {@link IInputMethodPrivilegedOperations#shouldOfferSwitchingToNextInputMethod()}
+ * Calls {@link IInputMethodPrivilegedOperations#shouldOfferSwitchingToNextInputMethod(
+ * IBooleanResultCallback)}
*
* @return {@code true} if the IEM should offer a way to globally switch IME
*/
@@ -327,14 +358,16 @@
return false;
}
try {
- return ops.shouldOfferSwitchingToNextInputMethod();
+ final Completable.Boolean value = Completable.createBoolean();
+ ops.shouldOfferSwitchingToNextInputMethod(ResultCallbacks.of(value));
+ return Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Calls {@link IInputMethodPrivilegedOperations#notifyUserAction()}
+ * Calls {@link IInputMethodPrivilegedOperations#notifyUserAction(IVoidResultCallback)}
*/
@AnyThread
public void notifyUserAction() {
@@ -343,14 +376,17 @@
return;
}
try {
- ops.notifyUserAction();
+ final Completable.Void value = Completable.createVoid();
+ ops.notifyUserAction(ResultCallbacks.of(value));
+ Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Calls {@link IInputMethodPrivilegedOperations#applyImeVisibility(IBinder, boolean)}.
+ * Calls {@link IInputMethodPrivilegedOperations#applyImeVisibility(IBinder, boolean,
+ * IVoidResultCallback)}.
*
* @param showOrHideInputToken placeholder token that maps to window requesting
* {@link android.view.inputmethod.InputMethodManager#showSoftInput(View, int)} or
@@ -365,7 +401,9 @@
return;
}
try {
- ops.applyImeVisibility(showOrHideInputToken, setVisible);
+ final Completable.Void value = Completable.createVoid();
+ ops.applyImeVisibility(showOrHideInputToken, setVisible, ResultCallbacks.of(value));
+ Completable.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/com/android/internal/inputmethod/ResultCallbacks.java b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
index 2a48c1f..c56ed2d 100644
--- a/core/java/com/android/internal/inputmethod/ResultCallbacks.java
+++ b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
@@ -387,4 +387,41 @@
}
};
}
+
+ /**
+ * Creates {@link IIInputContentUriTokenResultCallback.Stub} that is to set
+ * {@link Completable.IInputContentUriToken} when receiving the result.
+ *
+ * @param value {@link Completable.IInputContentUriToken} to be set when receiving the result.
+ * @return {@link IIInputContentUriTokenResultCallback.Stub} that can be passed as a binder IPC
+ * parameter.
+ */
+ @AnyThread
+ public static IIInputContentUriTokenResultCallback.Stub of(
+ @NonNull Completable.IInputContentUriToken value) {
+ final AtomicReference<WeakReference<Completable.IInputContentUriToken>>
+ atomicRef = new AtomicReference<>(new WeakReference<>(value));
+
+ return new IIInputContentUriTokenResultCallback.Stub() {
+ @BinderThread
+ @Override
+ public void onResult(IInputContentUriToken result) {
+ final Completable.IInputContentUriToken value = unwrap(atomicRef);
+ if (value == null) {
+ return;
+ }
+ value.onComplete(result);
+ }
+
+ @BinderThread
+ @Override
+ public void onError(ThrowableHolder throwableHolder) {
+ final Completable.IInputContentUriToken value = unwrap(atomicRef);
+ if (value == null) {
+ return;
+ }
+ value.onError(throwableHolder);
+ }
+ };
+ }
}
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 33ee8f0..db0b48e 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -327,11 +327,8 @@
}
if (info.surfaceControlCallbackFired) {
totalFramesCount++;
-
- // Only count missed frames if it's not stuffed.
if ((info.jankType & PREDICTION_ERROR) != 0
- || ((info.jankType & JANK_APP_DEADLINE_MISSED) != 0
- && (info.jankType & BUFFER_STUFFING) == 0)) {
+ || ((info.jankType & JANK_APP_DEADLINE_MISSED) != 0)) {
Log.w(TAG, "Missed App frame:" + info.jankType);
missedAppFramesCount++;
}
diff --git a/core/java/com/android/internal/os/DischargedPowerCalculator.java b/core/java/com/android/internal/os/BatteryChargeCalculator.java
similarity index 75%
rename from core/java/com/android/internal/os/DischargedPowerCalculator.java
rename to core/java/com/android/internal/os/BatteryChargeCalculator.java
index e94020c..dc72f32 100644
--- a/core/java/com/android/internal/os/DischargedPowerCalculator.java
+++ b/core/java/com/android/internal/os/BatteryChargeCalculator.java
@@ -27,10 +27,10 @@
/**
* Estimates the battery discharge amounts.
*/
-public class DischargedPowerCalculator extends PowerCalculator {
+public class BatteryChargeCalculator extends PowerCalculator {
private final double mBatteryCapacity;
- public DischargedPowerCalculator(PowerProfile powerProfile) {
+ public BatteryChargeCalculator(PowerProfile powerProfile) {
mBatteryCapacity = powerProfile.getBatteryCapacity();
}
@@ -42,6 +42,16 @@
.setDischargedPowerRange(
batteryStats.getLowDischargeAmountSinceCharge() * mBatteryCapacity / 100,
batteryStats.getHighDischargeAmountSinceCharge() * mBatteryCapacity / 100);
+
+ final long batteryTimeRemainingMs = batteryStats.computeBatteryTimeRemaining(rawRealtimeUs);
+ if (batteryTimeRemainingMs != -1) {
+ builder.setBatteryTimeRemainingMs(batteryTimeRemainingMs / 1000);
+ }
+
+ final long chargeTimeRemainingMs = batteryStats.computeChargeTimeRemaining(rawRealtimeUs);
+ if (chargeTimeRemainingMs != -1) {
+ builder.setChargeTimeRemainingMs(chargeTimeRemainingMs / 1000);
+ }
}
@Override
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index 15b584d..619cd8e 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -55,7 +55,7 @@
mPowerCalculators = new ArrayList<>();
// Power calculators are applied in the order of registration
- mPowerCalculators.add(new DischargedPowerCalculator(mPowerProfile));
+ mPowerCalculators.add(new BatteryChargeCalculator(mPowerProfile));
mPowerCalculators.add(new CpuPowerCalculator(mPowerProfile));
mPowerCalculators.add(new MemoryPowerCalculator(mPowerProfile));
mPowerCalculators.add(new WakelockPowerCalculator(mPowerProfile));
diff --git a/core/java/com/android/internal/os/OWNERS b/core/java/com/android/internal/os/OWNERS
index 0aa54f5..3f01ebb 100644
--- a/core/java/com/android/internal/os/OWNERS
+++ b/core/java/com/android/internal/os/OWNERS
@@ -6,6 +6,7 @@
per-file BatterySipper.java = file:/BATTERY_STATS_OWNERS
per-file BatteryStats* = file:/BATTERY_STATS_OWNERS
per-file BatteryUsageStats* = file:/BATTERY_STATS_OWNERS
+per-file *ChargeCalculator* = file:/BATTERY_STATS_OWNERS
per-file *PowerCalculator* = file:/BATTERY_STATS_OWNERS
per-file *PowerEstimator* = file:/BATTERY_STATS_OWNERS
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 6b1d408..8b5a62a 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -202,7 +202,7 @@
public static final String PKG_DATA_INFO_MAP = "--pkg-data-info-map";
/** List of allowlisted packages and its app data info: volume uuid and inode. */
- public static final String WHITELISTED_DATA_INFO_MAP = "--whitelisted-data-info-map";
+ public static final String ALLOWLISTED_DATA_INFO_MAP = "--allowlisted-data-info-map";
/** Bind mount app storage dirs to lower fs not via fuse */
public static final String BIND_MOUNT_APP_STORAGE_DIRS = "--bind-mount-storage-dirs";
@@ -324,7 +324,7 @@
* @param isTopApp true if the process is for top (high priority) application.
* @param pkgDataInfoList A list that stores related packages and its app data
* info: volume uuid and inode.
- * @param whitelistedDataInfoList Like pkgDataInfoList, but it's for allowlisted apps.
+ * @param allowlistedDataInfoList Like pkgDataInfoList, but it's for allowlisted apps.
* @param bindMountAppDataDirs True if the zygote needs to mount data dirs.
* @param bindMountAppStorageDirs True if the zygote needs to mount storage dirs.
*
@@ -334,14 +334,14 @@
static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
- boolean isTopApp, String[] pkgDataInfoList, String[] whitelistedDataInfoList,
+ boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList,
boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) {
ZygoteHooks.preFork();
int pid = nativeForkAndSpecialize(
uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp,
- pkgDataInfoList, whitelistedDataInfoList, bindMountAppDataDirs,
+ pkgDataInfoList, allowlistedDataInfoList, bindMountAppDataDirs,
bindMountAppStorageDirs);
if (pid == 0) {
// Note that this event ends at the end of handleChildProc,
@@ -364,7 +364,7 @@
int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet,
String appDataDir, boolean isTopApp, String[] pkgDataInfoList,
- String[] whitelistedDataInfoList, boolean bindMountAppDataDirs,
+ String[] allowlistedDataInfoList, boolean bindMountAppDataDirs,
boolean bindMountAppStorageDirs);
/**
@@ -392,18 +392,18 @@
* volume uuid and CE dir inode. For example, pkgDataInfoList = [app_a_pkg_name,
* app_a_data_volume_uuid, app_a_ce_inode, app_b_pkg_name, app_b_data_volume_uuid,
* app_b_ce_inode, ...];
- * @param whitelistedDataInfoList Like pkgDataInfoList, but it's for allowlisted apps.
+ * @param allowlistedDataInfoList Like pkgDataInfoList, but it's for allowlisted apps.
* @param bindMountAppDataDirs True if the zygote needs to mount data dirs.
* @param bindMountAppStorageDirs True if the zygote needs to mount storage dirs.
*/
private static void specializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName,
boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp,
- String[] pkgDataInfoList, String[] whitelistedDataInfoList,
+ String[] pkgDataInfoList, String[] allowlistedDataInfoList,
boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) {
nativeSpecializeAppProcess(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo,
niceName, startChildZygote, instructionSet, appDataDir, isTopApp,
- pkgDataInfoList, whitelistedDataInfoList,
+ pkgDataInfoList, allowlistedDataInfoList,
bindMountAppDataDirs, bindMountAppStorageDirs);
// Note that this event ends at the end of handleChildProc.
@@ -428,7 +428,7 @@
private static native void nativeSpecializeAppProcess(int uid, int gid, int[] gids,
int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp,
- String[] pkgDataInfoList, String[] whitelistedDataInfoList,
+ String[] pkgDataInfoList, String[] allowlistedDataInfoList,
boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs);
/**
@@ -807,7 +807,7 @@
args.mRuntimeFlags, rlimits, args.mMountExternal,
args.mSeInfo, args.mNiceName, args.mStartChildZygote,
args.mInstructionSet, args.mAppDataDir, args.mIsTopApp,
- args.mPkgDataInfoList, args.mWhitelistedDataInfoList,
+ args.mPkgDataInfoList, args.mAllowlistedDataInfoList,
args.mBindMountAppDataDirs, args.mBindMountAppStorageDirs);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index 65b454d..ef83982 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -230,7 +230,7 @@
* A list that stores all allowlisted app data info: volume uuid and inode.
* Null if it does need to do app data isolation.
*/
- String[] mWhitelistedDataInfoList;
+ String[] mAllowlistedDataInfoList;
/**
* @see Zygote#BIND_MOUNT_APP_STORAGE_DIRS
@@ -475,8 +475,8 @@
}
} else if (arg.startsWith(Zygote.PKG_DATA_INFO_MAP)) {
mPkgDataInfoList = getAssignmentList(arg);
- } else if (arg.startsWith(Zygote.WHITELISTED_DATA_INFO_MAP)) {
- mWhitelistedDataInfoList = getAssignmentList(arg);
+ } else if (arg.startsWith(Zygote.ALLOWLISTED_DATA_INFO_MAP)) {
+ mAllowlistedDataInfoList = getAssignmentList(arg);
} else if (arg.equals(Zygote.BIND_MOUNT_APP_STORAGE_DIRS)) {
mBindMountAppStorageDirs = true;
} else if (arg.equals(Zygote.BIND_MOUNT_APP_DATA_DIRS)) {
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 37c7590..1673362 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -265,7 +265,7 @@
fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
parsedArgs.mInstructionSet, parsedArgs.mAppDataDir,
parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList,
- parsedArgs.mWhitelistedDataInfoList, parsedArgs.mBindMountAppDataDirs,
+ parsedArgs.mAllowlistedDataInfoList, parsedArgs.mBindMountAppDataDirs,
parsedArgs.mBindMountAppStorageDirs);
try {
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 35d1d7b..f6629fd 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -43,6 +43,7 @@
per-file EphemeralStorage* = file:platform/system/libhwbinder:/OWNERS
per-file *Zygote* = file:/ZYGOTE_OWNERS
+per-file fd_utils.* = file:/ZYGOTE_OWNERS
per-file Android.bp = file:platform/build/soong:/OWNERS
per-file android_animation_* = file:/core/java/android/animation/OWNERS
per-file android_app_admin_* = file:/core/java/android/app/admin/OWNERS
diff --git a/core/jni/android_view_SurfaceControlFpsListener.cpp b/core/jni/android_view_SurfaceControlFpsListener.cpp
index 6fa12e5..0b15acd 100644
--- a/core/jni/android_view_SurfaceControlFpsListener.cpp
+++ b/core/jni/android_view_SurfaceControlFpsListener.cpp
@@ -84,11 +84,9 @@
listener->decStrong((void*)nativeCreate);
}
-void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr, jlong layerObj) {
+void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr, jint taskId) {
sp<SurfaceControlFpsListener> listener = reinterpret_cast<SurfaceControlFpsListener*>(ptr);
- auto layer = reinterpret_cast<SurfaceControl*>(layerObj);
- sp<IBinder> layerHandle = layer != nullptr ? layer->getHandle() : nullptr;
- if (SurfaceComposerClient::addFpsListener(layerHandle, listener) != OK) {
+ if (SurfaceComposerClient::addFpsListener(taskId, listener) != OK) {
constexpr auto error_msg = "Couldn't addFpsListener";
ALOGE(error_msg);
jniThrowRuntimeException(env, error_msg);
@@ -109,7 +107,7 @@
/* name, signature, funcPtr */
{"nativeCreate", "(Landroid/view/SurfaceControlFpsListener;)J", (void*)nativeCreate},
{"nativeDestroy", "(J)V", (void*)nativeDestroy},
- {"nativeRegister", "(JJ)V", (void*)nativeRegister},
+ {"nativeRegister", "(JI)V", (void*)nativeRegister},
{"nativeUnregister", "(J)V", (void*)nativeUnregister}};
} // namespace
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index bcfb06b..836074f 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1400,16 +1400,15 @@
}
static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list,
- jobjectArray whitelisted_data_info_list, uid_t uid, const char* process_name,
- jstring managed_nice_name, fail_fn_t fail_fn) {
+ jobjectArray allowlisted_data_info_list, uid_t uid,
+ const char* process_name, jstring managed_nice_name, fail_fn_t fail_fn) {
+ std::vector<std::string> merged_data_info_list;
+ insertPackagesToMergedList(env, merged_data_info_list, pkg_data_info_list, process_name,
+ managed_nice_name, fail_fn);
+ insertPackagesToMergedList(env, merged_data_info_list, allowlisted_data_info_list, process_name,
+ managed_nice_name, fail_fn);
- std::vector<std::string> merged_data_info_list;
- insertPackagesToMergedList(env, merged_data_info_list, pkg_data_info_list,
- process_name, managed_nice_name, fail_fn);
- insertPackagesToMergedList(env, merged_data_info_list, whitelisted_data_info_list,
- process_name, managed_nice_name, fail_fn);
-
- isolateAppData(env, merged_data_info_list, uid, process_name, managed_nice_name, fail_fn);
+ isolateAppData(env, merged_data_info_list, uid, process_name, managed_nice_name, fail_fn);
}
/**
@@ -1510,240 +1509,242 @@
}
// Utility routine to specialize a zygote child process.
-static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
- jint runtime_flags, jobjectArray rlimits,
- jlong permitted_capabilities, jlong effective_capabilities,
- jint mount_external, jstring managed_se_info,
- jstring managed_nice_name, bool is_system_server,
- bool is_child_zygote, jstring managed_instruction_set,
- jstring managed_app_data_dir, bool is_top_app,
- jobjectArray pkg_data_info_list,
- jobjectArray whitelisted_data_info_list,
- bool mount_data_dirs, bool mount_storage_dirs) {
- const char* process_name = is_system_server ? "system_server" : "zygote";
- auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1);
- auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
+static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, jint runtime_flags,
+ jobjectArray rlimits, jlong permitted_capabilities,
+ jlong effective_capabilities, jint mount_external,
+ jstring managed_se_info, jstring managed_nice_name,
+ bool is_system_server, bool is_child_zygote,
+ jstring managed_instruction_set, jstring managed_app_data_dir,
+ bool is_top_app, jobjectArray pkg_data_info_list,
+ jobjectArray allowlisted_data_info_list, bool mount_data_dirs,
+ bool mount_storage_dirs) {
+ const char* process_name = is_system_server ? "system_server" : "zygote";
+ auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1);
+ auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
- auto se_info = extract_fn(managed_se_info);
- auto nice_name = extract_fn(managed_nice_name);
- auto instruction_set = extract_fn(managed_instruction_set);
- auto app_data_dir = extract_fn(managed_app_data_dir);
+ auto se_info = extract_fn(managed_se_info);
+ auto nice_name = extract_fn(managed_nice_name);
+ auto instruction_set = extract_fn(managed_instruction_set);
+ auto app_data_dir = extract_fn(managed_app_data_dir);
- // Keep capabilities across UID change, unless we're staying root.
- if (uid != 0) {
- EnableKeepCapabilities(fail_fn);
- }
-
- SetInheritable(permitted_capabilities, fail_fn);
-
- DropCapabilitiesBoundingSet(fail_fn);
-
- bool need_pre_initialize_native_bridge =
- !is_system_server &&
- instruction_set.has_value() &&
- android::NativeBridgeAvailable() &&
- // Native bridge may be already initialized if this
- // is an app forked from app-zygote.
- !android::NativeBridgeInitialized() &&
- android::NeedsNativeBridge(instruction_set.value().c_str());
-
- MountEmulatedStorage(uid, mount_external, need_pre_initialize_native_bridge, fail_fn);
-
- // Make sure app is running in its own mount namespace before isolating its data directories.
- ensureInAppMountNamespace(fail_fn);
-
- // Sandbox data and jit profile directories by overlaying a tmpfs on those dirs and bind
- // mount all related packages separately.
- if (mount_data_dirs) {
- isolateAppData(env, pkg_data_info_list, whitelisted_data_info_list,
- uid, process_name, managed_nice_name, fail_fn);
- isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
- }
- // MOUNT_EXTERNAL_INSTALLER, MOUNT_EXTERNAL_PASS_THROUGH, MOUNT_EXTERNAL_ANDROID_WRITABLE apps
- // will have mount_storage_dirs == false here (set by ProcessList.needsStorageDataIsolation()),
- // and hence they won't bind mount storage dirs.
- if (mount_storage_dirs) {
- BindMountStorageDirs(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
- }
-
- // If this zygote isn't root, it won't be able to create a process group,
- // since the directory is owned by root.
- if (!is_system_server && getuid() == 0) {
- const int rc = createProcessGroup(uid, getpid());
- if (rc == -EROFS) {
- ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
- } else if (rc != 0) {
- ALOGE("createProcessGroup(%d, %d) failed: %s", uid, /* pid= */ 0, strerror(-rc));
+ // Keep capabilities across UID change, unless we're staying root.
+ if (uid != 0) {
+ EnableKeepCapabilities(fail_fn);
}
- }
- SetGids(env, gids, is_child_zygote, fail_fn);
- SetRLimits(env, rlimits, fail_fn);
+ SetInheritable(permitted_capabilities, fail_fn);
- if (need_pre_initialize_native_bridge) {
- // Due to the logic behind need_pre_initialize_native_bridge we know that
- // instruction_set contains a value.
- android::PreInitializeNativeBridge(
- app_data_dir.has_value() ? app_data_dir.value().c_str() : nullptr,
- instruction_set.value().c_str());
- }
+ DropCapabilitiesBoundingSet(fail_fn);
- if (setresgid(gid, gid, gid) == -1) {
- fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno)));
- }
+ bool need_pre_initialize_native_bridge = !is_system_server && instruction_set.has_value() &&
+ android::NativeBridgeAvailable() &&
+ // Native bridge may be already initialized if this
+ // is an app forked from app-zygote.
+ !android::NativeBridgeInitialized() &&
+ android::NeedsNativeBridge(instruction_set.value().c_str());
- // Must be called when the new process still has CAP_SYS_ADMIN, in this case,
- // before changing uid from 0, which clears capabilities. The other
- // alternative is to call prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that
- // breaks SELinux domain transition (see b/71859146). As the result,
- // privileged syscalls used below still need to be accessible in app process.
- SetUpSeccompFilter(uid, is_child_zygote);
+ MountEmulatedStorage(uid, mount_external, need_pre_initialize_native_bridge, fail_fn);
- // Must be called before losing the permission to set scheduler policy.
- SetSchedulerPolicy(fail_fn, is_top_app);
+ // Make sure app is running in its own mount namespace before isolating its data directories.
+ ensureInAppMountNamespace(fail_fn);
- if (setresuid(uid, uid, uid) == -1) {
- fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno)));
- }
-
- // The "dumpable" flag of a process, which controls core dump generation, is
- // overwritten by the value in /proc/sys/fs/suid_dumpable when the effective
- // user or group ID changes. See proc(5) for possible values. In most cases,
- // the value is 0, so core dumps are disabled for zygote children. However,
- // when running in a Chrome OS container, the value is already set to 2,
- // which allows the external crash reporter to collect all core dumps. Since
- // only system crashes are interested, core dump is disabled for app
- // processes. This also ensures compliance with CTS.
- int dumpable = prctl(PR_GET_DUMPABLE);
- if (dumpable == -1) {
- ALOGE("prctl(PR_GET_DUMPABLE) failed: %s", strerror(errno));
- RuntimeAbort(env, __LINE__, "prctl(PR_GET_DUMPABLE) failed");
- }
-
- if (dumpable == 2 && uid >= AID_APP) {
- if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) {
- ALOGE("prctl(PR_SET_DUMPABLE, 0) failed: %s", strerror(errno));
- RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 0) failed");
+ // Sandbox data and jit profile directories by overlaying a tmpfs on those dirs and bind
+ // mount all related packages separately.
+ if (mount_data_dirs) {
+ isolateAppData(env, pkg_data_info_list, allowlisted_data_info_list, uid, process_name,
+ managed_nice_name, fail_fn);
+ isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
}
- }
-
- // Set process properties to enable debugging if required.
- if ((runtime_flags & RuntimeFlags::DEBUG_ENABLE_JDWP) != 0) {
- EnableDebugger();
- }
- if ((runtime_flags & RuntimeFlags::PROFILE_FROM_SHELL) != 0) {
- // simpleperf needs the process to be dumpable to profile it.
- if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
- ALOGE("prctl(PR_SET_DUMPABLE) failed: %s", strerror(errno));
- RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 1) failed");
+ // MOUNT_EXTERNAL_INSTALLER, MOUNT_EXTERNAL_PASS_THROUGH, MOUNT_EXTERNAL_ANDROID_WRITABLE apps
+ // will have mount_storage_dirs == false here (set by ProcessList.needsStorageDataIsolation()),
+ // and hence they won't bind mount storage dirs.
+ if (mount_storage_dirs) {
+ BindMountStorageDirs(env, pkg_data_info_list, uid, process_name, managed_nice_name,
+ fail_fn);
}
- }
- HeapTaggingLevel heap_tagging_level;
- switch (runtime_flags & RuntimeFlags::MEMORY_TAG_LEVEL_MASK) {
- case RuntimeFlags::MEMORY_TAG_LEVEL_TBI:
- heap_tagging_level = M_HEAP_TAGGING_LEVEL_TBI;
- break;
- case RuntimeFlags::MEMORY_TAG_LEVEL_ASYNC:
- heap_tagging_level = M_HEAP_TAGGING_LEVEL_ASYNC;
- break;
- case RuntimeFlags::MEMORY_TAG_LEVEL_SYNC:
- heap_tagging_level = M_HEAP_TAGGING_LEVEL_SYNC;
- break;
- default:
- heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE;
- break;
- }
- mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, heap_tagging_level);
-
- // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime.
- runtime_flags &= ~RuntimeFlags::MEMORY_TAG_LEVEL_MASK;
-
- // Avoid heap zero initialization for applications without MTE. Zero init may
- // cause app compat problems, use more memory, or reduce performance. While it
- // would be nice to have them for apps, we will have to wait until they are
- // proven out, have more efficient hardware, and/or apply them only to new
- // applications.
- if (!(runtime_flags & RuntimeFlags::NATIVE_HEAP_ZERO_INIT)) {
- mallopt(M_BIONIC_ZERO_INIT, 0);
- }
-
- // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime.
- runtime_flags &= ~RuntimeFlags::NATIVE_HEAP_ZERO_INIT;
-
- bool forceEnableGwpAsan = false;
- switch (runtime_flags & RuntimeFlags::GWP_ASAN_LEVEL_MASK) {
- default:
- case RuntimeFlags::GWP_ASAN_LEVEL_NEVER:
- break;
- case RuntimeFlags::GWP_ASAN_LEVEL_ALWAYS:
- forceEnableGwpAsan = true;
- [[fallthrough]];
- case RuntimeFlags::GWP_ASAN_LEVEL_LOTTERY:
- android_mallopt(M_INITIALIZE_GWP_ASAN, &forceEnableGwpAsan, sizeof(forceEnableGwpAsan));
- }
- // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime.
- runtime_flags &= ~RuntimeFlags::GWP_ASAN_LEVEL_MASK;
-
- if (NeedsNoRandomizeWorkaround()) {
- // Work around ARM kernel ASLR lossage (http://b/5817320).
- int old_personality = personality(0xffffffff);
- int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
- if (new_personality == -1) {
- ALOGW("personality(%d) failed: %s", new_personality, strerror(errno));
+ // If this zygote isn't root, it won't be able to create a process group,
+ // since the directory is owned by root.
+ if (!is_system_server && getuid() == 0) {
+ const int rc = createProcessGroup(uid, getpid());
+ if (rc == -EROFS) {
+ ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
+ } else if (rc != 0) {
+ ALOGE("createProcessGroup(%d, %d) failed: %s", uid, /* pid= */ 0, strerror(-rc));
+ }
}
- }
- SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities, fail_fn);
+ SetGids(env, gids, is_child_zygote, fail_fn);
+ SetRLimits(env, rlimits, fail_fn);
- __android_log_close();
- AStatsSocket_close();
+ if (need_pre_initialize_native_bridge) {
+ // Due to the logic behind need_pre_initialize_native_bridge we know that
+ // instruction_set contains a value.
+ android::PreInitializeNativeBridge(app_data_dir.has_value() ? app_data_dir.value().c_str()
+ : nullptr,
+ instruction_set.value().c_str());
+ }
- const char* se_info_ptr = se_info.has_value() ? se_info.value().c_str() : nullptr;
- const char* nice_name_ptr = nice_name.has_value() ? nice_name.value().c_str() : nullptr;
+ if (setresgid(gid, gid, gid) == -1) {
+ fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno)));
+ }
- if (selinux_android_setcontext(uid, is_system_server, se_info_ptr, nice_name_ptr) == -1) {
- fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed",
- uid, is_system_server, se_info_ptr, nice_name_ptr));
- }
+ // Must be called when the new process still has CAP_SYS_ADMIN, in this case,
+ // before changing uid from 0, which clears capabilities. The other
+ // alternative is to call prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that
+ // breaks SELinux domain transition (see b/71859146). As the result,
+ // privileged syscalls used below still need to be accessible in app process.
+ SetUpSeccompFilter(uid, is_child_zygote);
- // Make it easier to debug audit logs by setting the main thread's name to the
- // nice name rather than "app_process".
- if (nice_name.has_value()) {
- SetThreadName(nice_name.value());
- } else if (is_system_server) {
- SetThreadName("system_server");
- }
+ // Must be called before losing the permission to set scheduler policy.
+ SetSchedulerPolicy(fail_fn, is_top_app);
- // Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers).
- UnsetChldSignalHandler();
+ if (setresuid(uid, uid, uid) == -1) {
+ fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno)));
+ }
- if (is_system_server) {
- env->CallStaticVoidMethod(gZygoteClass, gCallPostForkSystemServerHooks, runtime_flags);
+ // The "dumpable" flag of a process, which controls core dump generation, is
+ // overwritten by the value in /proc/sys/fs/suid_dumpable when the effective
+ // user or group ID changes. See proc(5) for possible values. In most cases,
+ // the value is 0, so core dumps are disabled for zygote children. However,
+ // when running in a Chrome OS container, the value is already set to 2,
+ // which allows the external crash reporter to collect all core dumps. Since
+ // only system crashes are interested, core dump is disabled for app
+ // processes. This also ensures compliance with CTS.
+ int dumpable = prctl(PR_GET_DUMPABLE);
+ if (dumpable == -1) {
+ ALOGE("prctl(PR_GET_DUMPABLE) failed: %s", strerror(errno));
+ RuntimeAbort(env, __LINE__, "prctl(PR_GET_DUMPABLE) failed");
+ }
+
+ if (dumpable == 2 && uid >= AID_APP) {
+ if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) {
+ ALOGE("prctl(PR_SET_DUMPABLE, 0) failed: %s", strerror(errno));
+ RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 0) failed");
+ }
+ }
+
+ // Set process properties to enable debugging if required.
+ if ((runtime_flags & RuntimeFlags::DEBUG_ENABLE_JDWP) != 0) {
+ EnableDebugger();
+ }
+ if ((runtime_flags & RuntimeFlags::PROFILE_FROM_SHELL) != 0) {
+ // simpleperf needs the process to be dumpable to profile it.
+ if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
+ ALOGE("prctl(PR_SET_DUMPABLE) failed: %s", strerror(errno));
+ RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 1) failed");
+ }
+ }
+
+ HeapTaggingLevel heap_tagging_level;
+ switch (runtime_flags & RuntimeFlags::MEMORY_TAG_LEVEL_MASK) {
+ case RuntimeFlags::MEMORY_TAG_LEVEL_TBI:
+ heap_tagging_level = M_HEAP_TAGGING_LEVEL_TBI;
+ break;
+ case RuntimeFlags::MEMORY_TAG_LEVEL_ASYNC:
+ heap_tagging_level = M_HEAP_TAGGING_LEVEL_ASYNC;
+ break;
+ case RuntimeFlags::MEMORY_TAG_LEVEL_SYNC:
+ heap_tagging_level = M_HEAP_TAGGING_LEVEL_SYNC;
+ break;
+ default:
+ heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE;
+ break;
+ }
+ mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, heap_tagging_level);
+
+ // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART
+ // runtime.
+ runtime_flags &= ~RuntimeFlags::MEMORY_TAG_LEVEL_MASK;
+
+ // Avoid heap zero initialization for applications without MTE. Zero init may
+ // cause app compat problems, use more memory, or reduce performance. While it
+ // would be nice to have them for apps, we will have to wait until they are
+ // proven out, have more efficient hardware, and/or apply them only to new
+ // applications.
+ if (!(runtime_flags & RuntimeFlags::NATIVE_HEAP_ZERO_INIT)) {
+ mallopt(M_BIONIC_ZERO_INIT, 0);
+ }
+
+ // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART
+ // runtime.
+ runtime_flags &= ~RuntimeFlags::NATIVE_HEAP_ZERO_INIT;
+
+ bool forceEnableGwpAsan = false;
+ switch (runtime_flags & RuntimeFlags::GWP_ASAN_LEVEL_MASK) {
+ default:
+ case RuntimeFlags::GWP_ASAN_LEVEL_NEVER:
+ break;
+ case RuntimeFlags::GWP_ASAN_LEVEL_ALWAYS:
+ forceEnableGwpAsan = true;
+ [[fallthrough]];
+ case RuntimeFlags::GWP_ASAN_LEVEL_LOTTERY:
+ android_mallopt(M_INITIALIZE_GWP_ASAN, &forceEnableGwpAsan, sizeof(forceEnableGwpAsan));
+ }
+ // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART
+ // runtime.
+ runtime_flags &= ~RuntimeFlags::GWP_ASAN_LEVEL_MASK;
+
+ if (NeedsNoRandomizeWorkaround()) {
+ // Work around ARM kernel ASLR lossage (http://b/5817320).
+ int old_personality = personality(0xffffffff);
+ int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
+ if (new_personality == -1) {
+ ALOGW("personality(%d) failed: %s", new_personality, strerror(errno));
+ }
+ }
+
+ SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities,
+ fail_fn);
+
+ __android_log_close();
+ AStatsSocket_close();
+
+ const char* se_info_ptr = se_info.has_value() ? se_info.value().c_str() : nullptr;
+ const char* nice_name_ptr = nice_name.has_value() ? nice_name.value().c_str() : nullptr;
+
+ if (selinux_android_setcontext(uid, is_system_server, se_info_ptr, nice_name_ptr) == -1) {
+ fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
+ is_system_server, se_info_ptr, nice_name_ptr));
+ }
+
+ // Make it easier to debug audit logs by setting the main thread's name to the
+ // nice name rather than "app_process".
+ if (nice_name.has_value()) {
+ SetThreadName(nice_name.value());
+ } else if (is_system_server) {
+ SetThreadName("system_server");
+ }
+
+ // Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers).
+ UnsetChldSignalHandler();
+
+ if (is_system_server) {
+ env->CallStaticVoidMethod(gZygoteClass, gCallPostForkSystemServerHooks, runtime_flags);
+ if (env->ExceptionCheck()) {
+ fail_fn("Error calling post fork system server hooks.");
+ }
+
+ // TODO(b/117874058): Remove hardcoded label here.
+ static const char* kSystemServerLabel = "u:r:system_server:s0";
+ if (selinux_android_setcon(kSystemServerLabel) != 0) {
+ fail_fn(CREATE_ERROR("selinux_android_setcon(%s)", kSystemServerLabel));
+ }
+ }
+
+ if (is_child_zygote) {
+ initUnsolSocketToSystemServer();
+ }
+
+ env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
+ is_system_server, is_child_zygote, managed_instruction_set);
+
+ // Reset the process priority to the default value.
+ setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_DEFAULT);
+
if (env->ExceptionCheck()) {
- fail_fn("Error calling post fork system server hooks.");
+ fail_fn("Error calling post fork hooks.");
}
-
- // TODO(oth): Remove hardcoded label here (b/117874058).
- static const char* kSystemServerLabel = "u:r:system_server:s0";
- if (selinux_android_setcon(kSystemServerLabel) != 0) {
- fail_fn(CREATE_ERROR("selinux_android_setcon(%s)", kSystemServerLabel));
- }
- }
-
- if (is_child_zygote) {
- initUnsolSocketToSystemServer();
- }
-
- env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
- is_system_server, is_child_zygote, managed_instruction_set);
-
- // Reset the process priority to the default value.
- setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_DEFAULT);
-
- if (env->ExceptionCheck()) {
- fail_fn("Error calling post fork hooks.");
- }
}
static uint64_t GetEffectiveCapabilityMask(JNIEnv* env) {
@@ -2068,12 +2069,11 @@
NO_PAC_FUNC
static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
- JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
- jint runtime_flags, jobjectArray rlimits,
- jint mount_external, jstring se_info, jstring nice_name,
+ JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint runtime_flags,
+ jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name,
jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote,
jstring instruction_set, jstring app_data_dir, jboolean is_top_app,
- jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list,
+ jobjectArray pkg_data_info_list, jobjectArray allowlisted_data_info_list,
jboolean mount_data_dirs, jboolean mount_storage_dirs) {
jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
@@ -2108,14 +2108,11 @@
pid_t pid = zygote::ForkCommon(env, false, fds_to_close, fds_to_ignore, true);
if (pid == 0) {
- SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
- capabilities, capabilities,
- mount_external, se_info, nice_name, false,
- is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
- is_top_app == JNI_TRUE, pkg_data_info_list,
- whitelisted_data_info_list,
- mount_data_dirs == JNI_TRUE,
- mount_storage_dirs == JNI_TRUE);
+ SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities,
+ mount_external, se_info, nice_name, false, is_child_zygote == JNI_TRUE,
+ instruction_set, app_data_dir, is_top_app == JNI_TRUE, pkg_data_info_list,
+ allowlisted_data_info_list, mount_data_dirs == JNI_TRUE,
+ mount_storage_dirs == JNI_TRUE);
}
return pid;
}
@@ -2147,12 +2144,11 @@
if (pid == 0) {
// System server prcoess does not need data isolation so no need to
// know pkg_data_info_list.
- SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
- permitted_capabilities, effective_capabilities,
- MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
+ SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities,
+ effective_capabilities, MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
false, nullptr, nullptr, /* is_top_app= */ false,
/* pkg_data_info_list */ nullptr,
- /* whitelisted_data_info_list */ nullptr, false, false);
+ /* allowlisted_data_info_list */ nullptr, false, false);
} else if (pid > 0) {
// The zygote process checks whether the child process has died or not.
ALOGI("System server process %d has been created", pid);
@@ -2260,7 +2256,7 @@
if (!path_cstr) {
RuntimeAbort(env, __LINE__, "path_cstr == nullptr");
}
- FileDescriptorWhitelist::Get()->Allow(path_cstr);
+ FileDescriptorAllowlist::Get()->Allow(path_cstr);
}
static void com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter(
@@ -2295,20 +2291,19 @@
* @param is_top_app If the process is for top (high priority) application
*/
static void com_android_internal_os_Zygote_nativeSpecializeAppProcess(
- JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
- jint runtime_flags, jobjectArray rlimits,
- jint mount_external, jstring se_info, jstring nice_name,
- jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app,
- jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list,
- jboolean mount_data_dirs, jboolean mount_storage_dirs) {
- jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
+ JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint runtime_flags,
+ jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name,
+ jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir,
+ jboolean is_top_app, jobjectArray pkg_data_info_list,
+ jobjectArray allowlisted_data_info_list, jboolean mount_data_dirs,
+ jboolean mount_storage_dirs) {
+ jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
- SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
- capabilities, capabilities,
- mount_external, se_info, nice_name, false,
- is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
- is_top_app == JNI_TRUE, pkg_data_info_list, whitelisted_data_info_list,
- mount_data_dirs == JNI_TRUE, mount_storage_dirs == JNI_TRUE);
+ SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities,
+ mount_external, se_info, nice_name, false, is_child_zygote == JNI_TRUE,
+ instruction_set, app_data_dir, is_top_app == JNI_TRUE, pkg_data_info_list,
+ allowlisted_data_info_list, mount_data_dirs == JNI_TRUE,
+ mount_storage_dirs == JNI_TRUE);
}
/**
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 06a71cb..7fa627b 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -31,8 +31,8 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-// Static whitelist of open paths that the zygote is allowed to keep open.
-static const char* kPathWhitelist[] = {
+// Static allowlist of open paths that the zygote is allowed to keep open.
+static const char* kPathAllowlist[] = {
"/dev/null",
"/dev/socket/zygote",
"/dev/socket/zygote_secondary",
@@ -53,118 +53,114 @@
static const char kFdPath[] = "/proc/self/fd";
// static
-FileDescriptorWhitelist* FileDescriptorWhitelist::Get() {
- if (instance_ == nullptr) {
- instance_ = new FileDescriptorWhitelist();
- }
- return instance_;
+FileDescriptorAllowlist* FileDescriptorAllowlist::Get() {
+ if (instance_ == nullptr) {
+ instance_ = new FileDescriptorAllowlist();
+ }
+ return instance_;
}
static bool IsArtMemfd(const std::string& path) {
return android::base::StartsWith(path, "/memfd:/boot-image-methods.art");
}
-bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const {
- // Check the static whitelist path.
- for (const auto& whitelist_path : kPathWhitelist) {
- if (path == whitelist_path)
- return true;
- }
-
- // Check any paths added to the dynamic whitelist.
- for (const auto& whitelist_path : whitelist_) {
- if (path == whitelist_path)
- return true;
- }
-
- // Framework jars are allowed.
- static const char* kFrameworksPrefix[] = {
- "/system/framework/",
- "/system_ext/framework/",
- };
-
- static const char* kJarSuffix = ".jar";
-
- for (const auto& frameworks_prefix : kFrameworksPrefix) {
- if (android::base::StartsWith(path, frameworks_prefix)
- && android::base::EndsWith(path, kJarSuffix)) {
- return true;
+bool FileDescriptorAllowlist::IsAllowed(const std::string& path) const {
+ // Check the static allowlist path.
+ for (const auto& allowlist_path : kPathAllowlist) {
+ if (path == allowlist_path) return true;
}
- }
- // Jars from APEXes are allowed. This matches /apex/**/javalib/*.jar.
- static const char* kApexPrefix = "/apex/";
- static const char* kApexJavalibPathSuffix = "/javalib";
- if (android::base::StartsWith(path, kApexPrefix) && android::base::EndsWith(path, kJarSuffix) &&
- android::base::EndsWith(android::base::Dirname(path), kApexJavalibPathSuffix)) {
- return true;
- }
+ // Check any paths added to the dynamic allowlist.
+ for (const auto& allowlist_path : allowlist_) {
+ if (path == allowlist_path) return true;
+ }
- // the in-memory file created by ART through memfd_create is allowed.
- if (IsArtMemfd(path)) {
- return true;
- }
+ // Framework jars are allowed.
+ static const char* kFrameworksPrefix[] = {
+ "/system/framework/",
+ "/system_ext/framework/",
+ };
- // Whitelist files needed for Runtime Resource Overlay, like these:
- // /system/vendor/overlay/framework-res.apk
- // /system/vendor/overlay-subdir/pg/framework-res.apk
- // /vendor/overlay/framework-res.apk
- // /vendor/overlay/PG/android-framework-runtime-resource-overlay.apk
- // /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap
- // /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap
- // See AssetManager.cpp for more details on overlay-subdir.
- static const char* kOverlayDir = "/system/vendor/overlay/";
- static const char* kVendorOverlayDir = "/vendor/overlay";
- static const char* kVendorOverlaySubdir = "/system/vendor/overlay-subdir/";
- static const char* kSystemProductOverlayDir = "/system/product/overlay/";
- static const char* kProductOverlayDir = "/product/overlay";
- static const char* kSystemSystemExtOverlayDir = "/system/system_ext/overlay/";
- static const char* kSystemExtOverlayDir = "/system_ext/overlay";
- static const char* kSystemOdmOverlayDir = "/system/odm/overlay";
- static const char* kOdmOverlayDir = "/odm/overlay";
- static const char* kSystemOemOverlayDir = "/system/oem/overlay";
- static const char* kOemOverlayDir = "/oem/overlay";
- static const char* kApkSuffix = ".apk";
+ static const char* kJarSuffix = ".jar";
- if ((android::base::StartsWith(path, kOverlayDir)
- || android::base::StartsWith(path, kVendorOverlaySubdir)
- || android::base::StartsWith(path, kVendorOverlayDir)
- || android::base::StartsWith(path, kSystemProductOverlayDir)
- || android::base::StartsWith(path, kProductOverlayDir)
- || android::base::StartsWith(path, kSystemSystemExtOverlayDir)
- || android::base::StartsWith(path, kSystemExtOverlayDir)
- || android::base::StartsWith(path, kSystemOdmOverlayDir)
- || android::base::StartsWith(path, kOdmOverlayDir)
- || android::base::StartsWith(path, kSystemOemOverlayDir)
- || android::base::StartsWith(path, kOemOverlayDir))
- && android::base::EndsWith(path, kApkSuffix)
- && path.find("/../") == std::string::npos) {
- return true;
- }
+ for (const auto& frameworks_prefix : kFrameworksPrefix) {
+ if (android::base::StartsWith(path, frameworks_prefix) &&
+ android::base::EndsWith(path, kJarSuffix)) {
+ return true;
+ }
+ }
- static const char* kOverlayIdmapPrefix = "/data/resource-cache/";
- static const char* kOverlayIdmapSuffix = ".apk@idmap";
- if (android::base::StartsWith(path, kOverlayIdmapPrefix)
- && android::base::EndsWith(path, kOverlayIdmapSuffix)
- && path.find("/../") == std::string::npos) {
- return true;
- }
+ // Jars from APEXes are allowed. This matches /apex/**/javalib/*.jar.
+ static const char* kApexPrefix = "/apex/";
+ static const char* kApexJavalibPathSuffix = "/javalib";
+ if (android::base::StartsWith(path, kApexPrefix) && android::base::EndsWith(path, kJarSuffix) &&
+ android::base::EndsWith(android::base::Dirname(path), kApexJavalibPathSuffix)) {
+ return true;
+ }
- // All regular files that are placed under this path are whitelisted automatically.
- static const char* kZygoteWhitelistPath = "/vendor/zygote_whitelist/";
- if (android::base::StartsWith(path, kZygoteWhitelistPath)
- && path.find("/../") == std::string::npos) {
- return true;
- }
+ // the in-memory file created by ART through memfd_create is allowed.
+ if (IsArtMemfd(path)) {
+ return true;
+ }
- return false;
+ // Allowlist files needed for Runtime Resource Overlay, like these:
+ // /system/vendor/overlay/framework-res.apk
+ // /system/vendor/overlay-subdir/pg/framework-res.apk
+ // /vendor/overlay/framework-res.apk
+ // /vendor/overlay/PG/android-framework-runtime-resource-overlay.apk
+ // /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap
+ // /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap
+ // See AssetManager.cpp for more details on overlay-subdir.
+ static const char* kOverlayDir = "/system/vendor/overlay/";
+ static const char* kVendorOverlayDir = "/vendor/overlay";
+ static const char* kVendorOverlaySubdir = "/system/vendor/overlay-subdir/";
+ static const char* kSystemProductOverlayDir = "/system/product/overlay/";
+ static const char* kProductOverlayDir = "/product/overlay";
+ static const char* kSystemSystemExtOverlayDir = "/system/system_ext/overlay/";
+ static const char* kSystemExtOverlayDir = "/system_ext/overlay";
+ static const char* kSystemOdmOverlayDir = "/system/odm/overlay";
+ static const char* kOdmOverlayDir = "/odm/overlay";
+ static const char* kSystemOemOverlayDir = "/system/oem/overlay";
+ static const char* kOemOverlayDir = "/oem/overlay";
+ static const char* kApkSuffix = ".apk";
+
+ if ((android::base::StartsWith(path, kOverlayDir) ||
+ android::base::StartsWith(path, kVendorOverlaySubdir) ||
+ android::base::StartsWith(path, kVendorOverlayDir) ||
+ android::base::StartsWith(path, kSystemProductOverlayDir) ||
+ android::base::StartsWith(path, kProductOverlayDir) ||
+ android::base::StartsWith(path, kSystemSystemExtOverlayDir) ||
+ android::base::StartsWith(path, kSystemExtOverlayDir) ||
+ android::base::StartsWith(path, kSystemOdmOverlayDir) ||
+ android::base::StartsWith(path, kOdmOverlayDir) ||
+ android::base::StartsWith(path, kSystemOemOverlayDir) ||
+ android::base::StartsWith(path, kOemOverlayDir)) &&
+ android::base::EndsWith(path, kApkSuffix) && path.find("/../") == std::string::npos) {
+ return true;
+ }
+
+ static const char* kOverlayIdmapPrefix = "/data/resource-cache/";
+ static const char* kOverlayIdmapSuffix = ".apk@idmap";
+ if (android::base::StartsWith(path, kOverlayIdmapPrefix) &&
+ android::base::EndsWith(path, kOverlayIdmapSuffix) &&
+ path.find("/../") == std::string::npos) {
+ return true;
+ }
+
+ // All regular files that are placed under this path are allowlisted
+ // automatically. The directory name is maintained for compatibility.
+ static const char* kZygoteAllowlistPath = "/vendor/zygote_whitelist/";
+ if (android::base::StartsWith(path, kZygoteAllowlistPath) &&
+ path.find("/../") == std::string::npos) {
+ return true;
+ }
+
+ return false;
}
-FileDescriptorWhitelist::FileDescriptorWhitelist()
- : whitelist_() {
-}
+FileDescriptorAllowlist::FileDescriptorAllowlist() : allowlist_() {}
-FileDescriptorWhitelist* FileDescriptorWhitelist::instance_ = nullptr;
+FileDescriptorAllowlist* FileDescriptorAllowlist::instance_ = nullptr;
// Keeps track of all relevant information (flags, offset etc.) of an
// open zygote file descriptor.
@@ -217,7 +213,7 @@
fail_fn(android::base::StringPrintf("Unable to stat %d", fd));
}
- const FileDescriptorWhitelist* whitelist = FileDescriptorWhitelist::Get();
+ const FileDescriptorAllowlist* allowlist = FileDescriptorAllowlist::Get();
if (S_ISSOCK(f_stat.st_mode)) {
std::string socket_name;
@@ -225,16 +221,15 @@
fail_fn("Unable to get socket name");
}
- if (!whitelist->IsAllowed(socket_name)) {
- fail_fn(android::base::StringPrintf("Socket name not whitelisted : %s (fd=%d)",
- socket_name.c_str(),
- fd));
+ if (!allowlist->IsAllowed(socket_name)) {
+ fail_fn(android::base::StringPrintf("Socket name not allowlisted : %s (fd=%d)",
+ socket_name.c_str(), fd));
}
return new FileDescriptorInfo(fd);
}
- // We only handle whitelisted regular files and character devices. Whitelisted
+ // We only handle allowlisted regular files and character devices. Allowlisted
// character devices must provide a guarantee of sensible behaviour when
// reopened.
//
@@ -268,8 +263,8 @@
strerror(errno)));
}
- if (!whitelist->IsAllowed(file_path)) {
- fail_fn(android::base::StringPrintf("Not whitelisted (%d): %s", fd, file_path.c_str()));
+ if (!allowlist->IsAllowed(file_path)) {
+ fail_fn(android::base::StringPrintf("Not allowlisted (%d): %s", fd, file_path.c_str()));
}
// File descriptor flags : currently on FD_CLOEXEC. We can set these
diff --git a/core/jni/fd_utils.h b/core/jni/fd_utils.h
index 2caf157..14c318e 100644
--- a/core/jni/fd_utils.h
+++ b/core/jni/fd_utils.h
@@ -33,42 +33,40 @@
// This type is duplicated in com_android_internal_os_Zygote.cpp
typedef const std::function<void(std::string)>& fail_fn_t;
-// Whitelist of open paths that the zygote is allowed to keep open.
+// Allowlist of open paths that the zygote is allowed to keep open.
//
-// In addition to the paths listed in kPathWhitelist in file_utils.cpp, and
+// In addition to the paths listed in kPathAllowlist in file_utils.cpp, and
// paths dynamically added with Allow(), all files ending with ".jar"
-// under /system/framework" are whitelisted. See IsAllowed() for the canonical
+// under /system/framework" are allowlisted. See IsAllowed() for the canonical
// definition.
//
-// If the whitelisted path is associated with a regular file or a
+// If the allowlisted path is associated with a regular file or a
// character device, the file is reopened after a fork with the same
-// offset and mode. If the whilelisted path is associated with a
+// offset and mode. If the allowlisted path is associated with a
// AF_UNIX socket, the socket will refer to /dev/null after each
// fork, and all operations on it will fail.
-class FileDescriptorWhitelist {
- public:
- // Lazily creates the global whitelist.
- static FileDescriptorWhitelist* Get();
+class FileDescriptorAllowlist {
+public:
+ // Lazily creates the global allowlist.
+ static FileDescriptorAllowlist* Get();
- // Adds a path to the whitelist.
- void Allow(const std::string& path) {
- whitelist_.push_back(path);
- }
+ // Adds a path to the allowlist.
+ void Allow(const std::string& path) { allowlist_.push_back(path); }
- // Returns true iff. a given path is whitelisted. A path is whitelisted
- // if it belongs to the whitelist (see kPathWhitelist) or if it's a path
- // under /system/framework that ends with ".jar" or if it is a system
- // framework overlay.
- bool IsAllowed(const std::string& path) const;
+ // Returns true iff. a given path is allowlisted. A path is allowlisted
+ // if it belongs to the allowlist (see kPathAllowlist) or if it's a path
+ // under /system/framework that ends with ".jar" or if it is a system
+ // framework overlay.
+ bool IsAllowed(const std::string& path) const;
- private:
- FileDescriptorWhitelist();
+private:
+ FileDescriptorAllowlist();
- static FileDescriptorWhitelist* instance_;
+ static FileDescriptorAllowlist* instance_;
- std::vector<std::string> whitelist_;
+ std::vector<std::string> allowlist_;
- DISALLOW_COPY_AND_ASSIGN(FileDescriptorWhitelist);
+ DISALLOW_COPY_AND_ASSIGN(FileDescriptorAllowlist);
};
// A FileDescriptorTable is a collection of FileDescriptorInfo objects
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index ec41a47..74a37ca 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -628,6 +628,7 @@
optional string tag = 3;
optional int32 type = 4;
optional int32 reason_code = 5;
+ optional int32 calling_uid = 6;
}
repeated PendingTempWhitelist pending_temp_whitelist = 26;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 50d1e6b..4bbb69f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1876,15 +1876,15 @@
<permission android:name="android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE"
android:protectionLevel="signature|privileged" />
- <!-- @SystemApi @hide Allows system APK to update Wifi/Cellular coex channels to avoid.
+ <!-- @SystemApi @hide Allows applications to update Wifi/Cellular coex channels to avoid.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature|role" />
<!-- @SystemApi @hide Allows applications to access Wifi/Cellular coex channels being avoided.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|role" />
<!-- @SystemApi @hide Allows system APK to manage country code.
<p>Not for use by third-party applications. -->
@@ -5561,6 +5561,11 @@
<permission android:name="android.permission.READ_PEOPLE_DATA"
android:protectionLevel="signature|appPredictor|recents"/>
+ <!-- @hide @SystemApi Allows a logical component within an application to
+ temporarily renounce a set of otherwise granted permissions. -->
+ <permission android:name="android.permission.RENOUNCE_PERMISSIONS"
+ android:protectionLevel="signature|privileged" />
+
<!-- Attribution for Geofencing service. -->
<attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
<!-- Attribution for Country Detector. -->
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 4b591bf..648d2a1 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Laat die program toe om jou fotoversameling te wysig."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"lees liggings in jou mediaversameling"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Laat die program toe om liggings in jou mediaversameling te lees."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifieer dat dit jy is"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometriese hardeware is nie beskikbaar nie"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Stawing is gekanselleer"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nie herken nie"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Stawing is gekanselleer"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Geen PIN, patroon of wagwoord is gestel nie"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Kon nie staaf nie"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Gedeeltelike vingerafdruk is bespeur. Probeer asseblief weer."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Kon nie vingerafdruk verwerk nie. Probeer asseblief weer."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Vingerafdruksensor is vuil. Maak dit skoon en probeer weer."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Hierdie toetstel het nie \'n vingerafdruksensor nie."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor is tydelik gedeaktiveer."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Vinger <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Gebruik jou vingerafdruk om voort te gaan"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Kan nie meer gesig herken nie. Probeer weer."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Te eenders. Verander asseblief jou pose."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Draai jou kop \'n bietjie minder."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Kantel jou kop \'n bietjie minder."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Draai jou kop \'n bietjie minder."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Verwyder enigiets wat jou gesig versteek."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Maak die bokant van jou skerm skoon, insluitend die swart balk"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Gesigslot word nie op hierdie toestel gesteun nie."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor is tydelik gedeaktiveer."</string>
<string name="face_name_template" msgid="3877037340223318119">"Gesig <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Gesig-ikoon"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Gebruik kortpad"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Kleuromkering"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Kleurkorreksie"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Verminder helderheid"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Het volumesleutels ingehou. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aangeskakel."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Het volumesleutels ingehou. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> is afgeskakel"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Druk en hou albei volumesleutels drie sekondes lank om <xliff:g id="SERVICE_NAME">%1$s</xliff:g> te gebruik"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Uitvissingwaarskuwing"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Werkprofiel"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Kennisgewing gegee"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Geverifieer"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Vou uit"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Vou in"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"wissel uitvou-aksie"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Nuus en tydskrifte"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Kaarte en navigasie"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produktiwiteit"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Toestelberging"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-ontfouting"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"uur"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Om voort te gaan, moet <b><xliff:g id="APP">%s</xliff:g></b> toegang tot jou toestel se kamera hê."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Skakel aan"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensorprivaatheid"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Programikoon"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Programhandelsmerkprent"</string>
</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index a43b29a..eb98c69 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"መተግበሪያው የፎቶ ስብስብዎን እንዲቀይረው ያስችለዋል።"</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"አካባቢዎችን ከሚዲያ ስብስብዎ ማንበብ"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"መተግበሪያው አካባቢዎችን ከሚዲያ ስብስብዎ እንዲያነብብ ያስችለዋል።"</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"እርስዎን መሆንዎን ያረጋግጡ"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ባዮሜትራዊ ሃርድዌር አይገኝም"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ማረጋገጥ ተሰርዟል"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"አልታወቀም"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"ማረጋገጥ ተሰርዟል"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"ምንም ፒን፣ ሥርዓተ ጥለት ወይም የይለፍ ቃል አልተቀናበረም"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"ማረጋገጥ ላይ ስህተት"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"ከፊል የጣት አሻራ ተገኝቷል። እባክዎ እንደገና ይሞክሩ።"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ጣት አሻራን መስራት አልተቻለም። እባክዎ እንደገና ይሞክሩ።"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"የጣት አሻራ ዳሳሽ ቆሽሿል። እባክዎ ያጽዱት እና እንደገና ይሞክሩ።"</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ይህ መሣሪያ የጣት አሻራ ዳሳሽ የለውም።"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ዳሳሽ ለጊዜው ተሰናክሏል።"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"ጣት <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ለመቀጠል የእርስዎን የጣት አሻራ ይጠቀሙ"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"ከእንግዲህ ፊትን ለይቶ ማወቅ አይችልም። እንደገና ይሞክሩ።"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"በጣም ይመሳሰላል፣ እባክዎ የእርስዎን ፎቶ አነሳስ ይለውጡ"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ጭንቅላትዎን ትንሽ ብቻ ያዙሩት።"</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"ጭንቅላትዎን ትንሽ ብቻ ያጋድሉት።"</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ጭንቅላትዎን ትንሽ ብቻ ያዙሩት።"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"የእርስዎን ፊት የሚደብቀውን ሁሉንም ነገር በማስወገድ ላይ"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"የማያ ገጽዎን አናት ያጽዱት፣ ጥቁር አሞሌውን ጨምሮ"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"በመልክ መክፈት መስጫ በዚህ መሣሪያ ላይ አይደገፍም።"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"ዳሳሽ ለጊዜው ተሰናክሏል።"</string>
<string name="face_name_template" msgid="3877037340223318119">"ፊት <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"የፊት አዶ"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"አቋራጭ ይጠቀሙ"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"ተቃራኒ ቀለም"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"የቀለም ማስተካከያ"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"ብሩህነትን ይቀንሱ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"የድምፅ ቁልፎችን ይዟል። <xliff:g id="SERVICE_NAME">%1$s</xliff:g> በርቷል።"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"የድምፅ ቁልፎችን ይዟል። <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ጠፍተዋል።"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ን ለመጠቀም ለሦስት ሰከንዶች ሁለቱንም የድምፅ ቁልፎች ተጭነው ይያዙ"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"የማስገር ማንቂያ"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"የስራ መገለጫ"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"ነቅተዋል"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"ተረጋግጧል"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"ዘርጋ"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"ሰብስብ"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"ዝርጋታን ቀያይር"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"ዜና እና መጽሔቶች"</string>
<string name="app_category_maps" msgid="6395725487922533156">"ካርታዎች እና ዳሰሳ"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"ውጤታማነት"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"የመሣሪያ ማከማቻ"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"የዩኤስቢ ማረሚያ"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ሰዓት"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ለመቀጠል፣ <b><xliff:g id="APP">%s</xliff:g></b> የመሣሪያዎን ካሜራ መድረስ ይፈልጋል።"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"አብራ"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ዳሳሽ ግላዊነት"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"የመተግበሪያ አዶ"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"የመተግበሪያ የምርት ስም ምስል"</string>
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 3990bab..d6759b6 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -562,13 +562,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"للسماح للتطبيق بتعديل مجموعة صورك."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"قراءة المواقع من مجموعة الوسائط التابعة لك"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"للسماح للتطبيق بقراءة المواقع من مجموعة الوسائط التابعة لك."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"إثبات هويتك"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"معدّات المقاييس الحيوية غير متاحة."</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"تم إلغاء المصادقة."</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"لم يتم التعرف عليها."</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"تم إلغاء المصادقة."</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"لم يتم ضبط رقم تعريف شخصي أو نقش أو كلمة مرور."</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"خطأ في المصادقة"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"تم اكتشاف جزء من بصمة الإصبع فقط؛ يرجى إعادة المحاولة."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"تعذرت معالجة بصمة الإصبع. يُرجى إعادة المحاولة."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"زر استشعار بصمات الأصابع متّسخ. يُرجى تنظيفه وإعادة المحاولة."</string>
@@ -591,6 +601,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"لا يحتوي هذا الجهاز على مستشعِر بصمات إصبع."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"تم إيقاف جهاز الاستشعار مؤقتًا."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"الإصبع <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"يمكنك استخدام بصمة الإصبع للمتابعة."</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -618,8 +632,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"لم يعُد يمكن التعرّف على الوجه. حاول مرة أخرى."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"الوجه مشابه جدًا، يُرجى تغيير وضعيتك."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"حرّك رأسك قليلاً نحو الأمام مباشرة."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"يُرجى إمالة رأسك أقل قليلاً."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"حرّك رأسك قليلاً نحو الوسط."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"عليك بإزالة أي شيء يُخفي وجهك."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"يُرجى تنظيف الجزء العلوي من الشاشة، بما في ذلك الشريط الأسود."</string>
@@ -637,6 +650,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"\"فتح القفل بالوجه\" غير متوفر على هذا الجهاز."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"تم إيقاف جهاز الاستشعار مؤقتًا."</string>
<string name="face_name_template" msgid="3877037340223318119">"الوجه <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"رمز الوجه"</string>
@@ -1756,8 +1775,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"استخدام الاختصار"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"قلب الألوان"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"تصحيح الألوان"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"تقليل السطوع"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"تم الضغط مع الاستمرار على مفتاحَي التحكّم في مستوى الصوت. تم تفعيل <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"تم الضغط مع الاستمرار على مفتاحَي التحكّم في مستوى الصوت. تم إيقاف <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"اضغط مع الاستمرار على مفتاحي مستوى الصوت لمدة 3 ثوانٍ لاستخدام <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
@@ -2000,6 +2018,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"تنبيه بشأن تصيّد احتيالي"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"الملف الشخصي للعمل"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"تمّ تفعيل التنبيه"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"تم التحقّق"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"توسيع"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"تصغير"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"تبديل التوسيع"</string>
@@ -2075,6 +2094,8 @@
<string name="app_category_news" msgid="1172762719574964544">"الأخبار والمجلات"</string>
<string name="app_category_maps" msgid="6395725487922533156">"الخرائط والتنقل"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"الإنتاجية"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"مساحة التخزين للجهاز"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"تصحيح أخطاء USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ساعة"</string>
@@ -2357,8 +2378,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"للمتابعة، يحتاج تطبيق <b><xliff:g id="APP">%s</xliff:g></b> إلى الوصول إلى كاميرا الجهاز."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"تفعيل"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"الخصوصية في جهاز الاستشعار"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"رمز التطبيق"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"الصورة الذهنية للعلامة التجارية للتطبيق"</string>
</resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 28af8a3..0a4c397 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"এপক আপোনাৰ ফট’ সংগ্ৰহ সালসলনি কৰিবলৈ দিয়ে।"</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"আপোনাৰ মিডিয়া সংগ্ৰহৰ অৱস্থান পঢ়িবলৈ"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"এপক আপোনাৰ মিডিয়া সংগ্ৰহৰ অৱস্থান পঢ়িবলৈ দিয়ে।"</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"এইয়া আপুনিয়েই বুলি সত্যাপন কৰক"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"বায়োমেট্ৰিক হাৰ্ডৱেৰ উপলব্ধ নহয়"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"বিশ্বাসযোগ্যতাৰ প্ৰমাণীকৰণ বাতিল কৰা হৈছে"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"চিনাক্ত কৰিব পৰা নাই"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"বিশ্বাসযোগ্যতাৰ প্ৰমাণীকৰণ বাতিল কৰা হৈছে"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"কোনো পিন, আৰ্হি বা পাছৱৰ্ড ছেট কৰা নাই"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"আসোঁৱাহৰ বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰি থকা হৈছে"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"ফিংগাৰপ্ৰিণ্ট আংশিকভাৱে চিনাক্ত কৰা হৈছে। অনুগ্ৰহ কৰি আকৌ চেষ্টা কৰক৷"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ফিগাৰপ্ৰিণ্টৰ প্ৰক্ৰিয়া সম্পাদন কৰিবপৰা নগ\'ল। অনুগ্ৰহ কৰি আকৌ চেষ্টা কৰক৷"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো লেতেৰা হৈ আছে। অনুগ্ৰহ কৰি পৰিষ্কাৰ কৰি আকৌ চেষ্টা কৰক।"</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"এই ডিভাইচটোত ফিংগাৰপ্ৰিণ্ট ছেন্সৰ নাই।"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ছেন্সৰটো সাময়িকভাৱে অক্ষম হৈ আছে।"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> আঙুলি"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"অব্যাহত ৰাখিবলৈ আপোনাৰ ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"মুখমণ্ডল আৰু চিনাক্ত কৰিব নোৱাৰি। আকৌ চেষ্টা কৰক।"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"একে ধৰণৰ হৈছে, অনুগ্ৰহ কৰি আপোনাৰ প’জটো সলনি কৰক।"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"আপোনাৰ মূৰটো সামান্য কমকৈ ঘূৰাওক।"</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"আপোনাৰ মূৰটো অলপ কমকৈ হেলনীয়া কৰক।"</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"আপোনাৰ মূৰটো সামান্য কমকৈ ঘূৰাওক।"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"আপোনাৰ মুখখন ঢাকি ৰখা বস্তুবোৰ আঁতৰাওক।"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ক’লা বাৰডালকে ধৰি আপোনাৰ স্ক্রীণৰ ওপৰৰ অংশ চাফা কৰক"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"এই ডিভাইচটোত মুখাৱয়বৰদ্বাৰা আনলক কৰা সুবিধাটো নচলে।"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"ছেন্সৰটো সাময়িকভাৱে অক্ষম হৈ আছে।"</string>
<string name="face_name_template" msgid="3877037340223318119">"মুখমণ্ডল <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"মুখমণ্ডলৰ আইকন"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"শ্বৰ্টকাট ব্যৱহাৰ কৰক"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"ৰং বিপৰীতকৰণ"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"ৰং শুধৰণী"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"উজ্জ্বলতা কমাওক"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ভলিউম কীসমূহ ধৰি ৰাখক। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> অন কৰা হ\'ল।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ভলিউম কী ধৰি ৰাখিছিল। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> অফ কৰা হ\'ল।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ব্যৱহাৰ কৰিবলৈ দুয়োটা ভলিউম বুটাম তিনি ছেকেণ্ডৰ বাবে হেঁচি ৰাখক"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ফিশ্বিঙৰ সতৰ্কবাৰ্তা"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"কৰ্মস্থানৰ প্ৰ\'ফাইল"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"সতৰ্ক কৰা হ’ল"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"সত্যাপিত"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"বিস্তাৰ কৰক"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"সংকুচিত কৰক"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"সম্প্ৰসাৰণ ট’গল কৰক"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"বাতৰি আৰু আলোচনী"</string>
<string name="app_category_maps" msgid="6395725487922533156">"মেপ আৰু দিক্-নিৰ্দেশনা"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"উৎপাদনশীলতা"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ডিভাইচৰ সঞ্চয়াগাৰ"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"ইউএছবি ডিবাগিং"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ঘণ্টা"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"অব্যাহত ৰাখিবলৈ <b><xliff:g id="APP">%s</xliff:g></b>এ আপোনাৰ ডিভাইচৰ কেমেৰা এক্সেছ কৰাৰ আৱশ্যক।"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"অন কৰক"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ছেন্সৰ সম্পৰ্কীয় গোপনীয়তাৰ নীতি"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"এপ্লিকেশ্বনৰ চিহ্ন"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"এপ্লিকেশ্বনৰ ব্ৰেণ্ডৰ প্ৰতিচ্ছবি"</string>
</resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 8459403..afb5c39 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Tətbiqin foto kolleksiyanıza düzəliş etməsinə icazə verir."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"media kolleksiyanızdan məkanları oxuyun"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Tətbiqin media kolleksiyanızdan məkanları oxumasına icazə verin."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Kimliyinizi doğrulayın"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrik proqram əlçatan deyil"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Doğrulama ləğv edildi"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Tanınmır"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Doğrulama ləğv edildi"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Pin, nümunə və ya parol ayarlanmayıb"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Doğrulama zamanı xəta baş verdi"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Barmaq izi yarımçıq müəyyən olundu. Lütfən, yenidən cəhd edin."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Barmaq izi tanınmadı. Lütfən, yenidən cəhd edin."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Barmaq izi sensoru çirklidir. Lütfən, təmizləyin və yenidən cəhd edin."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu cihazda barmaq izi sensoru yoxdur."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor müvəqqəti deaktivdir."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Barmaq <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Davam etmək üçün barmaq izinizi istifadə edin"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Üzü artıq tanımaq olmur. Yenidən cəhd edin."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Digəri ilə oxşardır, pozanızı dəyişin."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Başınızı bir az döndərin."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Başınızı azca əyin."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Başınızı bir az döndərin."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Üzünüzü gizlədən maneələri kənarlaşdırın."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Qara panel daxil olmaqla, ekranın yuxarısını təmizləyin"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Üz kilidi bu cihazda dəstəklənmir."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor müvəqqəti deaktivdir."</string>
<string name="face_name_template" msgid="3877037340223318119">"Üz <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Üz işarəsi"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Qısayol İstifadə edin"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Rəng İnversiyası"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Rəng korreksiyası"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Parlaqlığı azaldın"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Səs səviyyəsi düymələrinə basıb saxlayın. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktiv edildi."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Səs səviyyəsi düymələrinə basılaraq saxlanıb. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> deaktiv edilib."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> istifadə etmək üçün hər iki səs düyməsini üç saniyə basıb saxlayın"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Fişinq siqnalı"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"İş profili"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Xəbərdarlıq edildi"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Doğrulanmış"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Genişləndirin"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Yığcamlaşdırın"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"keçid genişlənməsi"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Xəbər və Jurnallar"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Xəritə və Naviqasiya"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Məhsuldarlıq"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Cihaz yaddaşı"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB sazlama"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"saat"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Davam etmək üçün <b><xliff:g id="APP">%s</xliff:g></b> tətbiqi cihazın kamerasına giriş tələb edir."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Aktiv edin"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensor Məxfiliyi"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Tətbiq ikonası"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Tətbiqin brend şəkli"</string>
</resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index a7f6433..0d23fa5 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -553,13 +553,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Dozvoljava aplikaciji da menja kolekciju slika."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"čitanje lokacija iz medijske kolekcije"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Dozvoljava aplikaciji da čita lokacije iz medijske kolekcije."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Potvrdite svoj identitet"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrijski hardver nije dostupan"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Potvrda identiteta je otkazana"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nije prepoznato"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Potvrda identiteta je otkazana"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Niste podesili ni PIN, ni šablon, ni lozinku"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Greška pri potvrdi identiteta"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Otkriven je delimični otisak prsta. Probajte ponovo."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Nije uspela obrada otiska prsta. Probajte ponovo."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Senzor za otiske prstiju je prljav. Očistite ga i pokušajte ponovo."</string>
@@ -582,6 +592,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor za otisak prsta."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je privremeno onemogućen."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Nastavite pomoću otiska prsta"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -609,8 +623,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Više ne može da se prepozna lice. Probajte ponovo."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Previše je slično, promenite pozu."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Malo manje pomerite glavu."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Malo manje nagnite glavu."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Malo manje pomerite glavu."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Uklonite sve što vam zaklanja lice."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Očistite gornji deo ekrana, uključujući crnu traku"</string>
@@ -628,6 +641,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Otključavanje licem nije podržano na ovom uređaju"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je privremeno onemogućen."</string>
<string name="face_name_template" msgid="3877037340223318119">"Lice <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Ikona lica"</string>
@@ -1690,8 +1709,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Koristi prečicu"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzija boja"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Korekcija boja"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Smanjite osvetljenost"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Držali ste tastere za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je uključena."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Držali ste tastere za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je isključena."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pritisnite i zadržite oba tastera za jačinu zvuka tri sekunde da biste koristili <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1907,6 +1925,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Upozorenje o „pecanju“"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Poslovni profil"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Obavešteno"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Verifikovano"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Proširi"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Skupi"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"uključite/isključite proširenje"</string>
@@ -1979,6 +1998,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Novosti i časopisi"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Mape i navigacija"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produktivnost"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Memorijski prostor uređaja"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Otklanjanje grešaka sa USB-a"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"sat"</string>
@@ -2255,8 +2276,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"<b><xliff:g id="APP">%s</xliff:g></b> zahteva pristup kameri uređaja radi nastavljanja."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Uključi"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privatnost senzora"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Ikona aplikacije"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imidž brenda aplikacije"</string>
</resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 1022cef..87b4ce7f 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -556,13 +556,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Праграма зможа змяняць фотакалекцыю."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"паказваць месцазнаходжанне ў калекцыі мультымедыя"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Праграма зможа паказваць месцазнаходжанне ў калекцыі мультымедыя."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Спраўдзіце, што гэта вы"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Біяметрычнае абсталяванне недаступнае"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Аўтэнтыфікацыя скасавана"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Не распазнана"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Аўтэнтыфікацыя скасавана"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Не заданы PIN-код, узор разблакіроўкі або пароль"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Памылка аўтэнтыфікацыі"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Адсканіравана толькі частка адбітка пальца. Паспрабуйце яшчэ раз."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Не атрымалася апрацаваць адбітак пальца. Паспрабуйце яшчэ раз."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Сканер адбіткаў пальцаў брудны. Ачысціце яго і паспрабуйце яшчэ раз."</string>
@@ -585,6 +595,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На гэтай прыладзе няма сканера адбіткаў пальцаў."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчык часова выключаны."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Палец <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Каб працягнуць, выкарыстоўвайце свой адбітак пальца"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -612,8 +626,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Не ўдаецца распазнаць твар. Паўтарыце спробу."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Не бачна розніцы. Памяняйце позу."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Вы занадта моцна павярнулі галаву."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Трымайце галаву прама."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Вы занадта моцна павярнулі галаву."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Прыміце ўсё, што закрывае ваш твар."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Ачысціце ад бруду верхнюю частку экрана, у тым ліку чорную панэль"</string>
@@ -631,6 +644,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"На гэтай прыладзе распазнаванне твару не падтрымліваецца."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Датчык часова выключаны."</string>
<string name="face_name_template" msgid="3877037340223318119">"Твар <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Значок твару"</string>
@@ -1712,8 +1731,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Выкарыстоўваць камбінацыю хуткага доступу"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Інверсія колеру"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Карэкцыя колеру"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Паменшыць яркасць"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Клавішы гучнасці ўтрымліваліся націснутымі. Уключана служба \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\"."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Клавішы гучнасці ўтрымліваліся націснутымі. Служба \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\" выключана."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Каб карыстацца сэрвісам \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\", націсніце і ўтрымлівайце на працягу трох секунд абедзве клавішы гучнасці"</string>
@@ -1938,6 +1956,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Абвестка пра фішынг"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Працоўны профіль"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"З гукам"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Спраўджана"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Разгарнуць"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Згарнуць"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"разгарнуць/згарнуць"</string>
@@ -2011,6 +2030,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Навіны і часопісы"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Карты і навігацыя"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Прадукцыйнасць"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Сховішча на прыладзе"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Адладка USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"гадз"</string>
@@ -2289,8 +2310,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Каб працягнуць, дайце праграме <b><xliff:g id="APP">%s</xliff:g></b> доступ да камеры прылады."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Уключыць"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Прыватнасць інфармацыі з датчыка"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Значок праграмы"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Відарыс брэнда праграмы"</string>
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index ef20bad..7e847e0 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Разрешава на приложението да променя колекцията ви от снимки."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"да чете местоположенията от мултимедийната ви колекция"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Разрешава на приложението да чете местоположенията от мултимедийната ви колекция."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Потвърдете, че сте вие"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометричният хардуер не е налице"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Удостоверяването бе анулирано"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Не е разпознато"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Удостоверяването бе анулирано"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Няма зададен ПИН код, фигура или парола"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Грешка при удостоверяването"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Открит е частичен отпечатък. Моля, опитайте отново."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Отпечатъкът не бе обработен. Моля, опитайте отново."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Сензорът за отпечатъци е мръсен. Моля, почистете го и опитайте отново."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Това устройство няма сензор за отпечатъци."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензорът е временно деактивиран."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Пръст <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Използвайте отпечатъка си, за да продължите"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Лицето не бе разпознато. Опитайте отново."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Позата ви е сходна с предишна. Моля, променете я."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Не завъртайте главата си толкова много."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Не накланяйте главата си толкова много."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Не завъртайте главата си толкова много."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Премахнете всичко, което закрива лицето ви."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Почистете горната част на екрана си, включително черната лента"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Отключването с лице не се поддържа на това устройство."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Сензорът е временно деактивиран."</string>
<string name="face_name_template" msgid="3877037340223318119">"Лице <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Икона на лице"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Използване на пряк път"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Инвертиране на цветовете"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Коригиране на цветовете"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Намаляване на яркостта"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Задържахте бутоните за силата на звука. Услугата <xliff:g id="SERVICE_NAME">%1$s</xliff:g> е включена."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Задържахте бутоните за силата на звука. Услугата <xliff:g id="SERVICE_NAME">%1$s</xliff:g> е изключена."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"За да използвате <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, натиснете двата бутона за силата на звука и ги задръжте за 3 секунди"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Сигнал за фишинг"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Служебен потребителски профил"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Сигналът е изпратен"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Потвърдено"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Разгъване"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Свиване"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"превключване на разгъването"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Новини и списания"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Карти и навигация"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Производителност"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Хранилище на устройството"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Отстраняване на грешки през USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"час"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"За да продължите, <b><xliff:g id="APP">%s</xliff:g></b> се нуждае от достъп до камерата на устройството ви."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Включване"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Поверителност на сензорните данни"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Икона на приложението"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Изображение на търговската марка на приложението"</string>
</resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 0e30c04..4d3d793 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"অ্যাপকে আপনার ফটো সংগ্রহ পরিবর্তন করার অনুমতি দিন।"</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"ডিয়া সংগ্রহ থেকে লোকেশন দেখতে দিন"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"আপনার মিডিয়া সংগ্রহ থেকে লোকেশন দেখতে অ্যাপকে অনুমতি দিন।"</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"আপনার পরিচয় যাচাই করুন"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"বায়োমেট্রিক হার্ডওয়্যার পাওয়া যাবে না"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"যাচাইকরণ বাতিল হয়েছে"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"স্বীকৃত নয়"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"যাচাইকরণ বাতিল হয়েছে"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"পিন, প্যাটার্ন অথবা পাসওয়ার্ড সেট করা নেই"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"যাচাইকরণে সমস্যা হয়েছে"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"আঙ্গুলের ছাপ আংশিক শনাক্ত করা হয়েছে৷ অনুগ্রহ করে আবার চেষ্টা করুন৷"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"আঙ্গুলের ছাপ প্রক্রিয়া করা যায়নি৷ অনুগ্রহ করে আবার চেষ্টা করুন৷"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"আঙ্গুলের ছাপ নেওয়ার সেন্সরটি অপরিস্কার৷ পরিষ্কার করে আবার চেষ্টা করুন৷"</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"এই ডিভাইসে আঙ্গুলের ছাপ নেওয়ার সেন্সর নেই।"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"সেন্সর অস্থায়ীভাবে বন্ধ করা আছে।"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"আঙ্গুল <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"চালিয়ে যেতে আঙ্গুলের ছাপ ব্যবহার করুন"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"আর মুখ চিনতে পারবেন না। আবার চেষ্টা করুন।"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"একই ধরনের দেখতে, একটু অন্যদিকে ঘুরে দাঁড়ান।"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"আপনার মাথাটি নিচের দিকে সামান্য নামান।"</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"আপনার মাথা একটু কম ঝোঁকান।"</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"আপনার মাথাটি সামান্য ঘোরান।"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"আপনার ফেসকে আড়াল করে এমন সব কিছু সরিয়ে দিন।"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ব্ল্যাক বার সহ আপনার স্ক্রিনের উপরের অংশ মুছে ফেলুন"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"এই ডিভাইসে মুখের সাহায্যে আনলক করার সুবিধাটি কাজ করে না।"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"সেন্সর অস্থায়ীভাবে বন্ধ করা আছে।"</string>
<string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> ফেস"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"ফেস আইকন"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"শর্টকাট ব্যবহার করুন"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"রঙ উল্টানো"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"রঙ সংশোধন"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"উজ্জ্বলতা কমান"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ভলিউম কী ধরে ছিলেন। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> চালু করা হয়েছে।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ভলিউম কী ধরে ছিলেন। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> বন্ধ করা হয়েছে।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ব্যবহার করতে ভলিউম কী বোতাম ৩ সেকেন্ডের জন্য চেপে ধরে রাখুন"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ফিশিংয়ের সতর্কতা"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"কর্মস্থলের প্রোফাইল"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"সতর্ক করা হয়েছে"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"যাচাই করা হয়েছে"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"বড় করুন"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"সঙ্কুচিত করুন"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"টগল সম্প্রসারণ"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"খবর ও পত্রিকাগুলি"</string>
<string name="app_category_maps" msgid="6395725487922533156">"ম্যাপ ও নেভিগেশান"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"উৎপাদনশীলতা"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ডিভাইসের স্টোরেজ"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB ডিবাগিং"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ঘণ্টা"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"চালিয়ে যেতে, <b><xliff:g id="APP">%s</xliff:g></b> আপনার ডিভাইসের ক্যামেরা অ্যাক্সেস করতে চায়।"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"চালু করুন"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"সেন্সর গোপনীয়তা"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"অ্যাপের আইকন"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"অ্যাপের ব্র্যান্ড ছবি"</string>
</resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 77b64b5..2e24175 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -553,13 +553,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Omogućava aplikaciji da mijenja vašu kolekciju fotografija."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"čitanje lokacija iz kolekcije medija"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Omogućava aplikaciji da čita lokacije iz vaše kolekcije medija."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Potvrdite identitet"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrijski hardver nije dostupan"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentifikacija je otkazana"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nije prepoznato"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentifikacija je otkazana"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nije postavljen PIN, uzorak niti lozinka"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Greška pri autentifikaciji"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Otkriven je djelimični otisak prsta. Pokušajte ponovo."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Obrada otiska prsta nije uspjela. Pokušajte ponovo."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Senzor za otisak prsta je prljav. Očistite ga i pokušajte ponovo."</string>
@@ -582,6 +592,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor za otisak prsta."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je privremeno onemogućen."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Nastavite pomoću otiska prsta"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -609,8 +623,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Više nije moguće prepoznati lice. Pokušajte opet."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Previše slično, promijenite položaj."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Malo manje zakrenite glavu."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Malo manje nagnite glavu."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Malo manje zakrenite glavu."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Uklonite prepreke koje blokiraju vaše lice."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Očistite vrh ekrana, uključujući crnu traku"</string>
@@ -628,6 +641,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Otključavanje licem nije podržano na ovom uređaju."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je privremeno onemogućen."</string>
<string name="face_name_template" msgid="3877037340223318119">"Lice <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Ikona lica"</string>
@@ -1690,8 +1709,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Koristi prečicu"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzija boja"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Ispravka boja"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Smanjenje osvjetljenja"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Držali ste tipke za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je uključena."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Držali ste tipke za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je isključena."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pritisnite obje tipke za podešavanje jačine zvuka i držite ih pritisnutim tri sekunde da koristite uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1907,6 +1925,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Upozorenje o krađi identiteta"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profil za posao"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Upozoreni"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Potvrđeno"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Proširi"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Suzi"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"aktiviraj/deaktiviraj proširenje"</string>
@@ -1979,6 +1998,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Vijesti i časopisi"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Mape i navigacija"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produktivnost"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Memorija uređaja"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Otklanjanje grešaka putem USB-a"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"sat"</string>
@@ -2255,8 +2276,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Da nastavite, aplikaciji <b><xliff:g id="APP">%s</xliff:g></b> je potreban pristup kameri vašeg uređaja."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Uključi"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privatnost senzora"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Ikona aplikacije"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Slika robne marke za aplikaciju"</string>
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index a226ac3..70caa2c 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permet que l\'aplicació modifiqui la teva col·lecció de fotos."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"llegir les ubicacions de les teves col·leccions multimèdia"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Permet que l\'aplicació llegeixi les ubicacions de les teves col·leccions multimèdia."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica que ets tu"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Maquinari biomètric no disponible"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"S\'ha cancel·lat l\'autenticació"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"No s\'ha reconegut"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"S\'ha cancel·lat l\'autenticació"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No s\'ha definit cap PIN, patró o contrasenya"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Error en l\'autenticació"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"S\'ha detectat una empremta digital parcial. Torna-ho a provar."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"No s\'ha pogut processar l\'empremta digital. Torna-ho a provar."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"El sensor d\'empremtes dactilars està brut. Neteja\'l i torna-ho a provar."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Aquest dispositiu no té sensor d\'empremtes dactilars."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"El sensor està desactivat temporalment."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dit <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Fes servir l\'empremta digital per continuar"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Ja no es reconeix la teva cara. Torna-ho a provar."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"És massa semblant; canvia de postura."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"No giris tant el cap."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"No inclinis tant el cap."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"No giris tant el cap."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Suprimeix qualsevol cosa que amagui la teva cara."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Neteja la part superior de la pantalla, inclosa la barra negra"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"El desbloqueig facial no és compatible amb el dispositiu."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"El sensor està desactivat temporalment."</string>
<string name="face_name_template" msgid="3877037340223318119">"Cara <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Icona facial"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilitza la drecera"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversió de colors"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Correcció de color"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Reducció de la brillantor"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"S\'han mantingut premudes les tecles de volum. S\'ha activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"S\'han mantingut premudes les tecles de volum. S\'ha desactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Mantén premudes les dues tecles de volum durant 3 segons per fer servir <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerta de pesca de credencials"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de treball"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"S\'ha enviat una alerta"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Verificat"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Desplega"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Replega"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"desplega o replega"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Notícies i revistes"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Mapes i navegació"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Productivitat"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Emmagatzematge del dispositiu"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Depuració per USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"hora"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Per continuar, <b><xliff:g id="APP">%s</xliff:g></b> necessita accedir a la càmera del dispositiu."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Activa"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privadesa dels sensors"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Icona d\'aplicació"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imatge de brànding de l\'aplicació"</string>
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index fdb2ff1..0f73266 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -556,13 +556,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Umožňuje aplikaci upravit vaši sbírku fotek."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"čtení míst ze sbírky médií"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Umožňuje aplikaci číst místa z vaší sbírky médií."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Potvrďte, že jste to vy"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrický hardware není k dispozici"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Ověření bylo zrušeno"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nerozpoznáno"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Ověření bylo zrušeno"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Není nastaven žádný PIN, gesto ani heslo"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Při ověřování došlo k chybě"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Byla zjištěna jen část otisku prstu. Zkuste to znovu."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Zpracování otisku prstu se nezdařilo. Zkuste to znovu."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Senzor otisků prstů je znečištěn. Vyčistěte jej a zkuste to znovu."</string>
@@ -585,6 +595,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Toto zařízení nemá snímač otisků prstů."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je dočasně deaktivován."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Pokračujte přiložením prstu"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -612,8 +626,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Obličej už nelze rozpoznat. Zkuste to znovu."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Příliš podobné, změňte výraz."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Natočte hlavu o něco méně."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Nakloňte hlavu trochu méně."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Natočte hlavu o něco méně."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Odstraňte vše, co vám zakrývá obličej."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Očistěte horní část obrazovky včetně černé části"</string>
@@ -631,6 +644,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Odemknutí obličejem na tomto zařízení není podporováno."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je dočasně deaktivován."</string>
<string name="face_name_template" msgid="3877037340223318119">"Obličej <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Ikona obličeje"</string>
@@ -1712,8 +1731,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Použít zkratku"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Převrácení barev"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Oprava barev"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Snížit jas"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Byla podržena tlačítka hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je zapnutá."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Byla podržena tlačítka hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> byla vypnuta."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Chcete-li používat službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, tři sekundy podržte stisknutá obě tlačítka hlasitosti"</string>
@@ -1938,6 +1956,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Upozornění na phishing"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Pracovní profil"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Upozorněno"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Ověřeno"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Rozbalit"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Sbalit"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"přepnout rozbalení"</string>
@@ -2011,6 +2030,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Zprávy a časopisy"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Mapy a navigace"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produktivita"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Úložiště zařízení"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Ladění přes USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"hodina"</string>
@@ -2289,8 +2310,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Než budete pokračovat, udělte aplikaci <b><xliff:g id="APP">%s</xliff:g></b> přístup k fotoaparátu na zařízení."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Zapnout"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Ochrana soukromí – senzor"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Ikona aplikace"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Image značky aplikace"</string>
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index dddc070..13afaf2 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -552,13 +552,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Tillader, at appen kan ændre din billedsamling."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"læse placeringer fra din mediesamling"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Tillader, at appen kan læse placeringer fra din mediesamling."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Bekræft, at det er dig"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrisk hardware er ikke tilgængelig"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Godkendelsen blev annulleret"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Ikke genkendt"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Godkendelsen blev annulleret"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Der er ikke angivet pinkode, mønster eller adgangskode"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Der opstod fejl i forbindelse med godkendelse"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Der blev registreret et delvist fingeraftryk. Prøv igen."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Fingeraftrykket kunne ikke behandles. Prøv igen."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingeraftrykslæseren er beskidt. Tør den af, og prøv igen."</string>
@@ -581,6 +591,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Denne enhed har ingen fingeraftrykslæser."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensoren er midlertidigt deaktiveret."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Fingeraftryk <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Brug dit fingeraftryk for at fortsætte"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -608,8 +622,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Ansigtet kan ikke længere genkendes. Prøv igen."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Det minder for meget om et andet. Skift stilling."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Du skal ikke dreje hovedet så meget."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Ret dit hoved lidt op."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Du skal ikke dreje hovedet så meget."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Hvis noget skjuler dit ansigt, skal du fjerne det."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Rengør toppen af din skærm, inkl. den sorte bjælke"</string>
@@ -627,6 +640,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Ansigtslås understøttes ikke på denne enhed."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensoren er midlertidigt deaktiveret."</string>
<string name="face_name_template" msgid="3877037340223318119">"Ansigt <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Ansigt"</string>
@@ -1670,8 +1689,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Brug genvej"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Ombytning af farver"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Korriger farve"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Reducer lysstyrken"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Lydstyrkeknapperne blev holdt nede. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er aktiveret."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Lydstyrkeknapperne blev holdt nede. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er deaktiveret."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Hold begge lydstyrkeknapper nede i tre sekunder for at bruge <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1878,6 +1896,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Phishingadvarsel"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Arbejdsprofil"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Underrettet"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Bekræftet"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Udvid"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Skjul"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"Slå udvidelse til eller fra"</string>
@@ -1949,6 +1968,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Aviser og blade"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Kort og navigation"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produktivitet"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Lagerplads på enheden"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-fejlretning"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"time"</string>
@@ -2223,8 +2244,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"<b><xliff:g id="APP">%s</xliff:g></b> skal have adgang til din enheds kamera, før den kan fortsætte."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Aktivér"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Beskyttelse af sensoroplysninger"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Appens ikon"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Appens brandimage"</string>
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 472f1d2..512b3a5 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Ermöglicht der App, deine Fotosammlung zu ändern."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"Standorte aus meiner Mediensammlung abrufen"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Ermöglicht der App, Standorte aus deiner Mediensammlung abzurufen."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Deine Identität bestätigen"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrische Hardware nicht verfügbar"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentifizierung abgebrochen"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nicht erkannt"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Authentifizierung abgebrochen"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Keine PIN, kein Muster und kein Passwort festgelegt"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Fehler bei der Authentifizierung"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Fingerabdruck nur teilweise erkannt. Bitte versuche es noch einmal."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Fingerabdruck konnte nicht verarbeitet werden. Bitte versuche es noch einmal."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingerabdrucksensor ist verschmutzt. Reinige ihn und versuche es noch einmal."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dieses Gerät hat keinen Fingerabdrucksensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Der Sensor ist vorübergehend deaktiviert."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Mithilfe deines Fingerabdrucks fortfahren"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Gesicht wird nicht mehr erkannt. Erneut versuchen."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Zu ähnlich. Bitte dreh deinen Kopf etwas."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Dreh den Kopf etwas weniger zur Seite."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Neig den Kopf etwas weniger stark."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Neig den Kopf etwas weniger stark."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Entferne alles, was dein Gesicht verdeckt."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Reinige den oberen Teil deines Bildschirms, einschließlich der schwarzen Leiste"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Face Unlock wird auf diesem Gerät nicht unterstützt."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Der Sensor ist vorübergehend deaktiviert."</string>
<string name="face_name_template" msgid="3877037340223318119">"Gesicht <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Gesichtssymbol"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Verknüpfung verwenden"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Farbumkehr"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Farbkorrektur"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Helligkeit verringern"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Lautstärketasten wurden gedrückt gehalten. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ist aktiviert."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Lautstärketasten wurden gedrückt gehalten. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ist deaktiviert."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Halten Sie beide Lautstärketasten drei Sekunden lang gedrückt, um <xliff:g id="SERVICE_NAME">%1$s</xliff:g> zu verwenden"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Phishing-Warnung"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Arbeitsprofil"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Gewarnt"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Bestätigt"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Maximieren"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Minimieren"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"Maximierung ein-/auschalten"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Nachrichten & Zeitschriften"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Karten & Navigation"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Effizienz"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Gerätespeicher"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-Fehlerbehebung"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"Stunde"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Zum Fortfahren benötigt <b><xliff:g id="APP">%s</xliff:g></b> Zugriff auf die Kamera deines Geräts."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Aktivieren"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Datenschutz für Sensoren"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"App-Symbol"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"App-Branding-Hintergrundbild"</string>
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 22b3401..d9dc2c5 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Επιτρέπει στην εφαρμογή να τροποποιήσει τη συλλογή φωτογραφιών σας."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"ανάγνωση τοποθεσιών από τη συλλογή πολυμέσων σας"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Επιτρέπει στην εφαρμογή να διαβάσει τοποθεσίες από τη συλλογή πολυμέσων σας."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Επαλήθευση ταυτότητας"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Δεν υπάρχει διαθέσιμος βιομετρικός εξοπλισμός"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Ο έλεγχος ταυτότητας ακυρώθηκε"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Δεν αναγνωρίστηκε"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Ο έλεγχος ταυτότητας ακυρώθηκε"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Δεν έχει οριστεί PIN, μοτίβο ή κωδικός πρόσβασης"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Σφάλμα κατά τον έλεγχο ταυτότητας"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Εντοπίστηκε μόνο μέρος του δακτυλικού αποτυπώματος. Δοκιμάστε ξανά."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Δεν ήταν δυνατή η επεξεργασία του δακτυλικού αποτυπώματος. Δοκιμάστε ξανά."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Ο αισθητήρας δακτυλικού αποτυπώματος δεν είναι καθαρός. Καθαρίστε τον και δοκιμάστε ξανά."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Αυτή η συσκευή δεν διαθέτει αισθητήρα δακτυλικού αποτυπώματος."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Ο αισθητήρας απενεργοποιήθηκε προσωρινά."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Δάχτυλο <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Χρησιμοποιήστε το δακτυλικό αποτύπωμά σας για να συνεχίσετε"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Αδύνατη η αναγνώριση του προσώπου. Επανάληψη."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Πολύ παρόμοιο, αλλάξτε την πόζα σας."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Στρέψτε λιγότερο το κεφάλι σας."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Γείρετε λιγότερο το κεφάλι σας."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Στρέψτε λιγότερο το κεφάλι σας."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Απομακρύνετε οτιδήποτε κρύβει το πρόσωπό σας."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Καθαρίστε το επάνω μέρος της οθόνης σας, συμπεριλαμβανομένης της μαύρης γραμμής"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Το Face Unlock δεν υποστηρίζεται σε αυτήν τη συσκευή."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Ο αισθητήρας απενεργοποιήθηκε προσωρινά."</string>
<string name="face_name_template" msgid="3877037340223318119">"Πρόσωπο <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Εικ. προσ."</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Χρήση συντόμευσης"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Αντιστροφή χρωμάτων"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Διόρθωση χρωμάτων"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Μείωση φωτεινότητας"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Τα πλήκτρα έντασης είναι πατημένα. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ενεργοποιήθηκε."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Τα πλήκτρα έντασης είναι πατημένα. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>: απενεργοποιημένο"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Πατήστε παρατεταμένα και τα δύο κουμπιά έντασης ήχου για τρία δευτερόλεπτα, ώστε να χρησιμοποιήσετε την υπηρεσία <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Ειδοποίηση ηλεκτρονικού ψαρέματος (phishing)"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Προφίλ εργασίας"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Ειδοποιήθηκε"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Επαληθεύτηκε"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Ανάπτυξη"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Σύμπτυξη"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"εναλλαγή επέκτασης"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Ειδήσεις και περιοδικά"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Χάρτες και πλοήγηση"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Παραγωγικότητα"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Αποθηκευτικός χώρος συσκευής"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Εντοπισμός σφαλμάτων USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ώρα"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Για να συνεχίσετε, η εφαρμογή <b><xliff:g id="APP">%s</xliff:g></b> χρειάζεται πρόσβαση στην κάμερα της συσκευής σας."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Ενεργοποίηση"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Απόρρητο αισθητήρα"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Εικονίδιο εφαρμογής"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Εικόνα επωνυμίας εφαρμογής"</string>
</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index f2cbb75..73e2ca0 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Allows the app to modify your photo collection."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"read locations from your media collection"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Allows the app to read locations from your media collection."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verify that it’s you"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometric hardware unavailable"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentication cancelled"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Not recognised"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Authentication cancelled"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No pin, pattern or password set"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Error while authenticating"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Partial fingerprint detected. Please try again."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Couldn\'t process fingerprint. Please try again."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingerprint sensor is dirty. Please clean and try again."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Use your fingerprint to continue"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -624,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Face unlock is not supported on this device."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporarily disabled."</string>
<string name="face_name_template" msgid="3877037340223318119">"Face <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string>
@@ -1874,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Phishing alert"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Work profile"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Alerted"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Verified"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Expand"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Collapse"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"toggle expansion"</string>
@@ -1945,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"News & Magazines"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Maps & Navigation"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Productivity"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Device storage"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB debugging"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"hour"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index f440c8a..67130e1 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Allows the app to modify your photo collection."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"read locations from your media collection"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Allows the app to read locations from your media collection."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verify that it’s you"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometric hardware unavailable"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentication cancelled"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Not recognised"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Authentication cancelled"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No pin, pattern or password set"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Error while authenticating"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Partial fingerprint detected. Please try again."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Couldn\'t process fingerprint. Please try again."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingerprint sensor is dirty. Please clean and try again."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Use your fingerprint to continue"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -624,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Face unlock is not supported on this device."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporarily disabled."</string>
<string name="face_name_template" msgid="3877037340223318119">"Face <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string>
@@ -1874,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Phishing alert"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Work profile"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Alerted"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Verified"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Expand"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Collapse"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"toggle expansion"</string>
@@ -1945,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"News & Magazines"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Maps & Navigation"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Productivity"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Device storage"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB debugging"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"hour"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 93881e9..1d36494b 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Allows the app to modify your photo collection."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"read locations from your media collection"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Allows the app to read locations from your media collection."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verify that it’s you"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometric hardware unavailable"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentication cancelled"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Not recognised"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Authentication cancelled"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No pin, pattern or password set"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Error while authenticating"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Partial fingerprint detected. Please try again."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Couldn\'t process fingerprint. Please try again."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingerprint sensor is dirty. Please clean and try again."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Use your fingerprint to continue"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -624,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Face unlock is not supported on this device."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporarily disabled."</string>
<string name="face_name_template" msgid="3877037340223318119">"Face <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string>
@@ -1874,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Phishing alert"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Work profile"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Alerted"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Verified"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Expand"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Collapse"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"toggle expansion"</string>
@@ -1945,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"News & Magazines"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Maps & Navigation"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Productivity"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Device storage"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB debugging"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"hour"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index a7fa30e..016c55c 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Allows the app to modify your photo collection."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"read locations from your media collection"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Allows the app to read locations from your media collection."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verify that it’s you"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometric hardware unavailable"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentication cancelled"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Not recognised"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Authentication cancelled"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No pin, pattern or password set"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Error while authenticating"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Partial fingerprint detected. Please try again."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Couldn\'t process fingerprint. Please try again."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingerprint sensor is dirty. Please clean and try again."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Use your fingerprint to continue"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -624,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Face unlock is not supported on this device."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporarily disabled."</string>
<string name="face_name_template" msgid="3877037340223318119">"Face <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string>
@@ -1874,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Phishing alert"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Work profile"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Alerted"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Verified"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Expand"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Collapse"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"toggle expansion"</string>
@@ -1945,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"News & Magazines"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Maps & Navigation"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Productivity"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Device storage"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB debugging"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"hour"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index ce9a915..aef32a4d 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -550,13 +550,18 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Allows the app to modify your photo collection."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"read locations from your media collection"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Allows the app to read locations from your media collection."</string>
+ <string name="biometric_app_setting_name" msgid="3339209978734534457">"Use biometrics"</string>
+ <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Use biometrics or screen lock"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verify it’s you"</string>
+ <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Use your biometric to continue"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometric hardware unavailable"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentication canceled"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Not recognized"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Authentication canceled"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No pin, pattern, or password set"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Error authenticating"</string>
+ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Use screen lock"</string>
+ <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Enter your device credential to continue"</string>
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Partial fingerprint detected. Please try again."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Couldn\'t process fingerprint. Please try again."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingerprint sensor is dirty. Please clean and try again."</string>
@@ -579,6 +584,8 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Use fingerprint"</string>
+ <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Use fingerprint or screen lock"</string>
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Use your fingerprint to continue"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -624,6 +631,9 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Face unlock is not supported on this device."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporarily disabled."</string>
<string name="face_name_template" msgid="3877037340223318119">"Face <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string name="face_app_setting_name" msgid="8130135875458467243">"Use face unlock"</string>
+ <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Use face or screen lock"</string>
+ <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Use face unlock to continue"</string>
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string>
@@ -1874,6 +1884,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Phishing alert"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Work profile"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Alerted"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Verified"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Expand"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Collapse"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"toggle expansion"</string>
@@ -1945,6 +1956,7 @@
<string name="app_category_news" msgid="1172762719574964544">"News & Magazines"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Maps & Navigation"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Productivity"</string>
+ <string name="app_category_accessibility" msgid="6643521607848547683">"Accessibility"</string>
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Device storage"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB debugging"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"hour"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 01d0c7e..bd7da80 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -333,8 +333,8 @@
<string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Controla el posicionamiento y el nivel de zoom de la pantalla."</string>
<string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Usar gestos"</string>
<string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Permite presionar, deslizar, pellizcar y usar otros gestos."</string>
- <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gestos del sensor de huellas digitales"</string>
- <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Captura los gestos que se hacen en el sensor de huellas digitales del dispositivo."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gestos del sensor de huellas dactilares"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Captura los gestos que se hacen en el sensor de huellas dactilares del dispositivo."</string>
<string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Tomar captura de pantalla"</string>
<string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Puede tomar una captura de la pantalla."</string>
<string name="permlab_statusBar" msgid="8798267849526214017">"desactivar o modificar la barra de estado"</string>
@@ -525,9 +525,9 @@
<string name="permdesc_changeWimaxState" product="tv" msgid="5373274458799425276">"Permite que la app conecte el dispositivo Android TV a redes WiMAX y que lo desconecte de ellas."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="1551666203780202101">"Permite que la aplicación conecte el dispositivo a una red WiMAX y que lo desconecte de ella."</string>
<string name="permlab_bluetooth" msgid="586333280736937209">"vincular con dispositivos Bluetooth"</string>
- <string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"Permite que la aplicación vea la configuración de Bluetooth de la tablet y que cree y acepte conexiones con los dispositivos sincronizados."</string>
- <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"Permite que la app vea la configuración de Bluetooth del dispositivo Android TV, así como que cree y acepte conexiones con los dispositivos sincronizados."</string>
- <string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"Permite que la aplicación vea la configuración de Bluetooth del dispositivo y que cree y acepte conexiones con los dispositivos sincronizados."</string>
+ <string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"Permite que la aplicación vea la configuración de Bluetooth de la tablet y que cree y acepte conexiones con los dispositivos vinculados."</string>
+ <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"Permite que la app vea la configuración de Bluetooth del dispositivo Android TV, así como que cree y acepte conexiones con los dispositivos vinculados."</string>
+ <string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"Permite que la aplicación vea la configuración de Bluetooth del dispositivo y que cree y acepte conexiones con los dispositivos vinculados."</string>
<string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Información sobre servicio de pago NFC preferido"</string>
<string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Permite que la app reciba información del servicio de pago NFC preferido, como el servicio de asistencia registrado y el destino de la ruta."</string>
<string name="permlab_nfc" msgid="1904455246837674977">"controlar la Transmisión de datos en proximidad"</string>
@@ -538,10 +538,10 @@
<string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"Permite que la app conozca el nivel de complejidad del bloqueo de pantalla (alta, media, baja o ninguna), lo que indica el rango de duración posible y el tipo de bloqueo. La app también puede sugerirles a los usuarios que actualicen el bloqueo de pantalla a un determinado nivel, aunque ellos pueden ignorar esta sugerencia y seguir navegando. Ten en cuenta que el bloqueo de pantalla no se almacena como texto sin formato, por lo que la app no conoce la contraseña exacta."</string>
<string name="permlab_useBiometric" msgid="6314741124749633786">"usar hardware biométrico"</string>
<string name="permdesc_useBiometric" msgid="7502858732677143410">"Permite que la app use hardware biométrico para realizar la autenticación"</string>
- <string name="permlab_manageFingerprint" msgid="7432667156322821178">"Administrar el hardware de huellas digitales"</string>
- <string name="permdesc_manageFingerprint" msgid="2025616816437339865">"Permite que la aplicación emplee métodos para agregar y eliminar plantillas de huellas digitales para su uso."</string>
- <string name="permlab_useFingerprint" msgid="1001421069766751922">"Utilizar hardware de huellas digitales"</string>
- <string name="permdesc_useFingerprint" msgid="412463055059323742">"Permite que la aplicación utilice el hardware de huellas digitales para realizar la autenticación."</string>
+ <string name="permlab_manageFingerprint" msgid="7432667156322821178">"Administrar el hardware de huellas dactilares"</string>
+ <string name="permdesc_manageFingerprint" msgid="2025616816437339865">"Permite que la aplicación emplee métodos para agregar y eliminar plantillas de huellas dactilares para su uso."</string>
+ <string name="permlab_useFingerprint" msgid="1001421069766751922">"Utilizar hardware de huellas dactilares"</string>
+ <string name="permdesc_useFingerprint" msgid="412463055059323742">"Permite que la aplicación utilice el hardware de huellas dactilares para realizar la autenticación."</string>
<string name="permlab_audioWrite" msgid="8501705294265669405">"modificar tu colección de música"</string>
<string name="permdesc_audioWrite" msgid="8057399517013412431">"Permite que la app modifique tu colección de música."</string>
<string name="permlab_videoWrite" msgid="5940738769586451318">"modificar tu colección de videos"</string>
@@ -550,39 +550,53 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que la app modifique tu colección de fotos."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"leer ubicaciones de tu colección de contenido multimedia"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que la app lea las ubicaciones de tu colección de contenido multimedia."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Comprueba que eres tú"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"No hay hardware biométrico disponible"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Se canceló la autenticación"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"No se reconoció"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Se canceló la autenticación"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No se estableció ningún PIN, patrón ni contraseña"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Error de autenticación"</string>
- <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Se detectó parcialmente la huella digital. Vuelve a intentarlo."</string>
- <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"No se pudo procesar la huella digital. Vuelve a intentarlo."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"El sensor de huellas digitales está sucio. Limpia el sensor y vuelve a intentarlo."</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
+ <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Se detectó parcialmente la huella dactilar. Vuelve a intentarlo."</string>
+ <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"No se pudo procesar la huella dactilar. Vuelve a intentarlo."</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"El sensor de huellas dactilares está sucio. Limpia el sensor y vuelve a intentarlo."</string>
<string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"Moviste el dedo muy rápido. Vuelve a intentarlo."</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Moviste el dedo muy lento. Vuelve a intentarlo."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_authenticated" msgid="2024862866860283100">"Se autenticó la huella digital"</string>
+ <string name="fingerprint_authenticated" msgid="2024862866860283100">"Se autenticó la huella dactilar"</string>
<string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Se autenticó el rostro"</string>
<string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Se autenticó el rostro; presiona Confirmar"</string>
- <string name="fingerprint_error_hw_not_available" msgid="4571700896929561202">"El hardware para detectar huellas digitales no está disponible."</string>
- <string name="fingerprint_error_no_space" msgid="6126456006769817485">"No se puede almacenar la huella digital. Elimina una de las existentes."</string>
- <string name="fingerprint_error_timeout" msgid="2946635815726054226">"Finalizó el tiempo de espera para la huella digital. Vuelve a intentarlo."</string>
- <string name="fingerprint_error_canceled" msgid="540026881380070750">"Se canceló la operación de huella digital."</string>
- <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"El usuario canceló la operación de huella digital."</string>
+ <string name="fingerprint_error_hw_not_available" msgid="4571700896929561202">"El hardware para detectar huellas dactilares no está disponible."</string>
+ <string name="fingerprint_error_no_space" msgid="6126456006769817485">"No se puede almacenar la huella dactilar. Elimina una de las existentes."</string>
+ <string name="fingerprint_error_timeout" msgid="2946635815726054226">"Finalizó el tiempo de espera para la huella dactilar. Vuelve a intentarlo."</string>
+ <string name="fingerprint_error_canceled" msgid="540026881380070750">"Se canceló la operación de huella dactilar."</string>
+ <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"El usuario canceló la operación de huella dactilar."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Demasiados intentos. Vuelve a intentarlo más tarde."</string>
- <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Realizaste demasiados intentos. Se inhabilitó el sensor de huellas digitales."</string>
+ <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Realizaste demasiados intentos. Se inhabilitó el sensor de huellas dactilares."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Vuelve a intentarlo."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No se registraron huellas digitales."</string>
- <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo no tiene sensor de huellas digitales."</string>
+ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo no tiene sensor de huellas dactilares."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Se inhabilitó temporalmente el sensor."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
- <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utiliza tu huella digital para continuar"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
+ <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utiliza tu huella dactilar para continuar"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
- <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícono de huella digital"</string>
+ <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícono de huella dactilar"</string>
<string name="permlab_manageFace" msgid="4569549381889283282">"administrar el hardware de desbloqueo facial"</string>
<string name="permdesc_manageFace" msgid="6204569688492710471">"Permite que la app emplee métodos para agregar y borrar plantillas de rostros para su uso."</string>
<string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"usar el hardware de desbloqueo facial"</string>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Ya no se reconoce el rostro. Vuelve a intentarlo."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Es muy similar a la anterior. Haz otra pose."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Gira la cabeza un poco menos."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Inclina un poco menos la cabeza."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Gira la cabeza un poco menos."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Quítate cualquier objeto que te cubra el rostro."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpia la parte superior de la pantalla, incluida la barra negra"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"No se admite el desbloqueo facial en este dispositivo."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Se inhabilitó temporalmente el sensor."</string>
<string name="face_name_template" msgid="3877037340223318119">"Rostro <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Ícono cara"</string>
@@ -1557,8 +1576,8 @@
<string name="expires_on" msgid="1623640879705103121">"Expira el:"</string>
<string name="serial_number" msgid="3479576915806623429">"Número de serie:"</string>
<string name="fingerprints" msgid="148690767172613723">"Huellas digitales:"</string>
- <string name="sha256_fingerprint" msgid="7103976380961964600">"Huella digital SHA-256"</string>
- <string name="sha1_fingerprint" msgid="2339915142825390774">"Huella digital SHA-1:"</string>
+ <string name="sha256_fingerprint" msgid="7103976380961964600">"Huella dactilar SHA-256"</string>
+ <string name="sha1_fingerprint" msgid="2339915142825390774">"Huella dactilar SHA-1:"</string>
<string name="activity_chooser_view_see_all" msgid="3917045206812726099">"Ver todas"</string>
<string name="activity_chooser_view_dialog_title_default" msgid="8880731437191978314">"Elige actividad"</string>
<string name="share_action_provider_share_with" msgid="1904096863622941880">"Compartir con"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Usar acceso directo"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversión de color"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Corrección de color"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Reducir el brillo"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Como mantuviste presionadas las teclas de volumen, se activó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Se presionaron las teclas de volumen. Se desactivó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Mantén presionadas ambas teclas de volumen durante tres segundos para usar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerta de suplantación de identidad (phishing)"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de trabajo"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Alerta enviada"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Verificado"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Expandir"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Contraer"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"activar o desactivar la expansión"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Noticias y revistas"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Mapas y navegación"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Productividad"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Almacenamiento del dispositivo"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Depuración por USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"hora"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Para continuar, <b><xliff:g id="APP">%s</xliff:g></b&gt necesita acceso a la cámara del dispositivo."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Activar"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacidad del sensor"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Ícono de la aplicación"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imagen de marca de la aplicación"</string>
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 28ff5fb..d771977 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que la aplicación modifique tu colección de fotos."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"leer las ubicaciones de tu colección de contenido multimedia"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que la aplicación lea las ubicaciones de tu colección de contenido multimedia."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica que eres tú"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biométrico no disponible"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticación cancelada"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"No se reconoce"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autenticación cancelada"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No se ha definido el PIN, el patrón o la contraseña"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"No se ha podido autenticar"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Se ha detectado una huella digital parcial. Vuelve a intentarlo."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"No se ha podido procesar la huella digital. Vuelve a intentarlo."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"El sensor de huellas digitales está sucio. Límpialo y vuelve a intentarlo."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo no tiene sensor de huellas digitales."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"El sensor está inhabilitado en estos momentos."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Usa tu huella digital para continuar"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"No puede reconocer tu cara. Vuelve a intentarlo."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Se parece mucha a la anterior. Pon otra cara."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Gira la cabeza un poco menos."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"No inclines tanto la cabeza."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"No gires tanto la cabeza."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Retira cualquier objeto que te tape la cara."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpia la parte superior de la pantalla, incluida la barra de color negro"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"El desbloqueo facial no está disponible en este dispositivo."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"El sensor está inhabilitado en estos momentos."</string>
<string name="face_name_template" msgid="3877037340223318119">"Cara <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Icono cara"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilizar acceso directo"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversión de color"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Corrección de color"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Reducir brillo"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Al mantener pulsadas las teclas de volumen, se ha activado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Se han mantenido pulsadas las teclas de volumen. Se ha desactivado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Para utilizar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, mantén pulsadas ambas teclas de volumen durante 3 segundos"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerta de phishing"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de trabajo"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Con sonido"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Verificado"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Mostrar"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Ocultar"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"alternar mostrar y ocultar"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Noticias y revistas"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Mapas y navegación"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Productividad"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Almacenamiento del dispositivo"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Depuración por USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"hora"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Para continuar, <b><xliff:g id="APP">%s</xliff:g></b> necesita tener acceso a la cámara del dispositivo."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Activar"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacidad del sensor"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Icono de aplicación"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imagen de marca de aplicación"</string>
</resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index cb2bcdc..ec02fad 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Võimaldab rakendusel muuta teie fotokogu."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"Lugeda teie meediakogus olevaid asukohti"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Võimaldab rakendusel lugeda teie meediakogus olevaid asukohti."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Kinnitage oma isik"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biomeetriline riistvara ei ole saadaval"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentimine tühistati"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Ei tuvastatud"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentimine tühistati"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN-koodi, mustrit ega parooli pole määratud"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Viga autentimisel"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Tuvastati osaline sõrmejälg. Proovige uuesti."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Sõrmejälge ei õnnestunud töödelda. Proovige uuesti."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Sõrmejäljeandur on must. Puhastage see ja proovige uuesti."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Selles seadmes pole sõrmejäljeandurit."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Andur on ajutiselt keelatud."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Sõrmejälg <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Jätkamiseks kasutage sõrmejälge"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Nägu ei õnnestu enam tuvastada. Proovige uuesti."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Liiga sarnane, palun muutke oma asendit."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Pöörake oma pead veidi vähem."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Kallutage oma pead pisut vähem."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Pöörake oma pead veidi vähem."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Eemaldage kõik, mis varjab teie nägu."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Puhastage ekraani ülaosa, sh musta värvi riba"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Seade ei toeta Face Unlocki."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Andur on ajutiselt keelatud."</string>
<string name="face_name_template" msgid="3877037340223318119">"Nägu <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Näoikoon"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Kasuta otseteed"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Värvide ümberpööramine"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Värvide korrigeerimine"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Ereduse vähendamine"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Helitugevuse klahve hoiti all. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> lülitati sisse."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Helitugevuse klahve hoiti all. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> lülitati välja."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kasutamiseks hoidke kolm sekundit all mõlemat helitugevuse klahvi"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Andmepüügihoiatus"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Tööprofiil"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Teavitatud"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Kinnitatud"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Laienda"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Ahenda"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"vaheta laiendamist"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Uudised ja ajakirjad"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Kaardid ja navigeerimine"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produktiivsus"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Seadme salvestusruum"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB silumine"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"tund"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Jätkamiseks vajab rakendus <b><xliff:g id="APP">%s</xliff:g></b> juurdepääsu teie seadme kaamerale."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Lülita sisse"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Anduri privaatsus"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Rakenduse ikoon"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Rakenduse brändi kujutis"</string>
</resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index f95c279..8ee77a6 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Argazki-bilduma aldatzeko baimena ematen die aplikazioei."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"multimedia-edukien bildumako kokapena irakurri"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Multimedia-edukien bildumako kokapena irakurtzeko baimena ematen die aplikazioei."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Egiaztatu zeu zarela"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biometrikoa ez dago erabilgarri"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Utzi da autentifikazioa"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Ez da ezagutu"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Utzi egin da autentifikazioa"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Ez da ezarri PIN koderik, eredurik edo pasahitzik"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Errorea autentifikatzean"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Hatz-marka ez da osorik hauteman. Saiatu berriro."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Ezin izan da prozesatu hatz-marka. Saiatu berriro."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Hatz-marken sentsorea zikina dago. Garbi ezazu, eta saiatu berriro."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Gailu honek ez du hatz-marken sentsorerik."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sentsorea aldi baterako desgaitu da."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> hatza"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Aurrera egiteko, erabili hatz-marka"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Ez dugu ezagutzen aurpegi hori. Saiatu berriro."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Jarrera berdintsuegia da. Alda ezazu."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Biratu burua pixka bat gutxiago."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Makurtu burua pixka bat gutxiago."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Biratu burua pixka bat gutxiago."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Kendu aurpegia estaltzen dizuten gauzak."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Garbitu pantailaren goialdea, barra beltza barne"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Gailu honek ez du onartzen aurpegiaren bidez desblokeatzea."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sentsorea aldi baterako desgaitu da."</string>
<string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> aurpegia"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Aurpegiaren ikonoa"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Erabili lasterbidea"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Koloreen alderantzikatzea"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Koloreen zuzenketa"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Murriztu distira"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Bolumen-botoiak sakatuta eduki direnez, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktibatu egin da."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Bolumen-botoiak sakatuta eduki direnez, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desaktibatu egin da."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> erabiltzeko, eduki sakatuta bi bolumen-botoiak hiru segundoz"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Phishing-alerta"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Work profila"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Egin du soinua"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Egiaztatuta"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Zabaldu"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Tolestu"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"zabaldu edo tolestu"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Albisteak eta aldizkariak"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Mapak eta nabigazioa"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produktibitatea"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Gailuaren memoria"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB bidezko arazketa"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ordu"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Aurrera egiteko, gailuaren kamera atzitzeko baimena behar du <b><xliff:g id="APP">%s</xliff:g></b> aplikazioak."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Aktibatu"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sentsoreen pribatutasuna"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Aplikazioaren ikonoa"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Aplikazioaren marka-irudia"</string>
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 714b5e4..42b8c85 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"به برنامه اجازه میدهد مجموعه عکستان را تغییر دهد."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"خواندن مکانها از مجموعه رسانه شما"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"به برنامه اجازه میدهد مکانها را از مجموعه رسانهتان بخواند."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"تأیید کنید این شما هستید"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"سختافزار زیستسنجی دردسترس نیست"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"اصالتسنجی لغو شد"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"شناسایی نشد"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"اصالتسنجی لغو شد"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"پین، الگو یا گذرواژهای تنظیم نشده است"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"خطا هنگام اصالتسنجی"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"بخشی از اثر انگشت شناسایی شد. لطفاً دوباره امتحان کنید."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"اثرانگشت پردازش نشد. لطفاً دوباره امتحان کنید."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"حسگر اثر انگشت کثیف است. لطفاً آن را تمیز کنید و دوباره امتحان نمایید."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"این دستگاه حسگر اثر انگشت ندارد."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"حسگر بهطور موقت غیرفعال است."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"انگشت <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"برای ادامه، از اثر انگشتتان استفاده کنید"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"دیگر چهره را تشخیص نمیدهد. دوباره امتحان کنید."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"بسیار شبیه قبلی است، لطفاً قیافه دیگری بگیرید."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"سرتان را کمی صاف بگیرید."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"سرتان را کمی کج بگیرید."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"سرتان را کمی صاف بگیرید."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"هرچیزی را که حائل چهرهتان است بردارید."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"بالای صفحه و همچنین نوار مشکی را تمیز کنید."</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"«بازگشایی با چهره» در این دستگاه پشتیبانی نمیشود."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"حسگر بهطور موقت غیرفعال است."</string>
<string name="face_name_template" msgid="3877037340223318119">"چهره <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"نماد چهره"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"استفاده از میانبر"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"وارونگی رنگ"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"تصحیح رنگ"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"کاهش روشنایی"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"کلیدهای میزان صدا پایین نگه داشته شد. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> روشن شد."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"کلیدهای میزان صدا پایین نگه داشته شد. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> خاموش شد."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"برای استفاده از <xliff:g id="SERVICE_NAME">%1$s</xliff:g>، هر دو کلید صدا را فشار دهید و سه ثانیه نگه دارید"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"هشدار رمزگیری"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"نمایه کاری"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"هشدار ارسال شد"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"تأییدشده"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"بزرگ کردن"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"کوچک کردن"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"روشن/خاموش کردن بزرگنمایی"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"اخبار و مجله"</string>
<string name="app_category_maps" msgid="6395725487922533156">"نقشه و پیمایش"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"بهرهوری"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"فضای ذخیرهسازی دستگاه"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"اشکالزدایی USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ساعت"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"برای ادامه دادن، <b><xliff:g id="APP">%s</xliff:g></b> باید به دوربین دستگاه دسترسی داشته باشد."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"روشن کردن"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"حریمخصوصی حسگر"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"نماد برنامه"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"تصویر نمانامسازی برنامه"</string>
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index ef872e9..be0cd23 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Antaa sovelluksen muokata kuvakokoelmaasi."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"lukea mediakokoelmasi sijainteja"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Antaa sovelluksen lukea mediakokoelmasi sijainteja."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Vahvista henkilöllisyytesi"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrinen laitteisto ei käytettävissä"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Todennus peruutettu"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Ei tunnistettu"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Todennus peruutettu"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN-koodia, kuviota tai salasanaa ei ole asetettu"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Virhe todennuksessa"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Sormenjälki havaittiin vain osittain. Yritä uudelleen."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Sormenjäljen prosessointi epäonnistui. Yritä uudelleen."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Sormenjälkitunnistin on likainen. Puhdista tunnistin ja yritä uudelleen."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Laitteessa ei ole sormenjälkitunnistinta."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Tunnistin poistettu väliaikaisesti käytöstä."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Sormi <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Jatka sormenjäljen avulla"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Ei enää tunnista kasvoja. Yritä uudelleen."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Liian samanlainen, vaihda asentoa."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Käännä päätä vähän vähemmän."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Kallista päätäsi vähän vähemmän."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Käännä päätä vähän vähemmän."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Poista esteet kasvojesi edestä."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Puhdista näytön yläreuna, mukaan lukien musta palkki"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Tämä laite ei tue Face Unlockia."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Tunnistin poistettu väliaikaisesti käytöstä."</string>
<string name="face_name_template" msgid="3877037340223318119">"Kasvot <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Kasvokuvake"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Käytä pikanäppäintä"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Käänteiset värit"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Värinkorjaus"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Vähennä kirkkautta"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Äänenvoimakkuuspainikkeita painettiin pitkään. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> laitettiin päälle."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Äänenvoimakkuuspainikkeita painettiin pitkään. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> laitettiin pois päältä."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Voit käyttää palvelua <xliff:g id="SERVICE_NAME">%1$s</xliff:g> painamalla molempia äänenvoimakkuuspainikkeita kolmen sekunnin ajan"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Varoitus tietojenkalastelusta"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Työprofiili"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Hälytti"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Vahvistettu"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Laajenna"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Tiivistä"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"Laajenna/tiivistä painikkeella"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Uutiset ja lehdet"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Kartat ja navigointi"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Tuottavuus"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Laitteen tallennustila"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-vianetsintä"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"tunnit"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Jotta voit jatkaa, <b><xliff:g id="APP">%s</xliff:g></b> tarvitsee pääsyn laitteesi kameraan."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Laita päälle"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Anturin tietosuoja"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Sovelluskuvake"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Sovelluksen tuotemerkkikuva"</string>
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 7cc3160..5c26e68 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Autorise l\'application à modifier votre collection de photos."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"lire les positions issues de votre collection multimédia"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Autorise l\'application à lire les positions indiquées dans votre collection multimédia."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirmez que c\'est vous"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Matériel biométrique indisponible"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentification annulée"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Données biométriques non reconnues"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Authentification annulée"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Aucun NIP, schéma ou mot de passe défini"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Erreur d\'authentification"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Empreinte digitale partielle détectée. Veuillez réessayer."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Impossible de reconnaître l\'empreinte digitale. Veuillez réessayer."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Le capteur d\'empreintes digitales est sale. Veuillez le nettoyer et réessayer."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Cet appareil ne possède pas de capteur d\'empreintes digitales."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Le capteur a été désactivé temporairement."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Doigt <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utilisez votre empreinte digitale pour continuer"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Ce visage ne sera plus reconnu. Réessayez."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Trop similaire. Changez de pose."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Tournez un peu moins votre tête."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Inclinez un peu moins votre tête."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Tournez un peu moins votre tête."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Retirez tout ce qui pourrait couvrir votre visage."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Nettoyez le haut de l\'écran, y compris la barre noire"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Cet appar. ne prend pas en charge le déverr. par reconn. faciale."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Le capteur a été désactivé temporairement."</string>
<string name="face_name_template" msgid="3877037340223318119">"Visage <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Icône visage"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utiliser le raccourci"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversion des couleurs"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Correction des couleurs"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Réduire la luminosité"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Touches de volume maintenues enfoncées. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> activé."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Touches de volume maintenues enfoncées. Service <xliff:g id="SERVICE_NAME">%1$s</xliff:g> désactivé."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Maintenez enfoncées les deux touches de volume pendant trois secondes pour utiliser <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerte d\'hameçonnage"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profil professionnel"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Alerté"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Vérifié"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Développer"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Réduire"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"activer/désactiver le développement"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Actualités et magazines"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Cartes et navigation"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Productivité"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Mémoire de l\'appareil"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Débogage USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"heures"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Pour continuer, vous devez accorder l\'accès à l\'appareil photo de votre appareil à l\'application <b><xliff:g id="APP">%s</xliff:g></b>."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Activer"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Confidentialité des capteurs"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Icône de l\'application"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Image de marque de l\'application"</string>
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index a3c0bad..3d8856d 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Autorise l\'application à modifier votre bibliothèque photo."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"consulter des positions issues de votre bibliothèque multimédia"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Autorise l\'application à consulter des positions issues de votre bibliothèque multimédia."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirmez votre identité"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Matériel biométrique indisponible"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Authentification annulée"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Non reconnu"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Authentification annulée"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Aucun code, schéma ni mot de passe n\'est défini"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Erreur d\'authentification"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Empreinte digitale partiellement détectée. Veuillez réessayer."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Impossible de reconnaître l\'empreinte digitale. Veuillez réessayer."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Le lecteur d\'empreinte digitale est sale. Veuillez le nettoyer, puis réessayer."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Aucun lecteur d\'empreinte digitale n\'est installé sur cet appareil."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Capteur temporairement désactivé."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Doigt <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utilisez votre empreinte digitale pour continuer"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Impossible de reconnaître le visage. Réessayez."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Ressemble à un visage existant, changez de pose."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Tournez un peu moins la tête."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Penchez un peu moins la tête."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Tournez un peu moins la tête."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Retirez tout ce qui cache votre visage."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Nettoyez la partie supérieure de l\'écran, y compris la barre noire"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Face Unlock n\'est pas compatible avec cet appareil."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Capteur temporairement désactivé."</string>
<string name="face_name_template" msgid="3877037340223318119">"Visage <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Icône visage"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utiliser le raccourci"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversion des couleurs"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Correction des couleurs"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Réduire la luminosité"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Touches de volume appuyées de manière prolongée. Service <xliff:g id="SERVICE_NAME">%1$s</xliff:g> activé."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Touches de volume appuyées de manière prolongée. Service <xliff:g id="SERVICE_NAME">%1$s</xliff:g> désactivé."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Appuyez de manière prolongée sur les deux touches de volume pendant trois secondes pour utiliser <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerte de hameçonnage"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profil professionnel"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Alerte envoyée"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Validé"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Développer"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Réduire"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"activer/désactiver le développement"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Actualités et magazines"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Plans et navigation"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Productivité"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Mémoire de l\'appareil"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Débogage USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"heures"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Pour continuer, <b><xliff:g id="APP">%s</xliff:g></b> a besoin d\'accéder à l\'appareil photo de votre appareil."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Activer"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Confidentialité du capteur"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Icône de l\'application"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Image de branding de l\'application"</string>
</resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 72a799e..1c5ab13 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que a aplicación modifique a túa colección de fotos."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"ler localizacións da túa colección multimedia"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que a aplicación lea as localizacións da túa colección multimedia."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica que es ti"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"O hardware biométrico non está dispoñible"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Cancelouse a autenticación"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Non se recoñeceu"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Cancelouse a autenticación"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Non se estableceu ningún PIN, padrón ou contrasinal"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Produciuse un erro ao realizar a autenticación"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Detectouse unha impresión dixital parcial. Téntao de novo."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Non se puido procesar a impresión dixital. Téntao de novo."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"O sensor de impresión dixital está sucio. Límpao e téntao de novo."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo non ten sensor de impresión dixital."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Desactivouse o sensor temporalmente."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utiliza a túa impresión dixital para continuar"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Xa non se pode recoñecer a cara. Téntao de novo."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"É moi similar. Cambia a pose."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Xira a cabeza un pouco menos."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Inclina a cabeza un pouco menos."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Xira a cabeza un pouco menos."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Quita todo o que oculte a túa cara."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpa a parte superior da pantalla, incluída a barra de cor negra"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Este dispositivo non admite o desbloqueo facial."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Desactivouse o sensor temporalmente."</string>
<string name="face_name_template" msgid="3877037340223318119">"Cara <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Icona cara"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilizar atallo"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversión de cor"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Corrección de cor"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Reducir brillo"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume premidas. Activouse o servizo <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume premidas. Desactivouse <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Mantén premidas as teclas do volume durante tres segudos para usar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerta de phishing"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de traballo"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Con son"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Verificada"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Despregar"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Contraer"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"alterna a expansión"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Noticias e revistas"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Mapas e navegación"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produtividade"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Almacenamento do dispositivo"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Depuración por USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"hora"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Para continuar, <b><xliff:g id="APP">%s</xliff:g></b> precisa acceder á cámara do dispositivo."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Activar"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacidade do sensor"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Icona de aplicación"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imaxe de marca da aplicación"</string>
</resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 7a2527f..fd3a06b 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"એપને તમારો ફોટો સંગ્રહ સંશોધિત કરવાની મંજૂરી આપે છે."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"આપના મીડિયા સંગ્રહમાંથી સ્થાનો વાંચવા"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"એપને તમારા મીડિયા સંગ્રહમાંથી સ્થાનો વાંચવાની મંજૂરી આપે છે."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"તે તમે જ છો એ ચકાસો"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"બાયોમેટ્રિક હાર્ડવેર ઉપલબ્ધ નથી"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"પ્રમાણીકરણ રદ કર્યું"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"ઓળખાયેલ નથી"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"પ્રમાણીકરણ રદ કર્યું"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"કોઈ પિન, પૅટર્ન અથવા પાસવર્ડ સેટ કરેલો નથી"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"પ્રમાણિત કરવામાં ભૂલ આવી"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"આંશિક ફિંગરપ્રિન્ટ મળી. કૃપા કરીને ફરી પ્રયાસ કરો."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ફિંગરપ્રિન્ટ પ્રક્રિયા કરી શકાઈ નથી. કૃપા કરીને ફરી પ્રયાસ કરો."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"ફિંગરપ્રિન્ટ સેન્સર ગંદું છે. કૃપા કરીને સાફ કરો અને ફરી પ્રયાસ કરો."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"આ ડિવાઇસમાં કોઈ ફિંગરપ્રિન્ટ સેન્સર નથી."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"સેન્સર હંગામી રૂપે બંધ કર્યું છે."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"આંગળી <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ચાલુ રાખવા માટે તમારી ફિંગરપ્રિન્ટનો ઉપયોગ કરો"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"ચહેરો ઓળખી શકાતો નથી. ફરી પ્રયાસ કરો."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"ઘણી સમાનતા ધરાવે છે, કૃપા કરીને તમારો પોઝ બદલો."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"તમારું માથું થોડું ફેરવો."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"તમારું માથું થોડું ઓછું ટિલ્ટ કરો."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"તમારું માથું થોડું ઓછું ફેરવો."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"તમારા ચહેરાને છુપાવતી કંઈપણ વસ્તુ દૂર કરો."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"કાળી પટ્ટી સહિત, તમારી સ્ક્રીનની ટોચ સાફ કરો"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"આ ડિવાઇસ પર ફેસ અનલૉક કરવાની સુવિધા નથી."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"સેન્સર હંગામી રૂપે બંધ કર્યું છે."</string>
<string name="face_name_template" msgid="3877037340223318119">"ચહેરાનું <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"ચહેરા આઇકન"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"શૉર્ટકટનો ઉપયોગ કરો"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"વિપરીત રંગમાં બદલવું"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"રંગ સુધારણા"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"બ્રાઇટનેસ ઘટાડો"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"વૉલ્યૂમ કી દબાવી રાખો. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ચાલુ કરી."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"વૉલ્યૂમ કી દબાવી રાખો. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> બંધ કરી."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>નો ઉપયોગ કરવા માટે બન્ને વૉલ્યૂમ કીને ત્રણ સેકન્ડ સુધી દબાવી રાખો"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ફિશિંગ અલર્ટ"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"ઑફિસની પ્રોફાઇલ"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"અલર્ટ કરેલ"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"ચકાસેલું"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"વિસ્તૃત કરો"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"સંકુચિત કરો"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"વિસ્તરણ ટૉગલ કરો"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"સમાચાર અને સામાયિકો"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Maps અને નેવિગેશન"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"ઉત્પાદકતા"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ડિવાઇસ સ્ટૉરેજ"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB ડિબગિંગ"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"કલાક"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ચાલુ રાખવા માટે, <b><xliff:g id="APP">%s</xliff:g></b>ને તમારા ડિવાઇસના કૅમેરાના ઍક્સેસની જરૂર છે."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ચાલુ કરો"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"સેન્સર પ્રાઇવસી સંબંધિત નોટિફિકેશન"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"ઍપ્લિકેશનનું આઇકન"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ઍપ્લિકેશનની બ્રાંડિંગ છબી"</string>
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index f108aa7..be64e90 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"इससे ऐप्लिकेशन को आपके फ़ोटो संग्रह में बदलाव करने की मंज़ूरी दी जाती है."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"अपने मीडिया संग्रह से जगह की जानकारी ऐक्सेस करने की अनुमति दें"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"इससे ऐप्लिकेशन को आपके मीडिया संग्रह से जगह की जानकारी ऐक्सेस करने की अनुमति दी जाती है."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"अपनी पहचान की पुष्टि करें"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"बायोमेट्रिक हार्डवेयर उपलब्ध नहीं है"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"प्रमाणीकरण रद्द किया गया"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"पहचान नहीं हो पाई"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"प्रमाणीकरण रद्द किया गया"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"पिन, पैटर्न या पासवर्ड सेट नहीं है"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"गड़बड़ी की पुष्टि की जा रही है"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"अधूरा फ़िंगरप्रिंट प्रोसेस हो सका. कृपया फिर से कोशिश करें."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"फ़िंगरप्रिंट प्रोसेस नहीं हो सका. कृपया दोबारा कोशिश करें."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"फ़िंगरप्रिंट सेंसर गंदा है. कृपया साफ़ करें और फिर कोशिश करें."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"इस डिवाइस में फ़िंगरप्रिंट सेंसर नहीं है."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"सेंसर कुछ समय के लिए बंद कर दिया गया है."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"फ़िंगरप्रिंट <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"जारी रखने के लिए फ़िंगरप्रिंट का इस्तेमाल करें"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"अब चेहरे की पहचान नहीं कर पा रहा. फिर से कोशिश करें."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"चेहरा काफ़ी मिलता-जुलता है, कृपया अपना पोज़ बदलें."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"अपना सिर थोड़ा कम घुमाएं."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"अपने सिर को थोड़ा कम झुकाएं."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"अपना सिर थोड़ा कम घुमाएं."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"आपके चेहरे को छिपाने वाली सभी चीज़ों को हटाएं."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"अपनी स्क्रीन के सबसे ऊपरी हिस्से को साफ़ करें, जिसमें काले रंग वाला बार भी शामिल है"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"इस डिवाइस पर \'मालिक का चेहरा पहचानकर अनलॉक\' काम नहीं करती है."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"सेंसर कुछ समय के लिए बंद कर दिया गया है."</string>
<string name="face_name_template" msgid="3877037340223318119">"चेहरा <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"चेहरे का आइकॉन"</string>
@@ -1347,7 +1366,7 @@
<string name="share_remote_bugreport_notification_message_finished" msgid="7325635795739260135">"आपके एडमिन ने इस डिवाइस की समस्या को हल करने में सहायता के लिए एक गड़बड़ी की रिपोर्ट का अनुरोध किया है. ऐप्लिकेशन और डेटा शेयर किए जा सकते हैं."</string>
<string name="share_remote_bugreport_action" msgid="7630880678785123682">"शेयर करें"</string>
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"अस्वीकार करें"</string>
- <string name="select_input_method" msgid="3971267998568587025">"इनपुट पद्धति चुनें"</string>
+ <string name="select_input_method" msgid="3971267998568587025">"इनपुट का तरीका चुनें"</string>
<string name="show_ime" msgid="6406112007347443383">"सामान्य कीबोर्ड के सक्रिय होने के दौरान इसे स्क्रीन पर बनाए रखें"</string>
<string name="hardware" msgid="1800597768237606953">"वर्चुअल कीबोर्ड दिखाएं"</string>
<string name="select_keyboard_layout_notification_title" msgid="4427643867639774118">"सामान्य कीबोर्ड कॉन्फ़िगर करें"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"शॉर्टकट का उपयोग करें"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"रंग बदलने की सुविधा"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"रंग में सुधार करने की सुविधा"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"स्क्रीन की चमक कम करें"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"आवाज़ कम-ज़्यादा करने वाले दोनों बटन दबाकर रखें. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को चालू कर दिया गया."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"आवाज़ कम-ज़्यादा करने वाले दोनों बटन दबाकर रखें. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को बंद कर दिया गया."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> इस्तेमाल करने के लिए आवाज़ वाले दोनों बटन तीन सेकंड तक दबाकर रखें"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"फ़िशिंग से जुड़ी चेतावनी"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"वर्क प्रोफ़ाइल"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"अलर्ट किया गया"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"पुष्टि हो चुकी है"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"विस्तार करें"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"छोटा करें"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"टॉगल विस्तार"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"समाचार और पत्रिकाएं"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Maps और नेविगेशन ऐप्लिकेशन"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"उत्पादकता"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"डिवाइस में जगह"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB डीबग करना"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"घंटा"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"जारी रखने के लिए, <b><xliff:g id="APP">%s</xliff:g></b> को आपके डिवाइस का कैमरा ऐक्सेस करने की ज़रूरत है."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"चालू करें"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"सेंसर से जुड़ी निजता के बारे में सूचना"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"ऐप्लिकेशन का आइकॉन"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ऐप्लिकेशन की ब्रैंड इमेज"</string>
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 91073d4..3a6ce21 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -553,13 +553,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Omogućuje aplikaciji izmjenu vaše zbirke fotografija."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"čitanje lokacija iz vaše medijske zbirke"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Omogućuje aplikaciji čitanje lokacija iz vaše medijske zbirke."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Potvrdite da ste to vi"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrijski hardver nije dostupan"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentifikacija otkazana"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nije prepoznato"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentifikacija otkazana"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nisu postavljeni PIN, uzorak ni zaporka"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Pogreška prilikom autentifikacije"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Otkriven je djelomični otisak prsta. Pokušajte ponovo."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Obrada otiska prsta nije uspjela. Pokušajte ponovo."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Senzor otiska prsta nije čist. Očistite ga i pokušajte ponovo."</string>
@@ -582,6 +592,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor otiska prsta."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je privremeno onemogućen."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Nastavite pomoću otiska prsta"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -609,8 +623,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Lice nije prepoznato. Pokušajte ponovo."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Previše slično, promijenite pozu."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Nagnite glavu malo manje."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Malo manje nagnite glavu."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Nagnite glavu malo manje."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Uklonite sve što vam zakriva lice."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Očistite vrh zaslona, uključujući crnu traku"</string>
@@ -628,6 +641,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Otključavanje licem nije podržano na ovom uređaju."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je privremeno onemogućen."</string>
<string name="face_name_template" msgid="3877037340223318119">"Lice <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Ikona lica"</string>
@@ -1690,8 +1709,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Upotrijebi prečac"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzija boja"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Korekcija boje"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Smanjenje svjetline"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Držali ste tipke za glasnoću. Uključila se usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Držali ste tipke za glasnoću. Isključila se usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pritisnite i zadržite tipke za glasnoću na tri sekunde da biste koristili uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1907,6 +1925,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Upozorenje o krađi identiteta"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Radni profil"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Upozoreni"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Potvrđeno"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Proširivanje"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Sažimanje"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"promjena proširenja"</string>
@@ -1979,6 +1998,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Vijesti i časopisi"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Karte i navigacija"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produktivnost"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Pohrana na uređaju"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Otklanjanje pogrešaka putem USB-a"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"sat"</string>
@@ -2255,8 +2276,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Da bi nastavila s radom, aplikacija <b><xliff:g id="APP">%s</xliff:g></b> treba pristupiti fotoaparatu vašeg uređaja."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Uključi"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privatnost senzora"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Ikona aplikacije"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imidž robne marke aplikacije"</string>
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 32f33df..3cd0aba 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Engedélyezi az alkalmazásnak a fényképgyűjtemény módosítását."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"helyek olvasása a médiagyűjteményből"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Engedélyezi az alkalmazásnak a helyek médiagyűjteményből való olvasását."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Igazolja, hogy Ön az"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrikus hardver nem áll rendelkezésre"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Hitelesítés megszakítva"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nem ismerhető fel"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Hitelesítés megszakítva"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nem állított be PIN-kódot, mintát vagy jelszót."</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Hiba történt a hitelesítés közben"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"A rendszer az ujjlenyomatnak csak egy részletét érzékelte. Próbálkozzon újra."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Nem sikerült feldolgozni az ujjlenyomatot. Próbálkozzon újra."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Az ujjlenyomat-olvasó koszos. Tisztítsa meg, majd próbálkozzon újra."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ez az eszköz nem rendelkezik ujjlenyomat-érzékelővel."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Az érzékelő átmenetileg le van tiltva."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. ujj"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"A folytatáshoz használja ujjlenyomatát"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Már nem lehet felismerni az arcát. Próbálja újra."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Túlságosan hasonló, változtasson a pózon."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Kicsit kevésbé fordítsa el a fejét."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Tartsa kicsit egyenesebben a fejét."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Kicsit kevésbé fordítsa el a fejét."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Távolítson el mindent, ami takarja az arcát."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Tisztítsa meg a képernyő tetejét, a fekete sávot is beleértve."</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Az eszköz nem támogatja az arcalapú feloldást"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Az érzékelő átmenetileg le van tiltva."</string>
<string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> arc"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Arcikon"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Billentyűparancs használata"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Színek invertálása"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Színkorrekció"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Fényerő csökkentése"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Nyomva tartotta a hangerőgombokat. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> bekapcsolva."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Nyomva tartotta a hangerőgombokat. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kikapcsolva."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"A(z) <xliff:g id="SERVICE_NAME">%1$s</xliff:g> használatához tartsa lenyomva három másodpercig a két hangerőgombot"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Adathalászati figyelmeztetés"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Munkaprofil"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Értesítve"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Ellenőrizve"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Kibontás"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Összecsukás"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"kibontás be- és kikapcsolása"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Hírlapok és folyóiratok"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Térképek és navigáció"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Irodai alkalmazások"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Eszköztárhely"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-hibakeresés"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"óra"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"A folytatáshoz a(z) <b><xliff:g id="APP">%s</xliff:g></b> alkalmazásnak hozzáférésre van szüksége az eszköze kamerájához."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Bekapcsolás"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Érzékelőkkel kapcsolatos adatvédelem"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Alkalmazás ikonja"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Alkalmazás márkaképe"</string>
</resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index cd1bbb1..8d6e42e 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Թույլ է տալիս հավելվածին փոփոխել ձեր լուսանկարների հավաքածուն:"</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"ճանաչել տեղադրության մասին տվյալները մեդիա բովանդակության հավաքածուից"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Թույլ է տալիս հավելվածին ճանաչել տեղադրության մասին տվյալները ձեր մեդիա բովանդակության հավաքածուից:"</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Հաստատեք ձեր ինքնությունը"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Կենսաչափական սարքը հասանելի չէ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Նույնականացումը չեղարկվեց"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Չհաջողվեց ճանաչել"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Նույնականացումը չեղարկվեց"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Ավելացրեք PIN կոդ, նախշ կամ գաղտնաբառ։"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Չհաջողվեց նույնականացնել"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Մատնահետքն ամբողջությամբ չի սկանավորվել: Փորձեք նորից:"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Չհաջողվեց մշակել մատնահետքը: Նորից փորձեք:"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Մատնահետքերի սենսորն աղտոտված է: Մաքրեք այն և փորձեք նորից:"</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Այս սարքը չունի մատնահետքերի սկաներ։"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Տվիչը ժամանակավորապես անջատված է:"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Մատնահետք <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Շարունակելու համար անհրաժեշտ է ձեր մատնահետքը"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Չհաջողվեց ճանաչել դեմքը։ Նորից փորձեք:"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Շատ նման է նախորդին։ Փոխեք ձեր դիրքը։"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Գլուխն ուղիղ պահեք։"</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Գլուխը մի փոքր իջեցրեք։"</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Գլուխն ուղիղ պահեք։"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Հեռացրեք այն ամենը, ինչը թաքցնում է ձեր երեսը:"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Մաքրեք էկրանի վերևի մասը, ներառյալ սև գոտին"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Դեմքով ապակողպումն այս սարքում չի աջակցվում"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Տվիչը ժամանակավորապես անջատված է:"</string>
<string name="face_name_template" msgid="3877037340223318119">"Դեմք <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Դեմքի պատկերակ"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Օգտագործել դյուրանցումը"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Գունաշրջում"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Գունաշտկում"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Պայծառության նվազեցում"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ձայնի կարգավորման կոճակները սեղմվեցին։ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունը միացավ։"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ձայնի կարգավորման կոճակները սեղմվեցին։ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունն անջատվեց։"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"«<xliff:g id="SERVICE_NAME">%1$s</xliff:g>» ծառայությունն օգտագործելու համար սեղմեք և 3 վայրկյան պահեք ձայնի ուժգնության երկու կոճակները"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Ֆիշինգի մասին զգուշացում"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Աշխատանքային պրոֆիլ"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Ուղարկվել է զգուշացում"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Հաստատված է"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Ընդարձակել"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Կոծկել"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"Կոծկել/Ընդարձակել"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Նորություններ և ամսագրեր"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Քարտեզներ և նավարկում"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Արդյունավետություն"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Սարքի հիշողություն"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-ով վրիպազերծում"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ժամ"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Շարունակելու համար <b><xliff:g id="APP">%s</xliff:g></b> հավելվածին անհրաժեշտ է ձեր սարքի տեսախցիկի օգտագործման թույլտվություն։"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Միացնել"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Տվիչների գաղտնիություն"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Հավելվածի պատկերակ"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Հավելվածի բրենդային պատկեր"</string>
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index f7fe384..28d2ed8 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Mengizinkan aplikasi untuk memodifikasi koleksi foto Anda."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"membaca lokasi dari koleksi media Anda"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Mengizinkan aplikasi untuk membaca lokasi dari koleksi media Anda."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifikasi bahwa ini memang Anda"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biometrik tidak tersedia"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentikasi dibatalkan"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Tidak dikenali"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentikasi dibatalkan"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Tidak ada PIN, pola, atau sandi yang disetel"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Error saat mengautentikasi"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Sebagian sidik jari terdeteksi. Coba lagi."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Tidak dapat memproses sidik jari. Coba lagi."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Sensor sidik jari kotor. Bersihkan dan coba lagi."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Perangkat ini tidak memiliki sensor sidik jari."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor dinonaktifkan untuk sementara."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Jari <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Gunakan sidik jari untuk melanjutkan"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Tidak lagi dapat mengenali wajah. Coba lagi."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Terlalu mirip, ubah pose Anda."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Putar sedikit kepala Anda."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Miringkan sedikit kepala Anda."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Putar sedikit kepala Anda."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Singkirkan apa saja yang menutupi wajah Anda."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Bersihkan bagian atas layar, termasuk kotak hitam"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Face unlock tidak didukung di perangkat ini."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor dinonaktifkan untuk sementara."</string>
<string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> wajah"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Ikon wajah"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Gunakan Pintasan"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversi Warna"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Koreksi Warna"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Kurangi kecerahan"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tombol volume ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> diaktifkan."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tombol volume ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dinonaktifkan."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Tekan dan tahan kedua tombol volume selama tiga detik untuk menggunakan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Peringatan phishing"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profil kerja"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Diingatkan"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Terverifikasi"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Luaskan"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Ciutkan"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"beralih ke perluasan"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Berita & Majalah"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Peta & Navigasi"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produktivitas"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Penyimpanan perangkat"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Proses debug USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"jam"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Untuk melanjutkan, <b><xliff:g id="APP">%s</xliff:g></b> memerlukan akses ke kamera perangkat."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Aktifkan"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privasi Sensor"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Ikon aplikasi"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Brand image aplikasi"</string>
</resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 5824c3a6..cd5b35a 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Leyfir forritinu að breyta myndasafninu þínu."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"lesa staðsetningar úr efnissafninu þínu"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Leyfir forritinu að lesa staðsetningar úr efnissafninu þínu."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Staðfestu hver þú ert"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Lífkennavélbúnaður ekki tiltækur"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Hætt við auðkenningu"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Þekktist ekki"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Hætt við auðkenningu"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Ekkert PIN-númer, mynstur eða aðgangsorð stillt"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Villa við auðkenningu"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Hluti fingrafars greindist. Reyndu aftur."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Ekki var hægt að vinna úr fingrafarinu. Reyndu aftur."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingrafaraskynjarinn er óhreinn. Hreinsaðu hann og reyndu aftur."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Þetta tæki er ekki með fingrafaralesara."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Slökkt tímabundið á skynjara."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Fingur <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Notaðu fingrafarið þitt til að halda áfram"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Andlit þekkist ekki lengur. Reyndu aftur."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Of svipað. Stilltu þér öðruvísi upp."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Snúðu höfðinu aðeins minna."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Hallaðu höfðinu aðeins minna."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Snúðu höfðinu aðeins minna."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Fjarlægðu það sem kann að hylja andlitið."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Hreinsaðu efsta hluta skjásins þíns, þ.m.t. svörtu stikuna"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Andlitsopnun er ekki studd í þessu tæki."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Slökkt tímabundið á skynjara."</string>
<string name="face_name_template" msgid="3877037340223318119">"Andlit <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Andlitstákn"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Nota flýtileið"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Umsnúningur lita"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Litaleiðrétting"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Minnka birtu"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Hljóðstyrkstökkum haldið inni. Kveikt á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Hljóðstyrkstökkum haldið inni. Slökkt á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Haltu báðum hljóðstyrkstökkunum inni í þrjár sekúndur til að nota <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Viðvörun um vefveiðar"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Vinnusnið"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Tilkynnt"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Staðfest"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Stækka"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Minnka"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"stækka eða minnka"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Fréttir og tímarit"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Kort og leiðsögn"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Aðstoð"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Geymslurými tækis"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-villuleit"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"klst."</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Til að halda áfram þarf <b><xliff:g id="APP">%s</xliff:g></b> aðgang að myndavél tækisins."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Kveikja"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Persónuvernd skynjara"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Forritstákn"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Mynd af merki forrits"</string>
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index d435a25..83b4a68 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Consente all\'app di modificare la tua raccolta di foto."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"lettura delle posizioni dalla tua raccolta multimediale"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Consente all\'app di leggere le posizioni dalla tua raccolta multimediale."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica la tua identità"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biometrico non disponibile"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticazione annullata"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Non riconosciuto"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autenticazione annullata"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Non hai impostato PIN, sequenza o password"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Errore durante l\'autenticazione"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Rilevata impronta parziale. Riprova."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Impossibile elaborare l\'impronta. Riprova."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Il sensore di impronte è sporco. Puliscilo e riprova."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Questo dispositivo non dispone di sensore di impronte."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensore temporaneamente disattivato."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dito <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utilizza la tua impronta per continuare"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Non è più possibile riconoscere il volto. Riprova."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Troppo simile; cambia posa."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Gira un po\' meno la testa."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Inclina un po\' meno la testa."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Gira un po\' meno la testa."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Rimuovi tutto ciò che ti nasconde il viso."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Pulisci la parte superiore dello schermo, inclusa la barra nera"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Sblocco con il volto non supportato su questo dispositivo."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensore temporaneamente disattivato."</string>
<string name="face_name_template" msgid="3877037340223318119">"Volto <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Icona volto"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Usa scorciatoia"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversione dei colori"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Correzione del colore"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Riduci la luminosità"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tieni premuti i tasti del volume. Servizio <xliff:g id="SERVICE_NAME">%1$s</xliff:g> attivato."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tieni premuti i tasti del volume. Servizio <xliff:g id="SERVICE_NAME">%1$s</xliff:g> disattivato."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Tieni premuti entrambi i tasti del volume per tre secondi per utilizzare <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Allerta phishing"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profilo di lavoro"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Avviso inviato"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Verificata"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Espandi"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Comprimi"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"attiva/disattiva l\'espansione"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Notizie e riviste"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Maps e Navigatore"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produttività"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Memoria dispositivo"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Debug USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ora"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Per continuare, l\'app <b><xliff:g id="APP">%s</xliff:g></b> deve accedere alla videocamera del dispositivo."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Attiva"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacy relativa ai sensori"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Icona dell\'applicazione"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Immagine del branding dell\'applicazione"</string>
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index ee771df..e3cb913 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -556,13 +556,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"מאפשרת לאפליקציה לשנות את אוסף התמונות שלך."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"לקרוא מיקומים מאוסף המדיה שלך"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"מאפשרת לאפליקציה לקרוא מיקומים מאוסף המדיה שלך."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"אימות זהותך"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"חומרה ביומטרית לא זמינה"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"האימות בוטל"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"לא זוהתה"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"האימות בוטל"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"עוד לא הוגדרו קוד גישה, קו ביטול נעילה או סיסמה"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"שגיאה באימות"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"זוהתה טביעת אצבע חלקית. אפשר לנסות שוב."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"לא ניתן היה לעבד את טביעת האצבע. נסה שוב."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"החיישן של טביעות האצבעות מלוכלך. צריך לנקות אותו ולנסות שוב."</string>
@@ -585,6 +595,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"במכשיר זה אין חיישן טביעות אצבע."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"החיישן מושבת באופן זמני."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"אצבע <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"יש להשתמש בטביעת האצבע כדי להמשיך"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -612,8 +626,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"כבר לא ניתן לזהות פנים. יש לנסות שוב."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"דומה מדי, יש לשנות תנוחה."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"עליך ליישר קצת את הראש."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"יש ליישר קצת את הראש."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"עליך ליישר קצת את הראש."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"יש להסיר כל דבר שמסתיר את הפנים."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"עליך לנקות את החלק העליון של המסך, כולל הסרגל השחור"</string>
@@ -631,6 +644,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"המכשיר הזה לא תומך בשחרור נעילה על ידי זיהוי פנים."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"החיישן מושבת באופן זמני."</string>
<string name="face_name_template" msgid="3877037340223318119">"פנים <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"סמל הפנים"</string>
@@ -1712,8 +1731,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"השתמש בקיצור הדרך"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"היפוך צבעים"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"תיקון צבעים"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"הפחתה של עוצמת הבהירות"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"לחצני עוצמת הקול נלחצו בלחיצה ארוכה. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> הופעל."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"לחצני עוצמת הקול נלחצו בלחיצה ארוכה. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> הושבת."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"יש ללחוץ לחיצה ארוכה על שני לחצני עוצמת הקול למשך שלוש שניות כדי להשתמש בשירות <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1938,6 +1956,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"התראה על פישינג"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"פרופיל עבודה"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"נשלחה התראה"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"מאומת"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"הרחב"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"כווץ"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"החלפת מצב הרחבה"</string>
@@ -2011,6 +2030,8 @@
<string name="app_category_news" msgid="1172762719574964544">"חדשות וכתבי עת"</string>
<string name="app_category_maps" msgid="6395725487922533156">"מפות וניווט"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"פרודוקטיביות"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"שטח האחסון במכשיר"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"ניקוי באגים ב-USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"שעה"</string>
@@ -2289,8 +2310,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"כדי להמשיך, האפליקציה <b><xliff:g id="APP">%s</xliff:g></b> צריכה גישה למצלמה של המכשיר שלך."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"הפעלה"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"פרטיות חיישנים"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"סמל האפליקציה"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"תדמית המותג של האפליקציה"</string>
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index b03f94c..4b54bdb 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"写真コレクションの変更をアプリに許可します。"</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"メディア コレクションの位置情報の読み取り"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"メディア コレクションの位置情報の読み取りをアプリに許可します。"</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"本人確認"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"生体認証ハードウェアが利用できません"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"認証をキャンセルしました"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"認識されませんでした"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"認証をキャンセルしました"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN、パターン、パスワードが設定されていません"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"エラー認証"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"指紋を一部しか検出できませんでした。もう一度お試しください。"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"指紋を処理できませんでした。もう一度お試しください。"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"指紋認証センサーに汚れがあります。汚れを落としてもう一度お試しください。"</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"このデバイスには指紋認証センサーがありません。"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"センサーが一時的に無効になっています。"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"指紋 <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"続行するには指紋認証を使用してください"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"顔を認識できなくなりました。もう一度お試しください。"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"似すぎています。ポーズを変えてください。"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"顔の向きを少し戻してください。"</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"顔を少し傾けてください。"</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"顔の向きを少し戻してください。"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"顔を隠しているものをすべて外してください"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"黒いバーを含め、画面の上部をきれいにしてください"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"このデバイスでは、顔認証はご利用いただけません。"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"センサーが一時的に無効になっています。"</string>
<string name="face_name_template" msgid="3877037340223318119">"顔 <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"顔アイコン"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ショートカットを使用"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"色反転"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"色補正"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"明るさを下げる"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"音量ボタンを長押ししました。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> が ON になりました。"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"音量ボタンを長押ししました。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> が OFF になりました。"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> を使用するには、音量大と音量小の両方のボタンを 3 秒間長押ししてください"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"フィッシングに関する警告"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"仕事用プロファイル"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"アラートとして送信済み"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"確認済み"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"展開"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"折りたたむ"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"展開の切り替え"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"ニュース&雑誌"</string>
<string name="app_category_maps" msgid="6395725487922533156">"地図&ナビ"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"仕事効率化"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"デバイスのストレージ"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB デバッグ"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"時"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"続行するには、<b><xliff:g id="APP">%s</xliff:g></b> にデバイスのカメラへのアクセスを許可する必要があります。"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ON にする"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"センサー プライバシー"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"アプリのアイコン"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"アプリのブランド イメージ"</string>
</resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index c25bd57..7a03bb3 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"აპი შეძლებს თქვენი ფოტოკოლექციის შეცვლას."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"მდებარეობების გაცნობა თქვენი მედიაკოლექციიდან"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"აპი შეძლებს მდებარეობების გაცნობას თქვენი მედიაკოლექციიდან."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"დაადასტურეთ ვინაობა"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ბიომეტრიული აპარატურა მიუწვდომელია"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ავტორიზაცია გაუქმდა"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"არ არის ამოცნობილი"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"ავტორიზაცია გაუქმდა"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN-კოდი, ნიმუში ან პაროლი დაყენებული არ არის"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"შეცდომა ავთენტიკაციისას"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"აღმოჩენილია თითის ნაწილობრივი ანაბეჭდი. გთხოვთ, სცადოთ ხელახლა."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"თითის ანაბეჭდის დამუშავება ვერ მოხერხდა. გთხოვთ, ცადოთ ხელახლა."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"თითის ანაბეჭდის სენსორი დაბინძურებულია. გთხოვთ, გაასუფთაოთ და სცადოთ ხელახლა."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ამ მოწყობილობას არ აქვს თითის ანაბეჭდის სენსორი."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"სენსორი დროებით გათიშულია."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"თითი <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"გასაგრძელებლად გამოიყენეთ თქვენი თითის ანაბეჭდი"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"სახის ამოცნობა ვეღარ ხერხდება. ცადეთ ხელახლა."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"მეტისმეტად მსგავსია. გთხოვთ, შეცვალოთ პოზა."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"თავი ცოტა ნაკლებად მიაბრუნეთ."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"თავი ცოტა ნაკლებად გადახარეთ."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"თავი ცოტა ნაკლებად მიაბრუნეთ."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"მოაშორეთ ყველაფერი, რაც სახეს გიფარავთ."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"გაწმინდეთ ეკრანის ზედა ნაწილი, შავი ზოლის ჩათვლით."</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"განბლოკვა სახით ამ მოწყობილობაზე მხარდაჭერილი არ არის."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"სენსორი დროებით გათიშულია."</string>
<string name="face_name_template" msgid="3877037340223318119">"სახე <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"სახის ხატულა"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"მალსახმობის გამოყენება"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"ფერთა ინვერსია"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"ფერთა კორექცია"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"სიკაშკაშის შემცირება"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ხანგრძლივად დააჭირეთ ხმის ღილაკებს. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ჩართულია."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ხანგრძლივად დააჭირეთ ხმის ღილაკებს. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> გამორთულია."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> რომ გამოიყენოთ, დააჭირეთ ხმის ორივე ღილაკზე 3 წამის განმავლობაში"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"გაფრთხილება ფიშინგის შესახებ"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"სამსახურის პროფილი"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"გაფრთხილებით"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"დადასტურებულია"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"გაშლა"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"ჩაკეცვა"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"გაშლის გადართვა"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"ახალი ამბები და ჟურნალები"</string>
<string name="app_category_maps" msgid="6395725487922533156">"რუკები და ნავიგაცია"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"პროდუქტიულობა"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"მოწყობილობის მეხსიერება"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB გამართვა"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"საათი"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"გასაგრძელებლად <b><xliff:g id="APP">%s</xliff:g></b>-ს თქვენი მოწყობილობის კამერაზე წვდომა სჭირდება."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ჩართვა"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"სენსორის კონფიდენციალურობა"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"აპლიკაციის ხატულა"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"აპლიკაციის ბრენდის სურათი"</string>
</resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 68edfea..1c00fe6 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Қолданбаға суреттер жинағын өзгертуге мүмкіндік береді."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"медиамазмұн жинағынан геодеректерді оқу"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Қолданбаға медиамазмұн жинағынан геодеректерді оқуға мүмкіндік береді."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Бұл сіз екеніңізді растаңыз"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрикалық жабдық жоқ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Аутентификациядан бас тартылды."</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Танылмады"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Аутентификациядан бас тартылды."</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Ешқандай PIN коды, өрнек немесе құпия сөз орнатылмаған."</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Аутентификациялауда қате шықты."</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Саусақ ізі толық анықталмады. Әрекетті қайталаңыз."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Саусақ ізін өңдеу мүмкін емес. Әрекетті қайталаңыз."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Сканер лас. Тазалап, әрекетті қайталаңыз."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Бұл құрылғыда саусақ ізін оқу сканері жоқ."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчик уақытша өшірулі."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> саусағы"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Жалғастыру үшін саусақ ізін пайдаланыңыз."</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Енді бет анықтау мүмкін емес. Әрекетті қайталаңыз."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Алдыңғысына тым ұқсас, басқаша қалыпта түсіңіз."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Басыңызды түзурек ұстаңыз."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Басыңызды түзуірек ұстаңыз."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Басыңызды кішкене бұрыңыз."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Бетіңізді жауып тұрған нәрсені алып тастаңыз."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Экранның жоғарғы жағын, сонымен қатар қара жолақты өшіріңіз."</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Бұл құрылғыда Face Unlock функциясы істемейді."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Датчик уақытша өшірулі."</string>
<string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> беті"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Бет белгішесі"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Төте жолды пайдалану"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Түстер инверсиясы"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Түсті түзету"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Жарықтығын азайту"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Пайдаланушы дыбыс деңгейі пернелерін басып ұстап тұрды. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> қосулы."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Дыбыс деңгейі пернелерін басып тұрған соң, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> өшірілді."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін пайдалану үшін дыбыс деңгейін реттейтін екі түймені де 3 секунд басып тұрыңыз"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Фишинг ескертуі"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Жұмыс профилі"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Ескертілді"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Расталды"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Жаю"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Жию"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"жаю/жию"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Газеттер және журналдар"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Карта және навигация"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Өнімділік"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Құрылғы жады"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB арқылы түзету"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"сағат"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Жалғастыру үшін <b><xliff:g id="APP">%s</xliff:g></b> қолданбасы құрылғыңыздың камерасына рұқсат алу керек."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Қосу"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Датчикке қатысты құпиялылық"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Қолданба белгішесі"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Қолданба брендін ілгері жылжыту кескіні"</string>
</resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index b3516d5..a2512d2 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"អនុញ្ញាតឱ្យកម្មវិធីកែប្រែបណ្ដុំរូបថតរបស់អ្នក។"</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"អានទីតាំងពីបណ្ដុំមេឌៀរបស់អ្នក"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"អនុញ្ញាតឱ្យកម្មវិធីអានទីតាំងពីបណ្ដុំមេឌៀរបស់អ្នក។"</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"ផ្ទៀងផ្ទាត់ថាជាអ្នក"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"មិនអាចប្រើឧបករណ៍ស្កេនស្នាមម្រាមដៃបានទេ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"បានបោះបង់ការផ្ទៀងផ្ទាត់"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"មិនអាចសម្គាល់បានទេ"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"បានបោះបង់ការផ្ទៀងផ្ទាត់"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"គ្មានការកំណត់កូដ pin លំនាំ ឬពាក្យសម្ងាត់ទេ"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"មានបញ្ហាក្នុងការផ្ទៀងផ្ទាត់"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"បានផ្តិតយកស្នាមម្រាមដៃមិនពេញលក្ខណៈ។ សូមព្យាយាមម្តងទៀត។"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"មិនអាចដំណើរការស្នាមម្រាមដៃបានទេ។ សូមព្យាយាមម្តងទៀត។"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"ឧបករណ៍ចាប់ស្នាមម្រាមដៃគឺប្រឡាក់។ សូមសម្អាត រួចព្យាយាមម្តងទៀត។"</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ឧបករណ៍នេះមិនមានឧបករណ៍ចាប់ស្នាមម្រាមដៃទេ។"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"បានបិទឧបករណ៍ចាប់សញ្ញាជាបណ្តោះអាសន្ន។"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"ម្រាមដៃ <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ប្រើស្នាមម្រាមដៃរបស់អ្នក ដើម្បីបន្ត"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"មិនអាចសម្គាល់មុខបានទៀតទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"ស្រដៀងគ្នាពេក សូមផ្លាស់ប្ដូរកាយវិការរបស់អ្នក។"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ងាកក្បាលរបស់អ្នកតិចជាងមុនបន្តិច។"</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"ផ្អៀងក្បាលរបស់អ្នកតិចជាងនេះបន្តិច។"</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ងាកក្បាលរបស់អ្នកបន្តិចទៀត។"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"យកអ្វីដែលបាំងមុខរបស់អ្នកចេញ។"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"សម្អាតផ្នែកខាងលើនៃអេក្រង់របស់អ្នក រួមទាំងរបារខ្មៅ"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"មិនអាចប្រើការដោះសោតាមទម្រង់មុខនៅលើឧបករណ៍នេះបានទេ។"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"បានបិទឧបករណ៍ចាប់សញ្ញាជាបណ្តោះអាសន្ន។"</string>
<string name="face_name_template" msgid="3877037340223318119">"ផ្ទៃមុខទី <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"រូបផ្ទៃមុខ"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ប្រើប្រាស់ផ្លូវកាត់"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"បញ្ច្រាសពណ៌"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"ការកែពណ៌"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"បន្ថយពន្លឺ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"បានសង្កត់គ្រាប់ចុចកម្រិតសំឡេងជាប់។ បានបើក <xliff:g id="SERVICE_NAME">%1$s</xliff:g>។"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"បានសង្កត់គ្រាប់ចុចកម្រិតសំឡេងជាប់។ បានបិទ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>។"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"ចុចគ្រាប់ចុចកម្រិតសំឡេងទាំងពីរឱ្យជាប់រយៈពេលបីវិនាទី ដើម្បីប្រើ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ការជូនដំណឹងអំពីការដាក់នុយ"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"ប្រវត្តិរូបការងារ"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"បានជូនដំណឹង"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"បានផ្ទៀងផ្ទាត់"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"ពង្រីក"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"លាក់"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"បិទ/បើកការពង្រីក"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"ព័ត៌មាន និងទស្សនាវដ្ដី"</string>
<string name="app_category_maps" msgid="6395725487922533156">"ផែនទី និងការរុករក"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"ផលិតភាព"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ទំហំផ្ទុកឧបករណ៍"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"ការកែកំហុសតាម USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ម៉ោង"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ដើម្បីបន្ត <b><xliff:g id="APP">%s</xliff:g></b> ត្រូវការសិទ្ធិចូលប្រើកាមេរ៉ារបស់ឧបករណ៍អ្នក។"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"បើក"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ឯកជនភាពឧបករណ៍ចាប់សញ្ញា"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"រូបកម្មវិធី"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"រូបភាពផ្សព្វផ្សាយម៉ាកកម្មវិធី"</string>
</resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 22bdd77..e9110c2 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"ನಿಮ್ಮ ಫೋಟೋ ಸಂಗ್ರಹಣೆಯನ್ನು ಮಾರ್ಪಡಿಸಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"ನಿಮ್ಮ ಮೀಡಿಯಾ ಸಂಗ್ರಹಣೆಯಿಂದ ಸ್ಥಳಗಳನ್ನು ಓದಿ"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"ನಿಮ್ಮ ಮೀಡಿಯಾ ಸಂಗ್ರಹಣೆಯಿಂದ ಸ್ಥಳಗಳನ್ನು ಓದಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"ಇದು ನೀವೇ ಎಂದು ಪರಿಶೀಲಿಸಿ"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ಬಯೋಮೆಟ್ರಿಕ್ ಹಾರ್ಡ್ವೇರ್ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ಪ್ರಮಾಣೀಕರಣವನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"ಪ್ರಮಾಣೀಕರಣವನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"ಪಿನ್, ಪ್ಯಾಟರ್ನ್ ಅಥವಾ ಪಾಸ್ವರ್ಡ್ ಸೆಟ್ ಮಾಡಿಲ್ಲ"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"ದೃಢೀಕರಿಸುವಾಗ ದೋಷ ಎದುರಾಗಿದೆ"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"ಭಾಗಶಃ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಪತ್ತೆಯಾಗಿದೆ. ದಯವಿಟ್ಟು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ದಯವಿಟ್ಟು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಕೊಳೆಯಾಗಿದೆ. ದಯವಿಟ್ಟು ಅದನ್ನು ಸ್ವಚ್ಛಗೊಳಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ಈ ಸಾಧನವು ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಅನ್ನು ಹೊಂದಿಲ್ಲ."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ಸೆನ್ಸಾರ್ ಅನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"ಫಿಂಗರ್ <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ಮುಂದುವರಿಸಲು ನಿಮ್ಮ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಬಳಸಿ"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"ಮುಖ ಗುರುತಿಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"ತುಂಬಾ ಸಮಾನ, ನಿಮ್ಮ ಪೋಸ್ ಬದಲಾಯಿಸಿ."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ನಿಮ್ಮ ತಲೆಯನ್ನು ಹೆಚ್ಚು ತಿರುಗಿಸಬೇಡಿ."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"ನಿಮ್ಮ ತಲೆಯನ್ನು ಸ್ವಲ್ಪ ಓರೆಯಾಗಿಸಿ."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ನಿಮ್ಮ ತಲೆಯನ್ನು ಸ್ವಲ್ಪ ಕಡಿಮೆ ತಿರುಗಿಸಿ."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"ನಿಮ್ಮ ಮುಖವನ್ನು ಮರೆಮಾಡುವ ಯಾವುದನ್ನಾದರೂ ತೆಗೆದುಹಾಕಿ."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ಬ್ಲ್ಯಾಕ್ ಬಾರ್ ಸೇರಿದಂತೆ ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ನ ಮೇಲ್ಭಾಗವನ್ನು ತೆರವುಗೊಳಿಸಿ"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"ಈ ಸಾಧನದಲ್ಲಿ ಫೇಸ್ ಅನ್ಲಾಕ್ ವೈಶಿಷ್ಟ್ಯವು ಬೆಂಬಲಿತವಾಗಿಲ್ಲ."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"ಸೆನ್ಸಾರ್ ಅನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
<string name="face_name_template" msgid="3877037340223318119">"ಮುಖದ <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"ಮುಖದ ಐಕಾನ್"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ಶಾರ್ಟ್ಕಟ್ ಬಳಸಿ"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"ಬಣ್ಣ ವಿಲೋಮ"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"ಬಣ್ಣ ತಿದ್ದುಪಡಿ"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"ಪ್ರಖರತೆಯನ್ನು ಕಡಿಮೆ ಮಾಡಿ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಹಿಡಿದುಕೊಳ್ಳಿ. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳಲಾಗಿದೆ. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಬಳಸಲು ಎರಡೂ ಧ್ವನಿ ಕೀಗಳನ್ನು ಮೂರು ಸೆಕೆಂಡ್ಗಳ ಕಾಲ ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ಫಿಶಿಂಗ್ ಕುರಿತು ಎಚ್ಚರಿಕೆ"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"ಎಚ್ಚರಿಕೆ ನೀಡಲಾಗಿದೆ"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"ಪರಿಶೀಲಿಸಲಾಗಿದೆ"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"ವಿಸ್ತೃತಗೊಳಿಸಿ"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"ಕುಗ್ಗಿಸಿ"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"ವಿಸ್ತರಣೆ ಟಾಗಲ್ ಮಾಡಿ"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"ಸುದ್ದಿ ಮತ್ತು ನಿಯತಕಾಲಿಕೆಗಳು"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Maps ಮತ್ತು ನ್ಯಾವಿಗೇಶನ್"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"ಉತ್ಪಾದಕತೆ"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ಸಾಧನ ಸಂಗ್ರಹಣೆ"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB ಡೀಬಗ್ ಮಾಡುವಿಕೆ"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ಗಂಟೆ"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ಮುಂದುವರಿಯಲು, <b><xliff:g id="APP">%s</xliff:g></b> ಗೆ ನಿಮ್ಮ ಸಾಧನದ ಕ್ಯಾಮರಾದ ಪ್ರವೇಶದ ಅಗತ್ಯವಿದೆ."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ಆನ್ ಮಾಡಿ"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ಸೆನ್ಸರ್ ಗೌಪ್ಯತೆ"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"ಅಪ್ಲಿಕೇಶನ್ ಐಕಾನ್"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ಅಪ್ಲಿಕೇಶನ್ ಬ್ರ್ಯಾಂಡಿಂಗ್ ಚಿತ್ರ"</string>
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 52f0a7c..16e2efa 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"앱에서 사진 컬렉션을 수정하도록 허용합니다."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"미디어 컬렉션에서 위치 읽기"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"앱에서 미디어 컬렉션의 위치를 읽도록 허용합니다."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"본인 확인"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"생체 인식 하드웨어를 사용할 수 없음"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"인증이 취소되었습니다."</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"인식할 수 없음"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"인증이 취소되었습니다."</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN, 패턴, 비밀번호가 설정되지 않음"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"인증 오류"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"지문이 일부만 인식되었습니다. 다시 시도해 주세요."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"지문을 인식할 수 없습니다. 다시 시도해 주세요."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"지문 센서를 깨끗이 닦고 다시 시도하세요."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"기기에 지문 센서가 없습니다."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"센서가 일시적으로 사용 중지되었습니다."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"손가락 <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"계속하려면 지문을 사용하세요."</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"더 이상 얼굴을 인식할 수 없습니다. 다시 시도하세요."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"너무 비슷합니다. 다른 포즈를 취해 보세요."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"고개를 조금 덜 돌려 보세요."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"고개를 조금 덜 기울여 보세요."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"고개를 조금 덜 돌려 보세요."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"얼굴이 가려지지 않도록 해 주세요."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"검은색 바를 포함한 화면 상단을 청소하세요."</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"이 기기에서는 얼굴인식 잠금해제가 지원되지 않습니다."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"센서가 일시적으로 사용 중지되었습니다."</string>
<string name="face_name_template" msgid="3877037340223318119">"얼굴 <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"얼굴 아이콘"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"단축키 사용"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"색상 반전"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"색상 보정"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"밝기 낮추기"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"볼륨 키를 길게 눌렀습니다. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 설정되었습니다."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"볼륨 키를 길게 눌렀습니다. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 중지되었습니다."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> 서비스를 사용하려면 두 볼륨 키를 3초 동안 길게 누르세요"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"피싱 알림"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"직장 프로필"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"알림 전송됨"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"확인됨"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"펼치기"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"접기"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"확장 전환"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"뉴스/잡지"</string>
<string name="app_category_maps" msgid="6395725487922533156">"지도/내비게이션"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"생산성"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"기기 저장용량"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB 디버깅"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"시"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"계속하려면 <b><xliff:g id="APP">%s</xliff:g></b>에서 기기 카메라에 액세스해야 합니다."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"사용"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"센서 개인정보 보호"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"애플리케이션 아이콘"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"애플리케이션 브랜드 이미지"</string>
</resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 4d8888e..2584225 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Колдонмого сүрөт жыйнагыңызды өзгөртүүгө мүмкүнчүлүк берет."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"медиа жыйнагыңыз сакталган жерлерди окуу"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Колдонмого медиа жыйнагыңыз сакталган жерлерди окууга мүмкүнчүлүк берет."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Өзүңүздү ырастаңыз"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрикалык аппарат жеткиликсиз"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Аныктыгын текшерүү жокко чыгарылды"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Таанылган жок"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Аныктыгын текшерүү жокко чыгарылды"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN код, графикалык ачкыч же сырсөз коюлган жок"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Аутентификация катасы"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Манжа изи жарым-жартылай аныкталды. Кайталап көрүңүз."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Манжа изи иштелбей койду. Кайталап көрүңүз."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Манжа изинин сенсору кирдеп калган. Тазалап, кайталап көрүңүз."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Бул түзмөктө манжа изинин сенсору жок."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сенсор убактылуу өчүрүлгөн."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>-манжа"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Улантуу үчүн манжаңыздын изин колдонуңуз"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Жүз таанылган жок. Кайталап көрүңүз."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Мурункуга окшош болуп калды, башкача туруңуз."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Башыңызды бир аз гана эңкейтиңиз."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Башыңызды бир аз гана эңкейтиңиз."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Башыңызды бир аз гана эңкейтиңиз."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Жүзүңүздү жашырып турган нерселерди алып салыңыз."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Экраныңыздын жогору жагын, анын ичинде тилкени да тазалаңыз"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Жүзүнөн таануу функциясы бул түзмөктө иштебейт."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Сенсор убактылуу өчүрүлгөн."</string>
<string name="face_name_template" msgid="3877037340223318119">"Жүз <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Жүздүн сүрөтчөсү"</string>
@@ -1015,7 +1034,7 @@
<item quantity="other">Акыркы <xliff:g id="COUNT_1">%d</xliff:g> күн</item>
<item quantity="one">Акыркы <xliff:g id="COUNT_0">%d</xliff:g> күн</item>
</plurals>
- <string name="last_month" msgid="1528906781083518683">"Өткөн ай"</string>
+ <string name="last_month" msgid="1528906781083518683">"Акыркы ай"</string>
<string name="older" msgid="1645159827884647400">"Эскирээк"</string>
<string name="preposition_for_date" msgid="2780767868832729599">"<xliff:g id="DATE">%s</xliff:g> күнү"</string>
<string name="preposition_for_time" msgid="4336835286453822053">"саат <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Кыска жолду колдонуу"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Түстү инверсиялоо"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Түсүн тууралоо"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Экрандын жарыктыгын төмөндөтүү"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Үндү катуулатуу/акырындатуу баскычтары басылып, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> күйгүзүлдү."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Үндү катуулатуу/акырындатуу баскычтары басылып, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> өчүрүлдү."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> кызматын колдонуу үчүн үнүн чоңойтуп/кичирейтүү баскычтарын үч секунд коё бербей басып туруңуз"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Фишинг жөнүндө эскертүү"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Жумуш профили"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Эскертилди"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Ырасталды"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Жайып көрсөтүү"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Жыйыштыруу"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"жайып көрсөтүү же жыйыштыруу"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Жаңылыктар жана журналдар"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Карталар жана чабыттоо"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Өндүрүш категориясы"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Түзмөктүн сактагычы"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB аркылуу мүчүлүштүктөрдү аныктоо"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"саат"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Улантуу үчүн <b><xliff:g id="APP">%s</xliff:g></b> колдонмосуна түзмөгүңүздүн камерасын пайдаланууга уруксат беришиңиз керек."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Күйгүзүү"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Сенсордун купуялыгы"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Колдонмонун сүрөтчөсү"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Колдонмонун брендинин сүрөтү"</string>
</resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 87c2ceb..7fb32e7 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"ອະນຸຍາດໃຫ້ແອັບແກ້ໄຂຄໍເລັກຊັນຮູບຂອງທ່ານ."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"ອ່ານສະຖານທີ່ຈາກຄໍເລັກຊັນມີເດຍຂອງທ່ານ"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"ອະນຸຍາດໃຫ້ແອັບອ່ານສະຖານທີ່ຈາກຄໍເລັກຊັນມີເດຍຂອງທ່ານ."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"ຢັ້ງຢືນວ່າແມ່ນທ່ານ"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ຮາດແວຊີວະມິຕິບໍ່ສາມາດໃຊ້ໄດ້"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ຍົກເລີກການຮັບຮອງຄວາມຖືກຕ້ອງແລ້ວ"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"ບໍ່ຮັບຮູ້"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"ຍົກເລີກການຮັບຮອງຄວາມຖືກຕ້ອງແລ້ວ"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"ບໍ່ໄດ້ຕັ້ງ PIN, ຮູບແບບປົດລັອກ ຫຼື ລະຫັດຜ່ານ"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"ເກີດຄວາມຜິດພາດໃນການພິສູດຢືນຢັນ"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"ກວດພົບລາຍນີ້ວມືບາງສ່ວນແລ້ວ. ກະລຸນາລອງໃໝ່ອີກ."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ບໍ່ສາມາດດຳເນີນການລາຍນີ້ວມືໄດ້. ກະລຸນາລອງໃໝ່ອີກ."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"ເຊັນເຊີລາຍນີ້ວມືເປື້ອນ. ກະລຸນາທຳຄວາມສະອາດ ແລະລອງໃໝ່ອີກ."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ອຸປະກອນນີ້ບໍ່ມີເຊັນເຊີລາຍນິ້ວມື."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ປິດການເຮັດວຽກຂອງເຊັນເຊີໄວ້ຊົ່ວຄາວແລ້ວ."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"ນີ້ວມື <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ໃຊ້ລາຍນີ້ວມືຂອງທ່ານເພື່ອສືບຕໍ່"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"ບໍ່ສາມາດຈຳແນກໃບໜ້າໄດ້ອີກຕໍ່ໄປ. ກະລຸນາລອງໃໝ່."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"ຄ້າຍກັນເກີນໄປ, ກະລຸນາປ່ຽນທ່າຂອງທ່ານ."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ອຽງຫົວຂອງທ່ານໜ້ອຍໜຶ່ງ."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"ປັບມຸມໜ້າຂອງທ່ານໃຫ້ຕັ້ງຊື່."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ອຽງຫົວຂອງທ່ານໜ້ອຍໜຶ່ງ."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"ນຳສິ່ງທີ່ກີດຂວາງໃບໜ້າທ່ານອອກ."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ທຳຄວາມສະອາດສ່ວນເທິງສຸດຂອງໜ້າຈໍທ່ານ, ຮວມທັງແຖບດຳນຳ"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"ບໍ່ຮອງຮັບການປົດລັອກດ້ວຍໜ້າຢູ່ອຸປະກອນນີ້."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"ປິດການເຮັດວຽກຂອງເຊັນເຊີໄວ້ຊົ່ວຄາວແລ້ວ."</string>
<string name="face_name_template" msgid="3877037340223318119">"ໃບໜ້າ <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"ໄອຄອນໃບໜ້າ"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ໃຊ້ປຸ່ມລັດ"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"ການປີ້ນສີ"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"ການແກ້ໄຂຄ່າສີ"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"ຫຼຸດຄວາມສະຫວ່າງລົງ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ກົດປຸ່ມລະດັບສຽງຄ້າງໄວ້. ເປີດໃຊ້ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ແລ້ວ."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ກົດປຸ່ມລະດັບສຽງຄ້າງໄວ້. ປິດ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ໄວ້ແລ້ວ."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"ກົດປຸ່ມສຽງທັງສອງພ້ອມກັນຄ້າງໄວ້ສາມວິນາທີເພື່ອໃຊ້ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ການແຈ້ງເຕືອນການຫຼອກເອົາຂໍ້ມູນ"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"ເຕືອນແລ້ວ"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"ຢັ້ງຢືນແລ້ວ"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"ຂະຫຍາຍ"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"ຫຍໍ້ເຂົ້າ"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"ປິດ/ເປີດ ການຂະຫຍາຍ"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"News & Magazines"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Maps & Navigation"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"ຜະລິດຕະພາບ"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ບ່ອນຈັດເກັບຂໍ້ມູນອຸປະກອນ"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"ການດີບັກຜ່ານ USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ຊົ່ວໂມງ"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ເພື່ອດຳເນີນການຕໍ່, <b><xliff:g id="APP">%s</xliff:g></b> ຕ້ອງການສິດເຂົ້າເຖິງກ້ອງຖ່າຍຮູບຂອງອຸປະກອນທ່ານ."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ເປີດໃຊ້"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ຄວາມເປັນສ່ວນຕົວເຊັນເຊີ"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"ໄອຄອນແອັບພລິເຄຊັນ"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ຮູບແບຣນແອັບພລິເຄຊັນ"</string>
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 2c3742b..820d7a0 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -556,13 +556,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Programai leidžiama keisti nuotraukų kolekciją."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"skaityti vietoves iš medijos kolekcijos"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Programai leidžiama skaityti vietoves iš medijos kolekcijos."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Patvirtinkite, kad tai jūs"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrinė aparatinė įranga nepasiekiama"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentifikavimas atšauktas"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Neatpažinta"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentifikavimas atšauktas"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nenustatytas PIN kodas, atrakinimo piešinys arba slaptažodis"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Autentifikuojant įvyko klaida"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Aptiktas dalinis piršto antspaudas. Bandykite dar kartą."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Nepavyko apdoroti piršto antspaudo. Bandykite dar kartą."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Piršto antspaudo jutiklis purvinas. Nuvalykite ir bandykite dar kartą."</string>
@@ -585,6 +595,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Šiame įrenginyje nėra kontrolinio kodo jutiklio."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Jutiklis laikinai išjungtas."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> pirštas"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Naudokite kontrolinį kodą, kad galėtumėte tęsti"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -612,8 +626,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Nebegalima atpažinti veido. Bandykite dar kartą."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Per daug panašu, pakeiskite veido išraišką."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Nesukite tiek galvos."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Pakreipkite galvą šiek tiek mažiau."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Nesukite tiek galvos."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Patraukite viską, kas užstoja jūsų veidą."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Išvalykite ekrano viršų, įskaitant juodą juostą"</string>
@@ -631,6 +644,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Atrakinimas pagal veidą šiame įrenginyje nepalaikomas."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Jutiklis laikinai išjungtas."</string>
<string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> veidas"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Veido pkt."</string>
@@ -1712,8 +1731,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Naudoti spartųjį klavišą"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Spalvų inversija"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Spalvų taisymas"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Šviesumo mažinimas"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Laikomi garsumo klavišai. „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“ įjungta."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Laikomi garsumo klavišai. „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“ išjungta."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Jei norite naudoti „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“, paspauskite abu garsumo klavišus ir palaikykite tris sekundes"</string>
@@ -1938,6 +1956,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Įspėjimas apie sukčiavimą"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Darbo profilis"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Įspėjimas išsiųstas"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Patvirtinta"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Išskleisti"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Sutraukti"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"perjungti išskleidimą"</string>
@@ -2011,6 +2030,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Naujienos ir žurnalai"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Žemėlapiai ir navigacija"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produktyvumas"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Įrenginio saugykla"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB derinimas"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"valanda"</string>
@@ -2289,8 +2310,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Kad būtų galima tęsti, <b><xliff:g id="APP">%s</xliff:g></b> reikalinga prieiga prie įrenginio fotoaparato."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Įjungti"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Jutiklių privatumas"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Programos piktograma"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Programos prekės ženklo vaizdas"</string>
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 8d6ce86..91c38a4 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -553,13 +553,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Ļauj lietotnei pārveidot jūsu fotoattēlu kolekciju."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"Lasīt atrašanās vietas no jūsu multivides kolekcijas"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Ļauj lietotnei lasīt atrašanās vietas no jūsu multivides kolekcijas."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Apstipriniet, ka tas esat jūs"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrisko datu aparatūra nav pieejama"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentifikācija ir atcelta"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Dati nav atpazīti"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentifikācija ir atcelta"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN, kombinācija vai parole nav iestatīta"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Autentifikācijas kļūda"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Noteikts daļējs pirksta nospiedums. Lūdzu, mēģiniet vēlreiz."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Nevarēja apstrādāt pirksta nospiedumu. Lūdzu, mēģiniet vēlreiz."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Pirkstu nospiedumu sensors ir netīrs. Lūdzu, notīriet to un mēģiniet vēlreiz."</string>
@@ -582,6 +592,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Šajā ierīcē nav pirksta nospieduma sensora."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensors ir īslaicīgi atspējots."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. pirksts"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Lai turpinātu, izmantojiet pirksta nospiedumu"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -609,8 +623,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Seju vairs nevar atpazīt. Mēģiniet vēlreiz."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Pārāk līdzīgi. Lūdzu, mainiet pozu."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Pagrieziet galvu nedaudz mazāk."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Nedaudz mazāk nolieciet galvu."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Pagrieziet galvu nedaudz mazāk."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Noņemiet visu, kas aizsedz jūsu seju."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Notīriet ekrāna augšdaļu, tostarp melno joslu."</string>
@@ -628,6 +641,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Autorizācija pēc sejas šajā ierīcē netiek atbalstīta"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensors ir īslaicīgi atspējots."</string>
<string name="face_name_template" msgid="3877037340223318119">"Seja <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Sejas ikona"</string>
@@ -1690,8 +1709,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Izmantot saīsni"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Krāsu inversija"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Krāsu korekcija"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Spilgtuma samazināšana"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Turējāt nospiestas skaļuma pogas. Pakalpojums <xliff:g id="SERVICE_NAME">%1$s</xliff:g> tika ieslēgts."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Turējāt nospiestas skaļuma pogas. Pakalpojums <xliff:g id="SERVICE_NAME">%1$s</xliff:g> tika izslēgts."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Lai izmantotu pakalpojumu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, nospiediet abus skaļuma taustiņus un turiet tos trīs sekundes."</string>
@@ -1907,6 +1925,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Brīdinājums par pikšķerēšanu"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Darba profils"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Brīdināts"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Verificēts"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Izvērst"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Sakļaut"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"izvērst/sakļaut"</string>
@@ -1979,6 +1998,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Ziņas un žurnāli"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Kartes un navigācija"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produktivitāte"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Ierīces krātuve"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB atkļūdošana"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"stunda"</string>
@@ -2255,8 +2276,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Lai turpinātu, lietotnei <b><xliff:g id="APP">%s</xliff:g></b> nepieciešama piekļuve jūsu ierīces kamerai."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Ieslēgt"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensoru konfidencialitāte"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Lietojumprogrammas ikona"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Lietojumprogrammas zīmola attēls"</string>
</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index af3ce00..88fb824 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Дозволува апликацијата да ја менува вашата збирка на фотографии."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"да чита локации од вашата збирка на аудиовизуелни содржини"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Дозволува апликацијата да чита локации од вашата збирка на аудиовизуелни содржини."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Потврдете дека сте вие"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрискиот хардвер е недостапен"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Проверката е откажана"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Непознат"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Проверката е откажана"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Не е поставен PIN, шема или лозинка"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Грешка при проверката"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Откриен е делумен отпечаток. Обидете се повторно."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Отпечатокот не може да се обработи. Обидете се повторно."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Сензорот за отпечатоци е валкан. Исчистете го и обидете се повторно."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Уредов нема сензор за отпечатоци."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензорот е привремено оневозможен."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Прст <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Користете го отпечатокот за да продолжите"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Ликот не се препознава. Обидете се повторно."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Премногу слично, сменете ја позата."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Не вртете ја главата толку многу."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Не навалувајте ја главата толку многу."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Не вртете ја главата толку многу."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Отстранете ги работите што ви го покриваат лицето."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Исчистете го врвот на екранот, вклучувајќи ја црната лента"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"„Отклучувањето со лик“ не е поддржано на уредов."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Сензорот е привремено оневозможен."</string>
<string name="face_name_template" msgid="3877037340223318119">"Лице <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Икона"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Користи кратенка"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Инверзија на бои"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Корекција на бои"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Намалување на осветленоста"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ги задржавте копчињата за јачина на звук. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> е вклучена."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ги задржавте копчињата за јачина на звук. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> е исклучена."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Притиснете ги и задржете ги двете копчиња за јачина на звукот во траење од три секунди за да користите <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Предупредување за фишинг"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Работен профил"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Предупредено"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Потврдено"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Прошири"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Собери"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"вклучи/исклучи проширување"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Вести и списанија"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Карти и навигација"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Продуктивност"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Простор на уредот"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Отстранување грешки на USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"час"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"За да продолжи, на <b><xliff:g id="APP">%s</xliff:g></b> ѝ е потребен пристап до камерата на уредот."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Вклучи"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Приватност на сензорот"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Икона за апликацијата"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Слика за брендирање на апликацијата"</string>
</resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index aaab7b5..f82267d 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"നിങ്ങളുടെ ഫോട്ടോ ശേഖരം പരിഷ്ക്കരിക്കുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"നിങ്ങളുടെ മീഡിയ ശേഖരത്തിൽ നിന്നും ലൊക്കേഷനുകൾ റീഡ് ചെയ്യുക"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"നിങ്ങളുടെ മീഡിയ ശേഖരത്തിൽ നിന്നും ലൊക്കേഷനുകൾ റീഡ് ചെയ്യുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"ഇത് നിങ്ങളാണെന്ന് പരിശോധിച്ചുറപ്പിക്കുക"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ബയോമെട്രിക് ഹാർഡ്വെയർ ലഭ്യമല്ല"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"പരിശോധിച്ചുറപ്പിക്കൽ റദ്ദാക്കി"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"തിരിച്ചറിഞ്ഞില്ല"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"പരിശോധിച്ചുറപ്പിക്കൽ റദ്ദാക്കി"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"പിന്നോ പാറ്റേണോ പാസ്വേഡോ സജ്ജീകരിച്ചിട്ടില്ല"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"പിശക് പരിശോധിച്ചുറപ്പിക്കുന്നു"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"ഫിംഗർപ്രിന്റ് ഭാഗികമായി തിരിച്ചറിഞ്ഞു. വീണ്ടും ശ്രമിക്കുക."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ഫിംഗർപ്രിന്റ് പ്രോസസ് ചെയ്യാനായില്ല. വീണ്ടും ശ്രമിക്കുക."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"ഫിംഗർപ്രിന്റ് സെൻസറിൽ ചെളിയുണ്ട്. അത് വൃത്തിയാക്കി വീണ്ടും ശ്രമിക്കുക."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ഈ ഉപകരണത്തിൽ ഫിംഗർപ്രിന്റ് സെൻസറില്ല."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"സെൻസർ താൽക്കാലികമായി പ്രവർത്തനരഹിതമാക്കി."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"കൈവിരൽ <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"തുടരുന്നതിന് നിങ്ങളുടെ ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കുക"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"ഇനി മുഖം തിരിച്ചറിയാനാവില്ല. വീണ്ടും ശ്രമിക്കൂ."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"വളരെയധികം സമാനത, നിങ്ങളുടെ പോസ് മാറ്റുക."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"നിങ്ങളുടെ തല ഇത്ര തിരിക്കേണ്ട."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"നിങ്ങളുടെ തല ചെറുതായി ടിൽറ്റ് ചെയ്യുക."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"നിങ്ങളുടെ തല ഇത്ര തിരിക്കേണ്ട."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"നിങ്ങളുടെ മുഖം മറയ്ക്കുന്നത് എല്ലാം നീക്കം ചെയ്യൂ."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"കറുപ്പ് ബാർ ഉൾപ്പെടെ നിങ്ങളുടെ സ്ക്രീനിന്റെ മുകൾഭാഗം വൃത്തിയാക്കുക"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"മുഖം തിരിച്ചറിഞ്ഞുള്ള അൺലോക്ക് ഈ ഉപകരണം പിന്തുണയ്ക്കുന്നില്ല."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"സെൻസർ താൽക്കാലികമായി പ്രവർത്തനരഹിതമാക്കി."</string>
<string name="face_name_template" msgid="3877037340223318119">"മുഖം <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"മുഖത്തിന്റെ ഐക്കൺ"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"കുറുക്കുവഴി ഉപയോഗിക്കുക"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"വർണ്ണ വിപര്യയം"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"നിറം ക്രമീകരിക്കൽ"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"തെളിച്ചം കുറയ്ക്കുക"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"വോളിയം കീകൾ പിടിച്ചു. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓണാക്കി."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"വോളിയം കീകൾ അമർത്തിപ്പിടിച്ചു. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓഫാക്കി."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഉപയോഗിക്കാൻ, രണ്ട് വോളിയം കീകളും മൂന്ന് സെക്കൻഡ് അമർത്തിപ്പിടിക്കുക"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ഫിഷിംഗ് മുന്നറിയിപ്പ്"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"മുന്നറിയിപ്പ് നൽകി"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"പരിശോധിച്ചുറപ്പിച്ചത്"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"വികസിപ്പിക്കുക"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"ചുരുക്കുക"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"വികസിപ്പിക്കൽ ടോഗിൾ ചെയ്യുക"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"വാർത്തകളും മാസികകളും"</string>
<string name="app_category_maps" msgid="6395725487922533156">"മാപ്പുകളും നാവിഗേഷനും"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"ഉല്പ്പാദനക്ഷമത"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ഉപകരണ സ്റ്റോറേജ്"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB ഡീബഗ്ഗിംഗ്"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"മണി."</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"തുടരാൻ, <b><xliff:g id="APP">%s</xliff:g></b> ആപ്പിന് നിങ്ങളുടെ ഉപകരണത്തിന്റെ ക്യാമറയിലേക്ക് ആക്സസ് നൽകേണ്ടതുണ്ട്."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ഓണാക്കുക"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"സെൻസർ സ്വകാര്യത"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"ആപ്പ് ഐക്കൺ"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"അപ്ലിക്കേഷൻ ബ്രാൻഡിംഗ് ഇമേജ്"</string>
</resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index c699285..203ad3d 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Таны зургийн цуглуулгыг тохируулах зөвшөөрлийг аппад олгодог."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"медиа цуглуулгаасаа байршлыг унших"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Таны медиа цуглуулгаас байршлыг унших зөвшөөрлийг аппад олгодог."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Өөрийгөө мөн гэдгийг баталгаажуулаарай"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрийн техник хангамж боломжгүй байна"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Нотолгоог цуцаллаа"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Таниагүй"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Нотолгоог цуцаллаа"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Тохируулсан пин, хээ эсвэл нууц үг алга"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Баталгаажуулахад алдаа гарлаа"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Хурууны хээг дутуу уншуулсан байна. Дахин оролдоно уу."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Хурууны хээ боловсруулж чадахгүй байна. Дахин оролдоно уу."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Хурууны хээ мэдрэгч бохирдсон байна. Цэвэрлэсний дараа дахин оролдоно уу."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Энэ төхөөрөмжид хурууны хээ мэдрэгч алга."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Мэдрэгчийг түр хугацаанд идэвхгүй болгосон."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Хурууны хээ <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Үргэлжлүүлэхийн тулд хурууны хээгээ ашиглаарай"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Царайг таних боломжгүй боллоо. Дахин оролдоно уу."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Хэт адилхан байгаа тул байрлалаа өөрчилнө үү."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Толгойгоо арай багаар эргүүлнэ үү."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Толгойгоо арай бага хазайлгана уу."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Толгойгоо арай багаар эргүүлнэ үү."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Таны нүүрийг далдалж буй аливаа зүйлийг хасна уу."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Хар хэсэг зэрэг дэлгэцийнхээ дээд хэсгийг цэвэрлэнэ үү"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Царайгаар тайлахыг энэ төхөөрөмж дээр дэмждэггүй."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Мэдрэгчийг түр хугацаанд идэвхгүй болгосон."</string>
<string name="face_name_template" msgid="3877037340223318119">"Царай <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Царайны дүрс тэмдэг"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Товчлол ашиглах"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Өнгө хувиргалт"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Өнгөний засвар"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Гэрэлтүүлгийг багасгах"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Дууны түвшний түлхүүрийг удаан дарсан. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г асаалаа."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Дууны түвшний түлхүүрийг удаан дарсан. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г унтраалаа."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г ашиглахын тулд дууны түвшнийг ихэсгэх, багасгах түлхүүрийг 3 секундийн турш зэрэг дарна уу"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Фишинг сэрэмжлүүлэг"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Ажлын профайл"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Мэдэгдсэн"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Баталгаажуулсан"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Дэлгэх"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Буулгах"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"асаах/унтраах өргөтгөл"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Мэдээ & сэтгүүл"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Газрын зураг & зүг чиг"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Бүтээмж"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Төхөөрөмжийн сан"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB дебаг хийлт"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"Цаг"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Үргэлжлүүлэхийн тулд <b><xliff:g id="APP">%s</xliff:g></b> таны төхөөрөмжийн камерт хандах шаардлагатай."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Асаах"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Мэдрэгчийн нууцлал"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Аппын дүрс тэмдэг"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Аппын брэнд зураг"</string>
</resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index a31951a..102c469 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"ॲपला तुमच्या फोटो संग्रहामध्ये सुधारणा करण्याची अनुमती देते."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"तुमच्या मीडिया संग्रहातून स्थाने वाचा"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"ॲपला तुमच्या मीडिया संग्रहामध्येील स्थाने वाचण्यासाठी अनुमती देते."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"हे तुम्हीच आहात याची पडताळणी करा"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"बायोमेट्रिक हार्डवेअर उपलब्ध नाही"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ऑथेंटिकेशन रद्द केले"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"ओळखले नाही"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"ऑथेंटिकेशन रद्द केले"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"कोणताही पिन, पॅटर्न किंवा पासवर्ड सेट केलेला नाही"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"एरर ऑथेंटिकेट करत आहे"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"आंशिक फिंगरप्रिंट आढळली. कृपया पुन्हा प्रयत्न करा."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"फिंगरप्रिंटवर प्रक्रिया करणे शक्य झाले नाही. कृपया पुन्हा प्रयत्न करा."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"फिंगरप्रिंट सेन्सर खराब आहे. कृपया साफ करा आणि पुन्हा प्रयत्न करा."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"या डिव्हाइसमध्ये फिंगरप्रिंट सेन्सर नाही."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"सेन्सर तात्पुरता बंद केला आहे."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> बोट"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"पुढे सुरू ठेवण्यासाठी तुमची फिंगरप्रिंट वापरा"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"चेहरा ओळखू शकत नाही. पुन्हा प्रयत्न करा."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"एकाच प्रकारची पोझ देत आहात कृपया तुमची पोझ बदला."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"तुमचे डोके थोडे कमी फिरवा."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"तुमचे डोके थोडे कमी तिरपे करा."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"तुमचे डोके थोडे कमी फिरवा."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"तुमचा चहेरा लपवणारे काहीही काढून टाका."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ब्लॅक बार सह तुमच्या स्क्रीनची वरची बाजू साफ करा"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"या डिव्हाइसवर फेस अनलॉकला सपोर्ट नाही."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"सेन्सर तात्पुरता बंद केला आहे."</string>
<string name="face_name_template" msgid="3877037340223318119">"चेहरा <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"चेहरा आयकन"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"शॉर्टकट वापरा"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"रंगांची उलटापालट"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"रंग सुधारणा"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"ब्राइटनेस कमी करा"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"धरून ठेवलेल्या व्हॉल्यूम की. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> सुरू केला आहे."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"धरून ठेवलेल्या व्हॉल्यूम की. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> बंद केले आहे."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> वापरण्यासाठी दोन्ही व्हॉल्युम की तीन सेकंद दाबा आणि धरून ठेवा"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"फिशिंगशी संबंधित सूचना"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"कार्य प्रोफाईल"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"सूचना दिल्या"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"पडताळणी केलेला"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"विस्तृत करा"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"संकुचित करा"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"टॉगल विस्तार"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"बातम्या आणि मासिके"</string>
<string name="app_category_maps" msgid="6395725487922533156">"नकाशे आणि नेव्हिगेशन"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"उत्पादनक्षमता"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"डिव्हाइस स्टोरेज"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB डीबगिंग"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"तास"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"पुढे सुरू ठेवण्यासाठी, <b><xliff:g id="APP">%s</xliff:g></b> ला तुमच्या डिव्हाइसचा कॅमेरा अॅक्सेस करण्याची आवश्यकता आहे."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"सुरू करा"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"सेन्सरशी संबंधित गोपनीयतेबाबत सूचना"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"ॲप्लिकेशन आयकन"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"अॅप्लिकेशन ब्रॅंडिंग इमेज"</string>
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 5e5b29f..d8d43a6 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Membenarkan apl mengubah suai koleksi foto anda."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"baca lokasi daripada koleksi media anda"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Membenarkan apl membaca lokasi daripada koleksi media anda."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Sahkan itu anda"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Perkakasan biometrik tidak tersedia"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Pengesahan dibatalkan"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Tidak dikenali"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Pengesahan dibatalkan"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Pin, corak atau kata laluan tidak ditetapkan"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Ralat semasa membuat pengesahan"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Cap jari separa dikesan. Sila cuba lagi."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Tidak dapat memproses cap jari. Sila cuba lagi."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Penderia cap jari kotor. Sila bersihkan dan cuba lagi."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Peranti ini tiada penderia cap jari."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Penderia dilumpuhkan sementara."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Jari <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Gunakan cap jari anda untuk teruskan"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Tidak lagi dapat mengecam wajah. Cuba lagi."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Terlalu serupa, sila ubah lagak gaya anda."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Pusingkan kepala anda kurang sedikit."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Sengetkan kepala anda kurang sedikit."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Pusingkan kepala anda kurang sedikit."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Alih keluar apa saja yang melindungi wajah anda."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Bersihkan bahagian atas skrin anda, termasuk bar hitam"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Wajah buka kunci tidak disokong pada peranti ini."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Penderia dilumpuhkan sementara."</string>
<string name="face_name_template" msgid="3877037340223318119">"Wajah <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Ikon wajah"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Gunakan Pintasan"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Penyongsangan Warna"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Pembetulan Warna"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Kurangkan kecerahan"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Kekunci kelantangan ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dihidupkan."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Kekunci kelantangan ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dimatikan."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Tekan dan tahan kedua-dua kekunci kelantangan selama tiga saat untuk menggunakan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Amaran pancingan data"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profil kerja"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Dimaklumkan"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Disahkan"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Kembangkan"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Runtuhkan"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"togol pengembangan"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Berita & Majalah"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Peta & Navigasi"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produktiviti"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Storan peranti"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Penyahpepijatan USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"jam"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Untuk meneruskan proses, <b><xliff:g id="APP">%s</xliff:g></b> memerlukan akses kepada kamera peranti anda."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Hidupkan"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privasi Penderia"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Ikon aplikasi"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imej jenama aplikasi"</string>
</resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 137c138..82008b0 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"အက်ပ်အား သင့်ဓာတ်ပုံစုစည်းမှုကို ပြုပြင်ခွင့်ပေးသည်။"</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"သင့်မီဒီယာစုစည်းမှုမှ တည်နေရာများကို ဖတ်ခြင်း"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"အက်ပ်အား သင့်မီဒီယာစုစည်းမှုမှ တည်နေရာများကို ဖတ်ခွင့်ပေးသည်။"</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"သင်ဖြစ်ကြောင်း အတည်ပြုပါ"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ဇီဝအချက်အလက်သုံး ကွန်ပျူတာစက်ပစ္စည်း မရရှိနိုင်ပါ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"အထောက်အထားစိစစ်ခြင်းကို ပယ်ဖျက်လိုက်သည်"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"မသိ"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"အထောက်အထားစိစစ်ခြင်းကို ပယ်ဖျက်လိုက်သည်"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"ပင်နံပါတ်၊ လော့ခ်ပုံစံ သို့မဟုတ် စကားဝှက် သတ်မှတ်မထားပါ"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"အထောက်အထားစိစစ်ရာတွင် အမှားအယွင်းရှိနေသည်"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"လက်ဗွေ တစ်ပိုင်းတစ်စ တွေ့ရှိသည်။ ကျေးဇူးပြု၍ ထပ်စမ်းကြည့်ပါ။"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"လက်ဗွေယူ၍ မရပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"လက်ဗွေဖတ်ကိရိယာ ညစ်ပေနေသည်။ ကျေးဇူးပြု၍ သန့်ရှင်းလိုက်ပြီး ပြန်စမ်းကြည့်ပါ။"</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ဤစက်တွင် လက်ဗွေအာရုံခံကိရိယာ မရှိပါ။"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"အာရုံခံကိရိယာကို ယာယီပိတ်ထားသည်။"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"လက်ချောင်း <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ရှေ့ဆက်ရန် သင့်လက်ဗွေကို သုံးပါ"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"မျက်နှာ မမှတ်သားနိုင်တော့ပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"ဆင်တူနေသည်၊ အမူအရာ ပြောင်းပါ။"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ခေါင်းကို သိပ်မလှည့်ပါနှင့်။"</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"သင့်ခေါင်းကို သိပ်မလှည့်ပါနှင့်။"</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ခေါင်းကို သိပ်မလှည့်ပါနှင့်။"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"သင့်မျက်နှာကို ကွယ်နေသည့်အရာအားလုံး ဖယ်ပါ။"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"အနက်ရောင်ဘားအပါအဝင် ဖန်သားပြင်ထိပ်ကို သန့်ရှင်းရေး လုပ်ပါ"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"ဤစက်ပစ္စည်းတွင် မျက်နှာမှတ် သော့ဖွင့်ခြင်းကို သုံး၍မရပါ။"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"အာရုံခံကိရိယာကို ယာယီပိတ်ထားသည်။"</string>
<string name="face_name_template" msgid="3877037340223318119">"မျက်နှာ <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"မျက်နှာသင်္ကေတ"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ဖြတ်လမ်းလင့်ခ်ကို သုံးရန်"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"အရောင် ပြောင်းပြန်လှန်ခြင်း"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"အရောင်ပြင်ဆင်ခြင်း"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"တောက်ပမှုကို လျှော့ခြင်း"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"အသံခလုတ်များကို ဖိထားသည်။ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ဖွင့်လိုက်သည်။"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"အသံခလုတ်များကို ဖိထားသည်။ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ပိတ်လိုက်သည်။"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ကို သုံးရန် အသံအတိုးအလျှော့ ခလုတ်နှစ်ခုလုံးကို သုံးစက္ကန့်ကြာ ဖိထားပါ"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"အယောင်ဆောင်ဖြားယောင်းခြင်း သတိပေးချက်"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"အလုပ်ကိုယ်ရေးအချက်အလက်"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"သတိပေးထားသည်"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"စိစစ်ထားသည်"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"ချဲ့ရန်"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"ခေါက်သိမ်းရန်"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"ချဲ့ခြင်းခလုတ်"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"သတင်းနှင့် မဂ္ဂဇင်းများ"</string>
<string name="app_category_maps" msgid="6395725487922533156">"မြေပုံနှင့် ခရီးလမ်းညွှန်ချက်"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"ထုတ်လုပ်နိုင်မှု"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"စက်ပစ္စည်း သိုလှောင်ခန်း"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB အမှားရှာပြင်ခြင်း"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"နာရီ"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ဆက်လက်လုပ်ဆောင်ရန် <b><xliff:g id="APP">%s</xliff:g></b> က သင့်စက်၏ ကင်မရာကို အသုံးပြုခွင့်ရရန် လိုအပ်သည်။"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ဖွင့်ရန်"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"အာရုံခံကိရိယာ လုံခြုံရေး"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"အပလီကေးရှင်း သင်္ကေတ"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"အပလီကေးရှင်း ကုန်အမှတ်တံဆိပ်ပုံ"</string>
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index de71c39..1bafd60 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Lar appen gjøre endringer i bildesamlingen din."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"lese posisjoner fra mediesamlingen din"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Lar appen lese posisjoner fra mediesamlingen din."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Bekreft at det er deg"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrisk maskinvare er utilgjengelig"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentiseringen er avbrutt"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Ikke gjenkjent"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentiseringen er avbrutt"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN-kode, mønster eller passord er ikke angitt"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Feil under autentiseringen"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Deler av fingeravtrykket er registrert. Prøv på nytt."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Kunne ikke registrere fingeravtrykket. Prøv på nytt."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingeravtrykksensoren er skitten. Rengjør den og prøv på nytt."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Denne enheten har ikke fingeravtrykkssensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensoren er midlertidig slått av."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Bruk fingeravtrykket ditt for å fortsette"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Kan ikke gjenkjenne ansiktet lenger. Prøv igjen."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"For likt – endre posituren din."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Vri hodet ditt litt mindre."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Vri hodet litt mindre."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Vri hodet ditt litt mindre."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Fjern alt som skjuler ansiktet ditt."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Rengjør den øverste delen av skjermen, inkludert den svarte linjen"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Ansiktslås støttes ikke på denne enheten"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensoren er midlertidig slått av."</string>
<string name="face_name_template" msgid="3877037340223318119">"Ansikt <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Ansiktikon"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Bruk snarveien"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Fargeinvertering"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Fargekorrigering"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Reduser lysstyrken"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Volumtastene holdes inne. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er slått på."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Volumtastene holdes inne. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er slått av."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Trykk og hold inne begge volumtastene i tre sekunder for å bruke <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Varsel om nettfisking"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Arbeidsprofil"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Varslet"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Bekreftet"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Vis"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Skjul"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"slå utvidelse av/på"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Nyheter og tidsskrifter"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Kart og navigering"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produktivitet"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Lagring på enheten"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-feilsøking"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"time"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"For å fortsette må <b><xliff:g id="APP">%s</xliff:g></b> ha tilgang til enhetskameraet."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Slå på"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensorpersonvern"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Appikon"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Merkevareprofilen til appen"</string>
</resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 83c03a4..a15a9a4 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"यसले एपलाई तपाईंको तस्बिरको सङ्ग्रह परिमार्जन गर्न दिन्छ।"</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"आफ्नो मिडियाको सङ्ग्रहका स्थानहरू पढ्नुहोस्"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"यसले एपलाई तपाईंको मिडिया सङ्ग्रहका स्थानहरू पढ्न दिन्छ।"</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"यो व्यक्ति तपाईं नै हो भन्ने प्रमाणित गर्नुहोस्"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"बायोमेट्रिक हार्डवेयर उपलब्ध छैन"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"प्रमाणीकरण रद्द गरियो"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"पहिचान भएन"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"प्रमाणीकरण रद्द गरियो"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"कुनै पनि PIN, ढाँचा वा पासवर्ड सेट गरिएको छैन"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"प्रमाणित गर्ने क्रममा त्रुटि भयो"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"आंशिक फिंगरप्रिन्ट पत्ता लाग्यो। कृपया फेरि प्रयास गर्नुहोस्।"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"फिंगरप्रिन्ट प्रशोधन गर्न सकिएन। कृपया फेरि प्रयास गर्नुहोस्।"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"फिंगरप्रिन्ट सेन्सर फोहोर छ। कृपया सफा गरेर फेरि प्रयास गर्नुहोस्।"</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"यो यन्त्रमा कुनै पनि फिंगरप्रिन्ट सेन्सर छैन।"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"केही समयका लागि सेन्सर असक्षम पारियो।"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"औंला <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"जारी राख्न आफ्नो फिंगरप्रिन्ट प्रयोग गर्नुहोस्"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"अब उप्रान्त अनुहार पहिचान गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"अनुहार उस्तै भयो, कृपया आफ्नो पोज बदल्नुहोस्।"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"आफ्नो टाउको अलि थोरै घुमाउनुहोस्।"</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"आफ्नो टाउको केही कम झुकाउनुहोस्।"</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"आफ्नो टाउको अलि थोरै घुमाउनुहोस्।"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"तपाईंको अनुहार लुकाउने सबै कुरा लुकाउनुहोस्।"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"कालो रङको पट्टीलगायत आफ्नो स्क्रिनको माथिल्लो भाग सफा गर्नुहोस्"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"यस यन्त्रमा फेस अनलक सुविधा प्रयोग गर्न मिल्दैन।"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"केही समयका लागि सेन्सर असक्षम पारियो।"</string>
<string name="face_name_template" msgid="3877037340223318119">"अनुहार <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"अनुहारको आइकन"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"सर्टकट प्रयोग गर्नुहोस्"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"रङ्ग उल्टाउने सुविधा"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"रङ्ग सच्याउने सुविधा"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"चमक घटाइयोस्"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"तपाईंले भोल्युम बटनहरू थिचिराख्नुभयो। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> अन भयो।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"तपाईंले भोल्युम बटनहरू थिचिराख्नुभयो। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> अफ भयो।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> प्रयोग गर्न दुवै भोल्युम कुञ्जीहरूलाई तीन सेकेन्डसम्म थिचिराख्नुहोस्"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"फिसिङसम्बन्धी अलर्ट"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"कार्य प्रोफाइल"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"सतर्कता गरियो"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"पुष्टि गरिएको"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"विस्तृत गर्नुहोस्"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"संक्षिप्त गर्नुहोस्"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"विस्तारलाई टगल गर्नुहोस्"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"समाचार तथा पत्रिकाहरू"</string>
<string name="app_category_maps" msgid="6395725487922533156">"नक्सा तथा नेभिगेसन"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"उत्पादकत्व"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"यन्त्रको भण्डारण"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB डिबग प्रक्रिया"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"घन्टा"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"जारी राख्न <b><xliff:g id="APP">%s</xliff:g></b> लाई तपाईंको यन्त्रको क्यामेरा प्रयोग गर्ने अनुमति दिनु पर्ने हुन्छ।"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"अन गर्नुहोस्"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"सेन्सरसम्बन्धी गोपनीयता"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"एप जनाउने आइकन"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"एपको ब्रान्डिङ फोटो"</string>
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index e2be98d..1f2680e 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Hiermee sta je de app toe je fotocollectie aan te passen."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"locaties van je mediacollecties bekijken"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Hiermee sta je de app toe locaties van je mediacollectie te bekijken."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Je identiteit verifiëren"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrische hardware niet beschikbaar"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Verificatie geannuleerd"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Niet herkend"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Verificatie geannuleerd"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Geen pincode, patroon of wachtwoord ingesteld"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Fout bij verificatie"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Gedeeltelijke vingerafdruk gedetecteerd. Probeer het opnieuw."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Kan vingerafdruk niet verwerken. Probeer het opnieuw."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"De vingerafdruksensor moet worden schoongemaakt. Probeer het daarna opnieuw."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dit apparaat heeft geen vingerafdruksensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor tijdelijk uitgeschakeld."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Vinger <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Gebruik je vingerafdruk om door te gaan."</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Herkent gezicht niet meer. Probeer het nog eens."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Lijkt te veel op elkaar. Verander je pose."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Draai je hoofd iets minder."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Kantel je hoofd iets minder."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Draai je hoofd iets minder."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Zorg dat je gezicht volledig zichtbaar is."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Reinig de bovenkant van je scherm, inclusief de zwarte balk"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Ontgrendelen via gezichtsherkenning wordt niet ondersteund op dit apparaat."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor tijdelijk uitgeschakeld."</string>
<string name="face_name_template" msgid="3877037340223318119">"Gezicht <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Gezichtspictogram"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Sneltoets gebruiken"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Kleurinversie"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Kleurcorrectie"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Helderheid verlagen"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Volumetoetsen ingedrukt gehouden. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> is ingeschakeld."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Volumetoetsen ingedrukt gehouden. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> uitgeschakeld."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Houd beide volumetoetsen drie seconden ingedrukt om <xliff:g id="SERVICE_NAME">%1$s</xliff:g> te gebruiken"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Phishingmelding"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Werkprofiel"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Gemeld"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Geverifieerd"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Uitvouwen"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Samenvouwen"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"uitvouwen in-/uitschakelen"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Nieuws en tijdschriften"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Maps en navigatie"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Productiviteit"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Apparaatopslag"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-foutopsporing"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"uur"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"<b><xliff:g id="APP">%s</xliff:g></b> heeft toegang tot de camera van je apparaat nodig om door te gaan."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Aanzetten"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensorprivacy"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"App-icoon"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Merkafbeelding voor app"</string>
</resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index bc76142..e3c3c09 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"ଆପଣଙ୍କ ଫଟୋ ସଂଗ୍ରହ ପରିବର୍ତ୍ତନ କରିବାକୁ ଆପ୍ ଅନୁମତି ଦେଇଥାଏ।"</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"ଆପଣଙ୍କ ମିଡିଆ ସଂଗ୍ରହ ଠାରୁ ଲୋକେସନ୍ଗୁଡିକୁ ପଢନ୍ତୁ"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"ଆପଣଙ୍କ ମିଡିଆ ସଂଗ୍ରହ ଠାରୁ ଅବସ୍ଥାନଗୁଡିକୁ ପଢିବାକୁ ଆପ୍ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"ଏହା ଆପଣ ବୋଲି ଯାଞ୍ଚ କରନ୍ତୁ"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ବାୟୋମେଟ୍ରିକ୍ ହାର୍ଡୱେର୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ପ୍ରାମାଣିକତାକୁ ବାତିଲ୍ କରାଯାଇଛି"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"ଚିହ୍ନଟ ହେଲାନାହିଁ"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"ପ୍ରାମାଣିକତାକୁ ବାତିଲ୍ କରାଯାଇଛି"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"କୌଣସି ପିନ୍, ପେଟେର୍ନ ବା ପାସ୍ୱର୍ଡ ସେଟ୍ ନାହିଁ"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"ପ୍ରାମାଣିକରଣ କରିବା ସମୟରେ ତ୍ରୁଟି"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"ଆଂଶିକ ଟିପଚିହ୍ନ ଚିହ୍ନଟ ହେଲା। ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ଟିପଚିହ୍ନ ପ୍ରୋସେସ୍ କରାଯାଇପାରିଲା ନାହିଁ। ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"ଟିପଚିହ୍ନ ସେନ୍ସର୍ ମଇଳା ହୋଇଯାଇଛି। ଦୟାକରି ସଫା କରନ୍ତୁ ଓ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ଏହି ଡିଭାଇସ୍ରେ ଟିପଚିହ୍ନ ସେନ୍ସର୍ ନାହିଁ।"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ସେନ୍ସରକୁ ଅସ୍ଥାୟୀ ଭାବେ ଅକ୍ଷମ କରାଯାଇଛି।"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"ଆଙ୍ଗୁଠି <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"ଆଉ ମୁହଁ ଚିହ୍ନଟ କରିହେଲା ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"ଅତ୍ୟନ୍ତ ସମପରି, ଦୟାକରି ଆପଣଙ୍କର ପୋଜ୍ ବଦଳାନ୍ତୁ।"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ଆପଣଙ୍କର ମୁଣ୍ଡକୁ ଟିକିଏ ବୁଲାନ୍ତୁ।"</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"ଆପଣଙ୍କ ମୁଣ୍ଡକୁ ଟିକିଏ କମ୍ ଟିଲ୍ଟ କରନ୍ତୁ।"</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ଆପଣଙ୍କର ମୁଣ୍ଡକୁ ଟିକିଏ ବୁଲାନ୍ତୁ।"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"ଆପଣଙ୍କର ମୁହଁ ଲୁଚାଉଥିବା ଜିନିଷକୁ କାଢ଼ି ଦିଅନ୍ତୁ।"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"କଳା ବାର୍ ସମେତ ଆପଣଙ୍କ ସ୍କ୍ରିନ୍ର ଶୀର୍ଷକୁ ସଫା କରନ୍ତୁ"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"ଏହି ଡିଭାଇସ୍ରେ ଫେସ୍ ଅନ୍ଲକ୍ ସମର୍ଥିତ ନୁହେଁ।"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"ସେନ୍ସରକୁ ଅସ୍ଥାୟୀ ଭାବେ ଅକ୍ଷମ କରାଯାଇଛି।"</string>
<string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g>ଙ୍କ ଫେସ୍"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"ଫେସ୍ ଆଇକନ୍"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ଶର୍ଟକଟ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"ରଙ୍ଗ ବଦଳାଇବାର ସୁବିଧା"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"ରଙ୍ଗ ସଂଶୋଧନ"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"ଉଜ୍ଜ୍ୱଳତା କମ୍ କରନ୍ତୁ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ଭଲ୍ୟୁମ୍ କୀ\'ଗୁଡ଼ିକୁ ଧରି ରଖାଯାଇଛି। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ଚାଲୁ ହୋଇଛି।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ଭଲ୍ୟୁମ୍ କୀ\'ଗୁଡ଼ିକୁ ଧରି ରଖାଯାଇଛି। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ବନ୍ଦ ହୋଇଛି।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ବ୍ୟବହାର କରିବାକୁ ତିନି ସେକେଣ୍ଡ ପାଇଁ ଉଭୟ ଭଲ୍ୟୁମ୍ କୀ ଦବାଇ ଧରି ରଖନ୍ତୁ"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ଫିସିଂ ଆଲର୍ଟ"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"ୱର୍କ ପ୍ରୋଫାଇଲ୍"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"ଆଲର୍ଟ କରାଯାଇଛି"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"ଯାଞ୍ଚ କରାଯାଇଛି"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"ବଢ଼ାନ୍ତୁ"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"ଛୋଟ କରନ୍ତୁ"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"ଟୋଗଲ୍ ସମ୍ପ୍ରସାରଣ"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"ଖବର ଓ ମ୍ୟାଗାଜିନ୍"</string>
<string name="app_category_maps" msgid="6395725487922533156">"ମାନଚିତ୍ର ଓ ନେଭିଗେଶନ୍"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"ଉତ୍ପାଦକତା"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ଡିଭାଇସ୍ ଷ୍ଟୋରେଜ୍"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB ଡିବଗିଂ"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ଘଣ୍ଟା"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ଜାରି ରଖିବାକୁ, <b><xliff:g id="APP">%s</xliff:g></b> ଆପଣଙ୍କ ଡିଭାଇସର କ୍ୟାମେରାକୁ ଆକ୍ସେସ୍ ଆବଶ୍ୟକ କରେ।"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ଚାଲୁ କରନ୍ତୁ"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ସେନ୍ସର୍ ଗୋପନୀୟତା"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"ଆପ୍ଲିକେସନ୍ ଆଇକନ୍"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ଆପ୍ଲିକେସନ୍ ବ୍ରାଣ୍ଡିଂ ଛବି"</string>
</resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index c9f57ef..26861dd 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਟੋ ਸੰਗ੍ਰਹਿ ਨੂੰ ਸੋਧਣ ਦਿੰਦੀ ਹੈ।"</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"ਤੁਹਾਡੇ ਮੀਡੀਆ ਸੰਗ੍ਰਹਿ ਦੇ ਟਿਕਾਣਿਆਂ ਨੂੰ ਪੜ੍ਹਨਾ"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਮੀਡੀਆ ਸੰਗ੍ਰਹਿ ਦੇ ਟਿਕਾਣਿਆਂ ਨੂੰ ਪੜ੍ਹਨ ਦਿੰਦੀ ਹੈ।"</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"ਆਪਣੀ ਪਛਾਣ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ਬਾਇਓਮੈਟ੍ਰਿਕ ਹਾਰਡਵੇਅਰ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ਪ੍ਰਮਾਣੀਕਰਨ ਰੱਦ ਕੀਤਾ ਗਿਆ"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"ਪ੍ਰਮਾਣੀਕਰਨ ਰੱਦ ਕੀਤਾ ਗਿਆ"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"ਕੋਈ ਪਿੰਨ, ਪੈਟਰਨ ਜਾਂ ਪਾਸਵਰਡ ਸੈੱਟ ਨਹੀਂ ਕੀਤਾ ਗਿਆ"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"ਗੜਬੜ ਨੂੰ ਪ੍ਰਮਾਣਿਤ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"ਅਧੂਰਾ ਫਿੰਗਰਪ੍ਰਿਟ ਮਿਲਿਆ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ਫਿੰਗਰਪ੍ਰਿੰਟ \'ਤੇ ਪ੍ਰਕਿਰਿਆ ਨਹੀਂ ਹੋ ਸਕੀ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਗੰਦਾ ਹੈ। ਕਿਰਪਾ ਕਰਕੇ ਇਸਨੂੰ ਸਾਫ਼ ਕਰੋ ਅਤੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ਇਸ ਡੀਵਾਈਸ ਵਿੱਚ ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਨਹੀਂ ਹੈ।"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ਸੈਂਸਰ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"ਉਂਗਲ <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਆਪਣਾ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"ਹੁਣ ਚਿਹਰਾ ਪਛਾਣਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"ਬਹੁਤ ਮਿਲਦਾ-ਜੁਲਦਾ ਹੈ, ਕਿਰਪਾ ਕਰਕੇ ਆਪਣਾ ਅੰਦਾਜ਼ ਬਦਲੋ।"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ਆਪਣਾ ਸਿਰ ਥੋੜਾ ਜਿਹਾ ਝੁਕਾਓ।"</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"ਆਪਣੇ ਸਿਰ ਨੂੰ ਥੋੜ੍ਹਾ ਜਿਹਾ ਝੁਕਾਓ।"</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ਆਪਣਾ ਸਿਰ ਥੋੜਾ ਜਿਹਾ ਝੁਕਾਓ।"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"ਤੁਹਾਡਾ ਚਿਹਰਾ ਲੁਕਾਉਣ ਵਾਲੀ ਕੋਈ ਵੀ ਚੀਜ਼ ਹਟਾਓ।"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ਕਾਲੀ ਪੱਟੀ ਸਮੇਤ, ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਸਿਖਰ ਨੂੰ ਸਾਫ਼ ਕਰੋ"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"ਇਸ ਡੀਵਾਈਸ ਵਿੱਚ ਚਿਹਰਾ ਅਣਲਾਕ ਦੀ ਸੁਵਿਧਾ ਨਹੀਂ ਹੈ।"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"ਸੈਂਸਰ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
<string name="face_name_template" msgid="3877037340223318119">"ਚਿਹਰਾ <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"ਚਿਹਰਾ ਪ੍ਰਤੀਕ"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ਸ਼ਾਰਟਕੱਟ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"ਰੰਗ ਪਲਟਨਾ"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"ਰੰਗ ਸੁਧਾਈ"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"ਚਮਕ ਘਟਾਓ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ਅਵਾਜ਼ੀ ਕੁੰਜੀਆਂ ਦਬਾ ਕੇ ਰੱਖੀਆਂ ਗਈਆਂ। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਗਿਆ।"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ਅਵਾਜ਼ੀ ਕੁੰਜੀਆਂ ਦਬਾ ਕੇ ਰੱਖੀਆਂ ਗਈਆਂ। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਦੋਵੇਂ ਅਵਾਜ਼ ਕੁੰਜੀਆਂ ਨੂੰ 3 ਸਕਿੰਟਾਂ ਲਈ ਦਬਾਈ ਰੱਖੋ"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ਫ਼ਿਸ਼ਿੰਗ ਸੰਬੰਧੀ ਸੁਚੇਤਨਾ"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"ਸੁਚੇਤਨਾਵਾਂ"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"ਪੁਸ਼ਟੀਕਿਰਤ"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"ਵਿਸਤਾਰ ਕਰੋ"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"ਸੁੰਗੇੜੋ"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"ਟੌਗਲ ਵਿਸਤਾਰ"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"ਖਬਰਾਂ ਅਤੇ ਰਸਾਲੇ"</string>
<string name="app_category_maps" msgid="6395725487922533156">"ਨਕਸ਼ੇ ਅਤੇ ਆਵਾਗੌਣ"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"ਉਤਪਾਦਕਤਾ"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ਡੀਵਾਈਸ ਸਟੋਰੇਜ"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB ਡੀਬੱਗਿੰਗ"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ਘੰਟਾ"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"ਜਾਰੀ ਰੱਖਣ ਲਈ, <b><xliff:g id="APP">%s</xliff:g></b> ਨੂੰ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੇ ਕੈਮਰਾ ਤੱਕ ਪਹੁੰਚ ਦੀ ਲੋੜ ਹੈ।"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ਚਾਲੂ ਕਰੋ"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ਸੈਂਸਰ ਪਰਦੇਦਾਰੀ"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"ਐਪਲੀਕੇਸ਼ਨ ਪ੍ਰਤੀਕ"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ਐਪਲੀਕੇਸ਼ਨ ਦਾ ਬ੍ਰਾਂਡ ਵਾਲਾ ਚਿੱਤਰ"</string>
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 6c12366..01bf276 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -556,13 +556,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Zezwala aplikacji na modyfikowanie kolekcji zdjęć."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"odczytywanie lokalizacji z kolekcji multimediów"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Zezwala aplikacji na odczytywanie lokalizacji z kolekcji multimediów."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Potwierdź swoją tożsamość"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Sprzęt biometryczny niedostępny"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Anulowano uwierzytelnianie"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nie rozpoznano"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Anulowano uwierzytelnianie"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nie ustawiono kodu PIN, wzoru ani hasła"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Podczas uwierzytelniania wystąpił błąd"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Odcisk palca został odczytany tylko częściowo. Spróbuj ponownie."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Nie udało się przetworzyć odcisku palca. Spróbuj ponownie."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Czytnik linii papilarnych jest zabrudzony. Wyczyść go i spróbuj ponownie."</string>
@@ -585,6 +595,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"To urządzenie nie jest wyposażone w czytnik linii papilarnych."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Czujnik jest tymczasowo wyłączony."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Odcisk palca <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Użyj odcisku palca, by kontynuować"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -612,8 +626,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Nie można już rozpoznać twarzy. Spróbuj ponownie."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Za mała różnica. Zmień pozycję."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Trochę mniej obróć głowę."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Trochę mniej pochyl głowę."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Trochę mniej obróć głowę."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Usuń wszystko, co zasłania Ci twarz."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Wyczyść górną krawędź ekranu, w tym czarny pasek"</string>
@@ -631,6 +644,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"To urządzenie nie obsługuje rozpoznawania twarzy."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Czujnik jest tymczasowo wyłączony."</string>
<string name="face_name_template" msgid="3877037340223318119">"Twarz <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Ikona twarzy"</string>
@@ -1712,8 +1731,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Użyj skrótu"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Odwrócenie kolorów"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Korekcja kolorów"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Zmniejsz jasność"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Przytrzymano klawisze głośności. Usługa <xliff:g id="SERVICE_NAME">%1$s</xliff:g> została włączona."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Przytrzymano klawisze głośności. Usługa <xliff:g id="SERVICE_NAME">%1$s</xliff:g> została wyłączona."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Naciśnij i przytrzymaj oba przyciski głośności przez trzy sekundy, by użyć usługi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1938,6 +1956,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alert o phishingu"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profil służbowy"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Alert"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Zweryfikowano"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Rozwiń"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Zwiń"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"przełącz rozwijanie"</string>
@@ -2011,6 +2030,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Wiadomości i czasopisma"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Mapy i nawigacja"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produktywność"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Pamięć urządzenia"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Debugowanie USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"godz."</string>
@@ -2289,8 +2310,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Aby kontynuować, musisz przyznać aplikacji „<xliff:g id="APP">%s</xliff:g>” dostęp do aparatu urządzenia."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Włącz"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Poufność danych z czujników"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Ikona aplikacji"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Wizerunek marki aplikacji"</string>
</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index d5cec26..aa693582f 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que o app modifique sua coleção de fotos."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"ler locais na sua coleção de mídias"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que o app leia os locais na sua coleção de mídias."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirme que é você"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biométrico indisponível"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticação cancelada"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Não reconhecido"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autenticação cancelada"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nenhum PIN, padrão ou senha configurado"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Erro na autenticação"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Impressão digital parcial detectada. Tente novamente."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Não foi possível processar a impressão digital. Tente novamente."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"O sensor de impressão digital está sujo. Limpe-o e tente novamente."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem um sensor de impressão digital."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor desativado temporariamente."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Use sua impressão digital para continuar"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"O rosto não é mais reconhecido. Tente novamente."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Muito parecido, mude de posição."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Incline a cabeça um pouco menos."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Incline a cabeça um pouco menos."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Incline a cabeça um pouco menos."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Remova tudo que esteja ocultando seu rosto."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpe a parte superior da tela, inclusive a barra preta"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"O desbloqueio facial não é compatível com este dispositivo."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor desativado temporariamente."</string>
<string name="face_name_template" msgid="3877037340223318119">"Rosto <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Ícone facial"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Usar atalho"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversão de cores"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Correção de cor"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Reduzir brilho"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume pressionadas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume pressionadas. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Toque nos dois botões de volume e os mantenha pressionados por três segundo para usar o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerta de phishing"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de trabalho"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Alertado"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Verificada"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Expandir"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Recolher"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"alternar expansão"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Notícias e revistas"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Mapas e navegação"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produtividade"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Armazenamento do dispositivo"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Depuração USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"hora"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Para continuar, o app <b><xliff:g id="APP">%s</xliff:g></b> precisa acessar a câmera do dispositivo."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Ativar"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacidade do sensor"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Ícone do aplicativo"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imagem da marca do aplicativo"</string>
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 6867950..232a1721 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -261,7 +261,7 @@
<item quantity="one">A tirar uma captura de ecrã do relatório de erro dentro de <xliff:g id="NUMBER_0">%d</xliff:g> segundo…</item>
</plurals>
<string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Captura de ecrã tirada com o relatório de erro."</string>
- <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Falha ao tirar captura de ecrã com o relatório de erro."</string>
+ <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Falha ao fazer captura de ecrã com o relatório de erro."</string>
<string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencioso"</string>
<string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Som desativado"</string>
<string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"O som está ativado"</string>
@@ -335,7 +335,7 @@
<string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"É possível tocar, deslizar rapidamente, juntar os dedos e realizar outros gestos"</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Gestos de impressão digital"</string>
<string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Pode capturar gestos realizados no sensor de impressões digitais do dispositivo."</string>
- <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Tirar captura de ecrã"</string>
+ <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Fazer captura de ecrã"</string>
<string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"É possível tirar uma captura de ecrã."</string>
<string name="permlab_statusBar" msgid="8798267849526214017">"desativar ou modificar barra de estado"</string>
<string name="permdesc_statusBar" msgid="5809162768651019642">"Permite à app desativar a barra de estado ou adicionar e remover ícones do sistema."</string>
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que a app modifique a sua coleção de fotos."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"ler as localizações a partir da sua coleção de multimédia"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que a app leia as localizações a partir da sua coleção de multimédia."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirme a sua identidade"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biométrico indisponível."</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticação cancelada"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Não reconhecido."</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autenticação cancelada"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nenhum PIN, padrão ou palavra-passe definidos."</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Erro ao autenticar."</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Impressão digital parcial detetada. Tente novamente."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Não foi possível processar a impressão digital. Tente novamente."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"O sensor de impressões digitais está sujo. Limpe-o e tente novamente."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem sensor de impressões digitais."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporariamente desativado."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utilize a sua impressão digital para continuar."</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Impossível reconhecer o rosto. Tente novamente."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Muito parecida, mude de pose."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Rode a cabeça um pouco menos."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Incline a cabeça um pouco menos."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Rode a cabeça um pouco menos."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Remova tudo o que esteja a ocultar o seu rosto."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpe a parte superior do ecrã, incluindo a barra preta."</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Desbloqueio facial não suportado neste dispositivo."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporariamente desativado."</string>
<string name="face_name_template" msgid="3877037340223318119">"Rosto <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Ícone de rosto"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilizar atalho"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversão de cores"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Correção da cor"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Reduza o brilho"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas do volume premidas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume premidas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Prima sem soltar as teclas de volume durante três segundos para utilizar o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerta de phishing."</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de trabalho"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Alertado"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Validada"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Expandir"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Reduzir"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"ativar/desativar expansão"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Notícias e revistas"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Mapas e navegação"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produtividade"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Armazenamento do dispositivo"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Depuração USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"hora"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Para continuar, a app <b><xliff:g id="APP">%s</xliff:g></b> precisa de acesso à câmara do dispositivo."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Ativar"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacidade dos sensores"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Ícone de aplicação."</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imagem de branding da aplicação."</string>
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index d5cec26..aa693582f 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que o app modifique sua coleção de fotos."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"ler locais na sua coleção de mídias"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que o app leia os locais na sua coleção de mídias."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirme que é você"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biométrico indisponível"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autenticação cancelada"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Não reconhecido"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autenticação cancelada"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nenhum PIN, padrão ou senha configurado"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Erro na autenticação"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Impressão digital parcial detectada. Tente novamente."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Não foi possível processar a impressão digital. Tente novamente."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"O sensor de impressão digital está sujo. Limpe-o e tente novamente."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem um sensor de impressão digital."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor desativado temporariamente."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Use sua impressão digital para continuar"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"O rosto não é mais reconhecido. Tente novamente."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Muito parecido, mude de posição."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Incline a cabeça um pouco menos."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Incline a cabeça um pouco menos."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Incline a cabeça um pouco menos."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Remova tudo que esteja ocultando seu rosto."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Limpe a parte superior da tela, inclusive a barra preta"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"O desbloqueio facial não é compatível com este dispositivo."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor desativado temporariamente."</string>
<string name="face_name_template" msgid="3877037340223318119">"Rosto <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Ícone facial"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Usar atalho"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversão de cores"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Correção de cor"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Reduzir brilho"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume pressionadas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume pressionadas. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Toque nos dois botões de volume e os mantenha pressionados por três segundo para usar o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerta de phishing"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de trabalho"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Alertado"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Verificada"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Expandir"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Recolher"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"alternar expansão"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Notícias e revistas"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Mapas e navegação"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produtividade"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Armazenamento do dispositivo"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Depuração USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"hora"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Para continuar, o app <b><xliff:g id="APP">%s</xliff:g></b> precisa acessar a câmera do dispositivo."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Ativar"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacidade do sensor"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Ícone do aplicativo"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imagem da marca do aplicativo"</string>
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 690884a..01daa55 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -553,13 +553,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite aplicației să vă modifice colecția de fotografii."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"citiți locațiile din colecția media"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite aplicației să citească locațiile din colecția dvs. media."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirmați-vă identitatea"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biometric indisponibil"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentificarea a fost anulată"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nu este recunoscut"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentificarea a fost anulată"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nu este setat niciun cod PIN, model sau parolă"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Eroare la autentificare"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"S-a detectat parțial amprenta. Încercați din nou."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Amprenta nu a putut fi procesată. Încercați din nou."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Senzorul pentru amprente este murdar. Curățați-l și încercați din nou."</string>
@@ -582,6 +592,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dispozitivul nu are senzor de amprentă."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzorul este dezactivat temporar."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Degetul <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Folosiți amprenta pentru a continua"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -609,8 +623,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Nu se mai poate recunoaște fața. Încercați din nou."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Prea asemănător, schimbați poziția."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Întoarceți capul mai puțin."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Înclinați capul mai puțin."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Întoarceți capul mai puțin."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Eliminați orice vă ascunde chipul."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Curățați partea de sus a ecranului, inclusiv bara neagră"</string>
@@ -628,6 +641,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Deblocarea facială nu este acceptată pe dispozitiv."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Senzorul este dezactivat temporar."</string>
<string name="face_name_template" msgid="3877037340223318119">"Chip <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Pictograma chip"</string>
@@ -1690,8 +1709,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilizați comanda rapidă"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inversarea culorilor"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Corecția culorii"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Reduceți luminozitatea"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"S-au apăsat lung tastele de volum. S-a activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"S-au apăsat lung tastele de volum. S-a dezactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Apăsați ambele butoane de volum timp de trei secunde pentru a folosi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1907,6 +1925,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alertă privind phishingul"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profil de serviciu"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Notificat"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Confirmat"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Extindeți"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Restrângeți"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"extindeți/restrângeți"</string>
@@ -1979,6 +1998,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Știri și reviste"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Hărți și navigare"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Productivitate"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Stocare pe dispozitiv"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Remedierea erorilor prin USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"oră"</string>
@@ -2255,8 +2276,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Pentru a continua, <b><xliff:g id="APP">%s</xliff:g></b> necesită acces la camera dispozitivului."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Activați"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Confidențialitatea privind senzorii"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Pictograma aplicației"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imaginea de branding a aplicației"</string>
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 84752d5..1a513e4 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -556,13 +556,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Приложение сможет вносить изменения в вашу фотоколлекцию."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"доступ к геоданным в медиаколлекции"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Приложение получит доступ к геоданным в вашей медиаколлекции."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Подтвердите, что это вы"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрическое оборудование недоступно"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Аутентификация отменена"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Не распознано"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Аутентификация отменена"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Укажите PIN-код, пароль или графический ключ"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Ошибка аутентификации."</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Отсканирована только часть отпечатка. Повторите попытку."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Не удалось распознать отпечаток. Повторите попытку."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Очистите сканер и повторите попытку."</string>
@@ -585,6 +595,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На этом устройстве нет сканера отпечатков пальцев."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сканер отпечатков пальцев временно отключен."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Отпечаток <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Чтобы продолжить, используйте цифровой отпечаток"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -612,8 +626,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Не удалось распознать лицо. Повторите попытку."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Слишком похожее выражение лица. Измените позу."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Держите голову ровнее."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Не наклоняйте голову слишком сильно."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Держите голову ровнее."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Ваше лицо плохо видно."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Протрите верхнюю часть экрана (в том числе черную панель)."</string>
@@ -631,6 +644,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Это устройство не поддерживает функцию \"Фейсконтроль\"."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Датчик временно отключен."</string>
<string name="face_name_template" msgid="3877037340223318119">"Лицо <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Значок лица"</string>
@@ -1712,8 +1731,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Использовать быстрое включение"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Инверсия цветов"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Коррекция цвета"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Уменьшение яркости"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Использован жест с кнопками регулировки громкости. Функция \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\" включена."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Использован жест с кнопками регулировки громкости. Функция \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\" отключена."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Чтобы использовать сервис \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\", нажмите и удерживайте обе клавиши громкости в течение трех секунд."</string>
@@ -1938,6 +1956,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Предупреждение о фишинге"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Рабочий профиль"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Отправлено оповещение"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Подтверждено"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Развернуть"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Скрыть"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"Свернуть или развернуть"</string>
@@ -2011,6 +2030,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Новости и журналы"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Карты и навигация"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Работа"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Хранилище устройства"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Отладка по USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ч."</string>
@@ -2289,8 +2310,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Чтобы продолжить, предоставьте приложению <b><xliff:g id="APP">%s</xliff:g></b> доступ к камере устройства."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Включить"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Конфиденциальность датчиков"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Значок приложения"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Образ бренда приложения"</string>
</resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 66547de..e01a1c4 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -550,13 +550,18 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"ඔබගේ ඡායාරූප එකතුව වෙනස් කිරීමට යෙදුමට ඉඩ දෙයි."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"ඔබගේ මාධ්ය එකතුවෙන් ස්ථාන කියවන්න"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"ඔබගේ මාධ්ය එකතුවෙන් ස්ථාන කියවීමට යෙදුමට ඉඩ දෙයි."</string>
+ <string name="biometric_app_setting_name" msgid="3339209978734534457">"ජෛවමිතික භාවිත කරන්න"</string>
+ <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ජෛවමිතික හෝ තිර අගුල භාවිත කරන්න"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"එය ඔබ බව තහවුරු කරන්න"</string>
+ <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"ඉදිරියට යාමට ඔබගේ ජෛවමිතික භාවිත කරන්න"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ජීවමිතික දෘඪාංග ලබා ගත නොහැකිය"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"සත්යාපනය අවලංගු කළා"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"හඳුනා නොගන්නා ලදී"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"සත්යාපනය අවලංගු කළා"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"රහස් අංක, රටා, හෝ මුරපද කිසිවක් සකසා නැත"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"සත්යාපනය කිරීමේ දෝෂයකි"</string>
+ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"තිර අගුල භාවිත කරන්න"</string>
+ <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"ඉදිරියට යාමට ඔබගේ උපාංග අක්තපත්ර ඇතුළු කරන්න"</string>
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"ඇඟිලි සලකුණ අඩ වශයෙන් අනාවරණය කර ගැනිණි. කරුණාකර නැවත උත්සාහ කරන්න."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ඇඟිලි සලකුණ පිරිසැකසීමට නොහැකි විය. කරුණාකර නැවත උත්සාහ කරන්න."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"ඇඟිලි සලකුණු සංවේදකය අපිරිසිදුයි. කරුණාකර පිරිසිදු කර නැවත උත්සාහ කරන්න."</string>
@@ -579,6 +584,8 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"මෙම උපාංගයේ ඇඟිලි සලකුණු සංවේදකයක් නොමැත."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"සංවේදකය තාවකාලිකව අබල කර ඇත."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"ඇඟිලි <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ඇඟිලි සලකුණ භාවිත කරන්න"</string>
+ <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ඇඟිලි සලකුණ හෝ තිර අගුල භාවිත කරන්න"</string>
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ඉදිරියට යාමට ඔබගේ ඇඟිලි සලකුණ භාවිත කරන්න"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +613,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"තවදුරටත් මුහුණ හඳුනාගත නොහැක. නැවත උත්සාහ කරන්න."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"ඉතා සමානයි, ඔබේ හැඩ ගැසීම වෙනස් කරන්න."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"ඔබේ හිස ටිකක් අඩුවෙන් කරකවන්න."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"ඔබගේ හිස ටිකක් අඩුවෙන් ඇල කරන්න."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"ඔබේ හිස ටිකක් අඩුවෙන් කරකවන්න."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"ඔබේ මුහුණ සඟවන කිසිවක් ඉවත් කරන්න."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"කලු තීරුව ඇතුළුව, ඔබේ තිරයෙහි මුදුන පිරිසිදු කරන්න"</string>
@@ -625,6 +631,9 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"මෙම උපාංගයෙහි මුහුණු අඟුලු ඇරීමට සහය නොදැක්වේ"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"සංවේදකය තාවකාලිකව අබල කර ඇත."</string>
<string name="face_name_template" msgid="3877037340223318119">"මුහුණු <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string name="face_app_setting_name" msgid="8130135875458467243">"මුහුණු අගුලු හැරීම භාවිත කරන්න"</string>
+ <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"මුහුණු අගුලු හැරීම හෝ තිර අගුල භාවිත කරන්න"</string>
+ <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"ඉදිරියට යාමට මුහුණු අගුලු හැරීම භාවිත කරන්න"</string>
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"මුහුණ නිරූපකය"</string>
@@ -1668,8 +1677,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"කෙටිමඟ භාවිතා කරන්න"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"වර්ණ අපවර්තනය"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"වර්ණ නිවැරදි කිරීම"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"දීප්තිය අඩු කරන්න"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"හඬ පරිමා යතුරු අල්ලා ගන්න <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්රියාත්මකයි."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"හඬ පරිමා යතුරු අල්ලා ගන්න <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්රියාවිරහිතයි."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> භාවිත කිරීමට හඬ පරිමා යතුරු දෙකම තත්පර තුනකට ඔබාගෙන සිටින්න"</string>
@@ -1876,6 +1884,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"තතුබෑම් ඇඟවීම"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"කාර්යාල පැතිකඩ"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"අනතුරු අඟවන ලදී"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"සත්යාපිතයි"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"දිග හරින්න"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"හකුළන්න"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"පුළුල් කිරීම ටොගල කරන්න"</string>
@@ -1947,6 +1956,7 @@
<string name="app_category_news" msgid="1172762719574964544">"පුවත් සහ සඟරා"</string>
<string name="app_category_maps" msgid="6395725487922533156">"සිතියම් සහ සංචලනය"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"ඵලදායිතාව"</string>
+ <string name="app_category_accessibility" msgid="6643521607848547683">"ප්රවේශ්යතාව"</string>
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"උපාංග ගබඩාව"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB නිදොස්කරණය"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"පැය"</string>
@@ -2221,8 +2231,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"දිගටම කර ගෙන යාමට, <b><xliff:g id="APP">%s</xliff:g></b> හට ඔබගේ උපාංගයෙහි කැමරාවට ප්රවේශය අවශ්යයි."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ක්රියාත්මක කරන්න"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"සංවේදක පෞද්ගලිකත්වය"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"යෙදුම් නිරූපකය"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"යෙදුම් සන්නම් කිරීමේ රූපය"</string>
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 487b818..011b042 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -556,13 +556,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Umožňuje aplikácii upravovať zbierku fotiek."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"čítať polohy zo zbierky médií"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Umožňuje aplikácii čítať polohy zo zbierky médií."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Overenie, že ste to vy"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrický hardvér nie je k dispozícii"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Overenie bolo zrušené"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nerozpoznané"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Overenie bolo zrušené"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nie je nastavený PIN, vzor ani heslo"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Chyba overenia"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Podarilo sa rozpoznať iba časť odtlačku prsta. Skúste to znova."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Odtlačok prsta sa nepodarilo spracovať. Skúste to znova."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Očistite senzor odtlačkov prstov a skúste to znova."</string>
@@ -585,6 +595,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Toto zariadenie nemá senzor odtlačkov prstov."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je dočasne vypnutý."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Prst: <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Pokračujte nasnímaním odtlačku prsta"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -612,8 +626,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Tvár už nie je možné rozpoznať. Skúste to znova."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Príliš rovnaké, zmeňte postoj."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Otočte hlavu o niečo menej."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Nakloňte hlavu trocha menej."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Otočte hlavu o niečo menej."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Odstráňte všetko, čo vám zakrýva tvár."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Vyčistite hornú časť obrazovky vrátane čierneho panela"</string>
@@ -631,6 +644,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Toto zariadenie nepodporuje odomknutie tvárou."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je dočasne vypnutý."</string>
<string name="face_name_template" msgid="3877037340223318119">"Tvár <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Ikona tváre"</string>
@@ -1712,8 +1731,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Použiť skratku"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzia farieb"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Úprava farieb"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Zníženie jasu"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Pridržali ste tlačidlá hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je zapnutá."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Pridržali ste tlačidlá hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je vypnutá."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Ak chcete používať službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, pridržte tri sekundy oba klávesy hlasitosti"</string>
@@ -1938,6 +1956,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Upozornenie na phishing"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Pracovný profil"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Upozornené"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Overené"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Rozbaliť"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Zbaliť"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"prepnúť rozbalenie"</string>
@@ -2011,6 +2030,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Noviny a časopisy"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Mapy a navigácia"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Kancelárske"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Úložisko zariadenia"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Ladenie cez USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"hodina"</string>
@@ -2289,8 +2310,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Ak chcete pokračovať, <b><xliff:g id="APP">%s</xliff:g></b> požaduje prístup k fotoaparátu zariadenia."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Zapnúť"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Ochrana súkromia senzorov"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Ikona aplikácie"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imidž značky aplikácie"</string>
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 87a66b3..0a7f760 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -556,13 +556,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Aplikaciji omogoča spreminjanje zbirke fotografij."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"branje lokacij v predstavnostni zbirki"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Aplikaciji omogoča branje lokacij v predstavnostni zbirki."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Preverite, da ste res vi"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Strojna oprema za biometrične podatke ni na voljo"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Preverjanje pristnosti je preklicano"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Ni prepoznano"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Preverjanje pristnosti je preklicano"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nastavljena ni nobena koda PIN, vzorec ali geslo"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Napaka pri preverjanju pristnosti"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Zaznan delni prstni odtis. Poskusite znova."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Prstnega odtisa ni bilo mogoče obdelati. Poskusite znova."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Tipalo prstnih odtisov je umazano. Očistite ga in poskusite znova."</string>
@@ -585,6 +595,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ta naprava nima tipala prstnih odtisov."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Tipalo je začasno onemogočeno."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Uporabite prstni odtis, če želite nadaljevati."</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -612,8 +626,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Obraza ni več mogoče prepoznati. Poskusite znova."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Preveč podobno, spremenite položaj."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Glejte malce bolj naravnost."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Obraz nastavite bolj naravnost."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Glejte malce bolj naravnost."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Umaknite vse, kar vam morda zakriva obraz."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Očistite vrhnji del zaslona, vključno s črno vrstico"</string>
@@ -631,6 +644,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Ta naprava ne podpira odklepanja z obrazom."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Tipalo je začasno onemogočeno."</string>
<string name="face_name_template" msgid="3877037340223318119">"Obraz <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Ikona obraza"</string>
@@ -1712,8 +1731,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Uporabi bližnjico"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzija barv"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Popravljanje barv"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Zmanjšanje svetlosti"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tipki za glasnost sta pridržani. Storitev <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je vklopljena."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tipki za glasnost sta pridržani. Storitev <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je izklopljena."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Za uporabo storitve <xliff:g id="SERVICE_NAME">%1$s</xliff:g> pritisnite obe tipki za glasnost in ju pridržite tri sekunde"</string>
@@ -1938,6 +1956,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Opozorilo o lažnem predstavljanju"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Delovni profil"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Opozorilo prikazano"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Preverjeno"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Razširi"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Strni"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"preklop razširitve"</string>
@@ -2011,6 +2030,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Novice in revije"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Zemljevidi in navigacija"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Storilnost"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Shramba naprave"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Odpravljanje težav prek povezave USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ura"</string>
@@ -2289,8 +2310,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Za nadaljevanje potrebuje aplikacija <b><xliff:g id="APP">%s</xliff:g></b> dostop do fotoaparata v napravi."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Vklopi"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Zasebnost pri uporabi tipal"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Ikona aplikacije"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Podoba blagovne znamke aplikacije"</string>
</resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 4c37424..ddce26d 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Lejon aplikacionin të modifikojë koleksionin tënd të fotografive."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"lexo vendndodhjet nga koleksioni yt i medias"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Lejon aplikacionin të lexojë vendndodhjet nga koleksioni yt i medias."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifiko që je ti"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Nuk ofrohet harduer biometrik"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Vërtetimi u anulua"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Nuk njihet"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Vërtetimi u anulua"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nuk është vendosur kod PIN, motiv ose fjalëkalim"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Gabim gjatë vërtetimit"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"U zbulua një gjurmë gishti e pjesshme. Provo përsëri."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Gjurma e gishtit nuk mund të përpunohej. Provo përsëri."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Sensori i gjurmës së gishtit nuk është i pastër. Pastroje dhe provo përsëri."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Kjo pajisje nuk ka sensor të gjurmës së gishtit."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensori është çaktivizuar përkohësisht."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Gishti <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Përdor gjurmën e gishtit për të vazhduar"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Fytyra nuk mund të njihet më. Provo përsëri."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Tepër e ngjashme, ndrysho pozën"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Ktheje kokën pak më pak."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Anoje kokën më pak."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Ktheje kokën pak më pak."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Hiq gjithçka që fsheh fytyrën tënde."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Pastro kreun e ekranit, duke përfshirë shiritin e zi"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Shkyçja me fytyrë nuk mbështetet në këtë pajisje"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensori është çaktivizuar përkohësisht."</string>
<string name="face_name_template" msgid="3877037340223318119">"Fytyra <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Ikona e fytyrës"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Përdor shkurtoren"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Kthimi i ngjyrës"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Korrigjimi i ngjyrës"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Redukto ndriçimin"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tastet e volumit të mbajtura shtypur. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> i aktivizuar."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tastet e volumit të mbajtura shtypur. U çaktivizua \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\"."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Shtyp dhe mbaj shtypur të dy butonat e volumit për tre sekonda për të përdorur <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Sinjalizim për mashtrim"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profili i punës"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Sinjalizuar"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"U verifikua"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Zgjero"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Palos"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"aktivizo zgjerimin"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Lajme dhe revista"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Harta dhe navigim"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produktivitet"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Hapësira ruajtëse e pajisjes"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Korrigjimi përmes USB-së"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"orë"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Për të vazhduar, <b><xliff:g id="APP">%s</xliff:g></b> ka nevojë të qaset në kamerën e pajisjes sate."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Aktivizo"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privatësia e sensorit"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Ikona e aplikacionit"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imazhi i vendosjes së aplikacionit të markës"</string>
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index d061d6f..11d5e7d 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -553,13 +553,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Дозвољава апликацији да мења колекцију слика."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"читање локација из медијске колекције"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Дозвољава апликацији да чита локације из медијске колекције."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Потврдите свој идентитет"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометријски хардвер није доступан"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Потврда идентитета је отказана"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Није препознато"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Потврда идентитета је отказана"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Нисте подесили ни PIN, ни шаблон, ни лозинку"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Грешка при потврди идентитета"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Откривен је делимични отисак прста. Пробајте поново."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Није успела обрада отиска прста. Пробајте поново."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Сензор за отиске прстију је прљав. Очистите га и покушајте поново."</string>
@@ -582,6 +592,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Овај уређај нема сензор за отисак прста."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензор је привремено онемогућен."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Прст <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Наставите помоћу отиска прста"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -609,8 +623,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Више не може да се препозна лице. Пробајте поново."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Превише је слично, промените позу."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Мало мање померите главу."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Мало мање нагните главу."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Мало мање померите главу."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Уклоните све што вам заклања лице."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Очистите горњи део екрана, укључујући црну траку"</string>
@@ -628,6 +641,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Откључавање лицем није подржано на овом уређају"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Сензор је привремено онемогућен."</string>
<string name="face_name_template" msgid="3877037340223318119">"Лице <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Икона лица"</string>
@@ -1690,8 +1709,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Користи пречицу"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Инверзија боја"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Корекција боја"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Смањите осветљеност"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Држали сте тастере за јачину звука. Услуга <xliff:g id="SERVICE_NAME">%1$s</xliff:g> је укључена."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Држали сте тастере за јачину звука. Услуга <xliff:g id="SERVICE_NAME">%1$s</xliff:g> је искључена."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Притисните и задржите оба тастера за јачину звука три секунде да бисте користили <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1907,6 +1925,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Упозорење о „пецању“"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Пословни профил"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Обавештено"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Верификовано"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Прошири"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Скупи"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"укључите/искључите проширење"</string>
@@ -1979,6 +1998,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Новости и часописи"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Мапе и навигација"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Продуктивност"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Меморијски простор уређаја"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Отклањање грешака са USB-а"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"сат"</string>
@@ -2255,8 +2276,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"<b><xliff:g id="APP">%s</xliff:g></b> захтева приступ камери уређаја ради настављања."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Укључи"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Приватност сензора"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Икона апликације"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Имиџ бренда апликације"</string>
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 8288d41..4f6ccff5 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Tillåter att appen gör ändringar i din fotosamling."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"läsa av platser i din mediesamling"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Tillåter att appen läser av platser i din mediesamling."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifiera din identitet"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrisk maskinvara är inte tillgänglig"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentiseringen avbröts"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Identifierades inte"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentiseringen avbröts"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Pinkod, grafiskt lösenord eller lösenord har inte angetts"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Ett fel uppstod vid autentiseringen"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Ofullständigt fingeravtryck. Försök igen."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Det gick inte att bearbeta fingeravtrycket. Försök igen."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingeravtryckssensorn är smutsig. Rengör den och försök igen."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Enheten har ingen fingeravtryckssensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensorn har tillfälligt inaktiverats."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Fortsätt med hjälp av ditt fingeravtryck"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Ansiktet kan inte längre kännas igen. Försök igen."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"För likt. Ändra ansiktsposition."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Vrid mindre på huvudet."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Vinkla huvudet mindre."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Vrid mindre på huvudet."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Ta bort allt som täcker ansiktet."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Rengör skärmens överkant, inklusive det svarta fältet"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Ansiktslås stöds inte på den här enheten."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensorn har tillfälligt inaktiverats."</string>
<string name="face_name_template" msgid="3877037340223318119">"Ansikte <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Ansikte"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Använd kortkommandot"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Inverterade färger"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Färgkorrigering"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Minska ljusstyrkan"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Volymknapparna har tryckts ned. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> har aktiverats."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Volymknapparna har tryckts ned. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> har inaktiverats."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Tryck och håll båda volymknapparna i tre sekunder för att använda <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Varning om nätfiske"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Jobbprofil"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Aviserad"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Verifierat"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Utöka"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Komprimera"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"Utöka/komprimera"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Nyheter och tidskrifter"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Kartor och navigation"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Produktivitet"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Enhetens lagringsutrymme"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-felsökning"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"timme"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"<b><xliff:g id="APP">%s</xliff:g></b> behöver behörighet till enhetens kamera för att fortsätta."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Aktivera"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensorintegritet"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Appikon"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Appens varumärkesbild"</string>
</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 6ac7d2a..8dd721f 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Inaruhusu programu kubadilisha mkusanyiko wa picha zako."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"kusoma maeneo kwenye mkusanyiko wa vipengee vyako"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Inaruhusu programu kusoma maeneo kwenye mkusanyiko wa vipengee vyako."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Thibitisha kuwa ni wewe"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Maunzi ya bayometriki hayapatikani"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Imeghairi uthibitishaji"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Hayatambuliki"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Imeghairi uthibitishaji"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Hujaweka pin, mchoro au nenosiri"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Hitilafu imetokea wakati wa uthibitishaji"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Kitambua alama kimetambua sehemu ya alama. Tafadhali jaribu tena."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Imeshindwa kuchakata alama ya kidole. Tafadhali jaribu tena."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Kitambua alama ya kidole ni kichafu. Tafadhali kisafishe na ujaribu tena."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Kifaa hiki hakina kitambua alama ya kidole."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Kitambuzi kimezimwa kwa muda."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Kidole cha <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Tumia alama ya kidole chako ili uendelee"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Haiwezi tena kutambua uso. Jaribu tena."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Inafanana sana, tafadhali badilisha mkao wako."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Geuza kichwa chako kidogo."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Inamisha kichwa chako kiasi."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Geuza kichwa chako kidogo."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Ondoa kitu chochote kinachoficha uso wako."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Safisha sehemu ya juu ya skrini yako, ikiwa ni pamoja na upau mweusi"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Kufungua kwa uso hakutumiki kwenye kifaa hiki."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Kitambuzi kimezimwa kwa muda."</string>
<string name="face_name_template" msgid="3877037340223318119">"Uso wa <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Aikoni ya uso"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Tumia Njia ya Mkato"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Ugeuzaji rangi"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Usahihishaji wa rangi"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Punguza ung\'aavu"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Vitufe vya sauti vilivyoshikiliwa. Umewasha <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Vitufe vya sauti vimeshikiliwa. Umezima <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Bonyeza na ushikilie vitufe vyote viwili vya sauti kwa sekunde tatu ili utumie <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Arifa ya wizi wa data binafsi"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Wasifu wa kazini"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Imearifu"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Imethibitishwa"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Panua"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Kunja"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"geuza upanuzi"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Habari na Magazeti"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Ramani na Maelekezo"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Uzalishaji"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Hifadhi ya kifaa"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Utatuzi wa USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"saa"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Ili uendelee, <b><xliff:g id="APP">%s</xliff:g></b> inahitaji ruhusa ya kufikia kamera ya kifaa chako."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Washa"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Faragha ya Kitambuzi"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Aikoni ya programu"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Picha ya kuweka chapa kwenye programu"</string>
</resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 1ac1734..3760c6d 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"உங்களின் படத் தொகுப்பை மாற்ற ஆப்ஸை அனுமதிக்கும்."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"மீடியா தொகுப்பிலிருந்து இடங்களை அறிதல்"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"உங்களின் மீடியா தொகுப்பிலிருந்து இடங்களை அறிந்துகொள்ள ஆப்ஸை அனுமதிக்கும்."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"நீங்கள்தான் என உறுதிசெய்க"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"பயோமெட்ரிக் வன்பொருள் இல்லை"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"அங்கீகரிப்பு ரத்தானது"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"அடையாளங்காணபடவில்லை"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"அங்கீகரிப்பு ரத்தானது"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"பின்னோ, பேட்டர்னோ, கடவுச்சொல்லோ அமைக்கப்படவில்லை"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"அங்கீகரிப்பதில் பிழை"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"கைரேகையை ஓரளவுதான் கண்டறிய முடிந்தது. மீண்டும் முயலவும்."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"கைரேகையைச் செயலாக்க முடியவில்லை. மீண்டும் முயலவும்."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"கைரேகை சென்சாரில் தூசி உள்ளது. சுத்தம் செய்து, முயலவும்."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"இந்தச் சாதனத்தில் கைரேகை சென்சார் இல்லை."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"சென்சார் தற்காலிகமாக முடக்கப்பட்டுள்ளது."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"கைரேகை <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"தொடர்வதற்கு கைரேகையைப் பயன்படுத்துங்கள்"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"முகத்தைக் கண்டறிய இயலவில்லை. மீண்டும் முயலவும்."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"மீண்டும் அதே போஸ் தருகிறீர்கள், வேறு முயலுங்கள்."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"தலையை லேசாகத் திருப்பவும்."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"உங்கள் தலையை லேசாகச் சாய்க்கவும்."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"உங்கள் தலையைச் சற்றுத் திருப்பவும்."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"உங்கள் முகத்தை மறைக்கும் அனைத்தையும் நீக்குக."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"திரையையும் அதிலுள்ள கருப்புப் பட்டியையும் சுத்தம் செய்யவும்"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"இந்த சாதனத்தில் ’முகம் காட்டித் திறத்தல்’ ஆதரிக்கப்படவில்லை."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"சென்சார் தற்காலிகமாக முடக்கப்பட்டுள்ளது."</string>
<string name="face_name_template" msgid="3877037340223318119">"முகம் <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"முக ஐகான்"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ஷார்ட்கட்டைப் பயன்படுத்து"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"கலர் இன்வெர்ஷன்"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"வண்ணத் திருத்தம்"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"ஒளிர்வைக் குறைத்தல்"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ஒலியளவுக்கான விசைகளைப் பிடித்திருந்தீர்கள். <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ஆன் செய்யப்பட்டது."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ஒலியளவுக்கான விசைகளைப் பிடித்திருந்தீர்கள். <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ஆஃப் செய்யப்பட்டது."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐப் பயன்படுத்த 3 விநாடிகளுக்கு இரண்டு ஒலியளவு பட்டன்களையும் அழுத்திப் பிடிக்கவும்"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ஃபிஷிங் எச்சரிக்கை"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"பணிக் கணக்கு"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"விழிப்பூட்டல் ஐகான்"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"சரிபார்க்கப்பட்டது"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"விரிவாக்கும்"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"சுருக்கும்"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"விரிவாக்கத்தை நிலைமாற்றும்"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"செய்திகளும் பத்திரிகைகளும்"</string>
<string name="app_category_maps" msgid="6395725487922533156">"வரைபடங்களும் வழிசெலுத்தலும்"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"உற்பத்தித்திறன்"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"சாதனச் சேமிப்பகம்"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB பிழைதிருத்தம்"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"மணி"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"தொடர, உங்கள் சாதனத்தின் கேமராவை அணுகுவதற்கு <b><xliff:g id="APP">%s</xliff:g></b> ஆப்ஸுக்கு அனுமதி வேண்டும்."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ஆன் செய்"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"சென்சார் தனியுரிமை"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"ஆப்ஸ் ஐகான்"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ஆப்ஸ் பிராண்டிங் இமேஜ்"</string>
</resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 9f822e3..63ee3a0 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"మీ ఫోటో సేకరణను సవరించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"మీ మీడియా సేకరణ నుండి స్థానాలను చదవండి"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"మీ మీడియా సేకరణ నుండి స్థానాలను చదవడానికి యాప్ను అనుమతిస్తుంది."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"ఇది మీరేనని వెరిఫై చేసుకోండి"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"బయోమెట్రిక్ హార్డ్వేర్ అందుబాటులో లేదు"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ప్రమాణీకరణ రద్దు చేయబడింది"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"గుర్తించలేదు"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"ప్రమాణీకరణ రద్దు చేయబడింది"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"పిన్, ఆకృతి లేదా పాస్వర్డ్ సెట్ చేయబడలేదు"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"ప్రామాణీకరిస్తున్నప్పుడు ఎర్రర్ ఏర్పడింది"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"పాక్షిక వేలిముద్ర గుర్తించబడింది. దయచేసి మళ్లీ ప్రయత్నించండి."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"వేలిముద్రను ప్రాసెస్ చేయడం సాధ్యపడలేదు. దయచేసి మళ్లీ ప్రయత్నించండి."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"వేలిముద్ర సెన్సార్ మురికిగా ఉంది. దయచేసి శుభ్రపరిచి, మళ్లీ ప్రయత్నించండి."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ఈ పరికరంలో వేలిముద్ర సెన్సార్ ఎంపిక లేదు."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"సెన్సార్ తాత్కాలికంగా డిజేబుల్ చేయబడింది."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"వేలు <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"కొనసాగించడానికి మీ వేలిముద్రను ఉపయోగించండి"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"ఇక ముఖం గుర్తించలేదు. మళ్లీ ప్రయత్నించండి."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"ఒకే మాదిరిగా ఉంది, దయచేసి భంగిమను మార్చండి."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"మీ తలను ఇంకాస్త తక్కువ తిప్పండి."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"మీ తలను కొంచెం తక్కువగా వంపండి."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"మీ తలను ఎడమ/కుడి వైపుగా ఇంకాస్త తిప్పండి."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"మీ ముఖానికి అడ్డుగా ఉన్నవాటిని తీసివేస్తుంది."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"నల్లని పట్టీతో సహా మీ స్క్రీన్ పైభాగం అంతటినీ శుభ్రంగా తుడవండి"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"ఈ పరికరంలో ముఖంతో అన్లాక్ను ఉపయోగించడానికి మద్దతు లేదు."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"సెన్సార్ తాత్కాలికంగా డిజేబుల్ చేయబడింది."</string>
<string name="face_name_template" msgid="3877037340223318119">"ముఖ <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"ముఖ చిహ్నం"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"సత్వరమార్గాన్ని ఉపయోగించు"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"కలర్ మార్పిడి"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"కలర్ సరిచేయడం"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"ప్రకాశాన్ని తగ్గించండి"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"వాల్యూమ్ కీలు నొక్కి ఉంచబడ్డాయి. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆన్ చేయబడింది"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"వాల్యూమ్ కీలు నొక్కి ఉంచబడ్డాయి. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆఫ్ చేయబడింది"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ని ఉపయోగించడానికి వాల్యూమ్ కీలు రెండింటినీ 3 సెకన్లు నొక్కి ఉంచండి"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"ఫిషింగ్ అలర్ట్"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"కార్యాలయ ప్రొఫైల్"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"హెచ్చరించబడింది"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"వెరిఫై చేయబడింది"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"విస్తరింపజేయి"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"కుదించు"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"విస్తరణను టోగుల్ చేయండి"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"వార్తలు & వార్తాపత్రికలు"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Maps & నావిగేషన్"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"ఉత్పాదకత"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"పరికర నిల్వ"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB డీబగ్గింగ్"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"గంట"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"కొనసాగించడానికి, <b><xliff:g id="APP">%s</xliff:g></b&gtకు మీ పరికరం యొక్క కెమెరా యాక్సెస్ అవసరం."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"ఆన్ చేయి"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"సెన్సార్ గోప్యత"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"యాప్ చిహ్నం"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"యాప్ బ్రాండింగ్ ఇమేజ్"</string>
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 21865cd..3c985b9 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"อนุญาตให้แอปแก้ไขคอลเล็กชันรูปภาพของคุณ"</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"อ่านตำแหน่งจากคอลเล็กชันสื่อของคุณ"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"อนุญาตให้แอปอ่านตำแหน่งจากคอลเล็กชันสื่อของคุณ"</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"ยืนยันว่าเป็นตัวคุณ"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ฮาร์ดแวร์ไบโอเมตริกไม่พร้อมใช้งาน"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"ยกเลิกการตรวจสอบสิทธิ์แล้ว"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"ไม่รู้จัก"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"ยกเลิกการตรวจสอบสิทธิ์แล้ว"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"ไม่ได้ตั้ง PIN, รูปแบบ หรือรหัสผ่าน"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"การตรวจสอบข้อผิดพลาด"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"ตรวจพบลายนิ้วมือเพียงบางส่วน โปรดลองอีกครั้ง"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ประมวลผลลายนิ้วมือไม่ได้ โปรดลองอีกครั้ง"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"เซ็นเซอร์ลายนิ้วมือไม่สะอาด โปรดทำความสะอาดและลองอีกครั้ง"</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"อุปกรณ์นี้ไม่มีเซ็นเซอร์ลายนิ้วมือ"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ปิดใช้เซ็นเซอร์ชั่วคราวแล้ว"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"นิ้ว <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ใช้ลายนิ้วมือของคุณเพื่อดำเนินการต่อ"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"จำใบหน้าไม่ได้แล้ว ลองอีกครั้ง"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"ใกล้เคียงเกินไป โปรดเปลี่ยนท่าโพส"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"จัดตำแหน่งศีรษะให้ตรง"</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"ปรับมุมศีรษะให้ตรง"</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"จัดตำแหน่งศีรษะให้ตรง"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"เอาสิ่งที่ปิดบังใบหน้าออก"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"ทำความสะอาดด้านบนของหน้าจอ รวมถึงแถบสีดำ"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"อุปกรณ์นี้ไม่รองรับการปลดล็อกด้วยใบหน้า"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"ปิดใช้เซ็นเซอร์ชั่วคราวแล้ว"</string>
<string name="face_name_template" msgid="3877037340223318119">"ใบหน้า <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"ไอคอนใบหน้า"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ใช้ทางลัด"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"การกลับสี"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"การแก้สี"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"ลดความสว่าง"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"กดปุ่มปรับระดับเสียงค้างไว้แล้ว เปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"กดปุ่มปรับระดับเสียงค้างไว้แล้ว ปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"กดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มค้างไว้ 3 วินาทีเพื่อใช้ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"การแจ้งเตือนฟิชชิง"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"โปรไฟล์งาน"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"แจ้งเตือนแล้ว"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"ยืนยันแล้ว"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"ขยาย"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"ยุบ"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"สลับการขยาย"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"ข่าวสารและนิตยสาร"</string>
<string name="app_category_maps" msgid="6395725487922533156">"แผนที่และการนำทาง"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"ประสิทธิภาพการทำงาน"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"พื้นที่เก็บข้อมูลของอุปกรณ์"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"การแก้ไขข้อบกพร่อง USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ชั่วโมง"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"<b><xliff:g id="APP">%s</xliff:g></b> ต้องได้รับสิทธิ์เข้าถึงกล้องของอุปกรณ์เพื่อดำเนินการต่อ"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"เปิด"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"ความเป็นส่วนตัวสำหรับเซ็นเซอร์"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"ไอคอนแอปพลิเคชัน"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ภาพลักษณ์ของแบรนด์แอปพลิเคชัน"</string>
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 37d06f8..7402195 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -227,7 +227,7 @@
<string name="reboot_to_update_prepare" msgid="6978842143587422365">"Naghahandang i-update…"</string>
<string name="reboot_to_update_package" msgid="4644104795527534811">"Pinoproseso ang package ng update…"</string>
<string name="reboot_to_update_reboot" msgid="4474726009984452312">"Nagre-restart…"</string>
- <string name="reboot_to_reset_title" msgid="2226229680017882787">"I-reset ang data ng factory"</string>
+ <string name="reboot_to_reset_title" msgid="2226229680017882787">"Pag-reset sa factory data"</string>
<string name="reboot_to_reset_message" msgid="3347690497972074356">"Nagre-restart…"</string>
<string name="shutdown_progress" msgid="5017145516412657345">"Nagsa-shut down…"</string>
<string name="shutdown_confirm" product="tablet" msgid="2872769463279602432">"Mag-shut down ang iyong tablet."</string>
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Pinapayagan ang app na baguhin ang iyong koleksyon ng larawan."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"basahin ang mga lokasyon mula sa iyong koleksyon ng media"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Pinapayagan ang app na basahin ang mga lokasyon mula sa iyong koleksyon ng media."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"I-verify na ikaw ito"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Walang biometric hardware"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Nakansela ang pag-authenticate"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Hindi nakilala"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Nakansela ang pag-authenticate"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Walang itinakdang pin, pattern, o password"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Nagkaroon ng error sa pag-authenticate"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Hindi buo ang natukoy na fingerprint. Pakisubukan ulit."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Hindi maproseso ang fingerprint. Pakisubukan ulit."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Marumi ang sensor ng fingerprint. Pakilinis at subukang muli."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Walang sensor ng fingerprint ang device na ito."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Pansamantalang na-disable ang sensor."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Daliri <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Gamitin ang iyong fingerprint para magpatuloy"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Hindi na makilala ang mukha. Subukang muli."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Masyadong magkatulad, pakibago ang pose mo."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Huwag masyadong lumingon."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Bawasan ang pag-tilt ng iyong ulo."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Huwag masyadong lumingon."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Alisin ang anumang humaharang sa iyong mukha."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Linisin ang itaas ng iyong screen, kasama ang itim na bar"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Hindi sinusuportahan ang face unlock sa device na ito."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Pansamantalang na-disable ang sensor."</string>
<string name="face_name_template" msgid="3877037340223318119">"Mukha <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Gamitin ang Shortcut"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Pag-invert ng Kulay"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Pagwawasto ng Kulay"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Bawasan ang liwanag"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Pinindot nang matagal ang volume keys. Na-on ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Pinindot nang matagal ang volume keys. Na-off ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pindutin nang matagal ang parehong volume key sa loob ng tatlong segundo para magamit ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerto sa phishing"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Profile sa trabaho"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Naalertuhan"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Na-verify"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Palawakin"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"I-collapse"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"i-toggle ang pagpapalawak"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Balita at Mga Magazine"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Mga Mapa at Navigation"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Productivity"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Storage ng device"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Pag-debug ng USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"oras"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Para magpatuloy, kailangan ng <b><xliff:g id="APP">%s</xliff:g></b> ng access sa camera ng iyong device."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"I-on"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Privacy ng Sensor"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Icon ng application"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Representasyon ng brand ng application"</string>
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 2132aac..147553f 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Uygulamanın fotoğraf koleksiyonunuzu değiştirmesine izin verir."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"medya koleksiyonunuzdaki konumları okuma"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Uygulamanın medya koleksiyonunuzdaki konumları okumasına izin verir."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Siz olduğunuzu doğrulayın"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biyometrik donanım kullanılamıyor"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Kimlik doğrulama iptal edildi"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Tanınmadı"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Kimlik doğrulama iptal edildi"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN, desen veya şifre seti yok"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Kimlik doğrulama sırasında hata oluştu"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Parmak izinin tümü algılanamadı. Lütfen tekrar deneyin."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Parmak izi işlenemedi. Lütfen tekrar deneyin."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Parmak izi sensörü kirli. Lütfen temizleyin ve tekrar deneyin."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu cihazda parmak izi sensörü yok."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensör geçici olarak devre dışı bırakıldı."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. parmak"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Devam etmek için parmak izinizi kullanın"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Yüz artık tanınamıyor. Tekrar deneyin."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Duruşunuz çok benzer, lütfen pozunuzu değiştirin."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Başınızı biraz daha az çevirin."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Başınızı biraz daha az eğin."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Başınızı biraz daha az çevirin."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Yüzünüzün görünmesini engelleyen şeyleri kaldırın."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Siyah çubuk da dahil olmak üzere ekranınızın üst kısmını temizleyin"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Bu cihazda yüz tanıma kilidi desteklenmiyor"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensör geçici olarak devre dışı bırakıldı."</string>
<string name="face_name_template" msgid="3877037340223318119">"Yüz <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Yüz simgesi"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Kısayolu Kullan"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Rengi Ters Çevirme"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Renk Düzeltme"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Parlaklığı azalt"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ses tuşlarını basılı tuttunuz. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> açıldı."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ses tuşlarını basılı tuttunuz. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kapatıldı."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini kullanmak için her iki ses tuşunu basılı tutun"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Kimlik avı uyarısı"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"İş profili"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Sesli uyarıldı"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Doğrulandı"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Genişlet"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Daralt"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"genişletmeyi aç/kapat"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Haberler ve Dergiler"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Haritalar ve Navigasyon"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Verimlilik"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Cihazdaki depolama alanı"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB üzerinden hata ayıklama"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"saat"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Devam etmek için <b><xliff:g id="APP">%s</xliff:g></b> uygulamasının cihazınızın kamerasına erişmesi gerekiyor."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Aç"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Sensör Gizliliği"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Uygulama simgesi"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Uygulama marka imajı"</string>
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 3b9db40..77e664a 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -556,13 +556,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Додаток зможе змінювати вашу колекцію фотографій."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"розпізнавати геодані з колекції медіа-вмісту"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Додаток зможе розпізнавати геодані з вашої колекції медіа-вмісту."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Підтвердьте, що це ви"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Біометричне апаратне забезпечення недоступне"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Автентифікацію скасовано"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Не розпізнано"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Автентифікацію скасовано"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Не вказано PIN-код, ключ або пароль"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Помилка автентифікації"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Відбиток пальця розпізнано частково. Повторіть спробу."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Не вдалось обробити відбиток пальця. Повторіть спробу."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Датчик відбитків пальців забруднився. Очистьте його та повторіть спробу."</string>
@@ -585,6 +595,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На цьому пристрої немає сканера відбитків пальців."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчик тимчасово вимкнено."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Відбиток пальця <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Щоб продовжити, скористайтеся своїм відбитком пальця"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -612,8 +626,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Розпізнати обличчя вже не вдається. Повторіть спробу."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Надто схоже на попередню спробу, змініть позу."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Трохи перемістіть обличчя."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Трохи зменште нахил голови."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Трохи поверніть обличчя."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Приберіть об’єкти, які затуляють ваше обличчя."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Очистьте верхню частину екрана, зокрема чорну панель"</string>
@@ -631,6 +644,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"На цьому пристрої не підтримується Фейсконтроль."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Датчик тимчасово вимкнено."</string>
<string name="face_name_template" msgid="3877037340223318119">"Обличчя <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Значок обличчя"</string>
@@ -1712,8 +1731,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Використовувати ярлик"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Інверсія кольорів"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Корекція кольорів"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Зменшення яскравості"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Утримано клавіші гучності. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> увімкнено."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Утримано клавіші гучності. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> вимкнено."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Щоб скористатися службою <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, утримуйте обидві клавіші гучності впродовж трьох секунд"</string>
@@ -1938,6 +1956,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Попередження про фішинг"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Робочий профіль"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Зі звуком"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Підтверджено"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Розгорнути"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Згорнути"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"розгорнути або згорнути"</string>
@@ -2011,6 +2030,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Новини та журнали"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Карти й навігація"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Продуктивність"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Пам’ять пристрою"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Налагодження USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"години"</string>
@@ -2289,8 +2310,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Щоб продовжити, надайте додатку <b><xliff:g id="APP">%s</xliff:g></b> доступ до камери пристрою."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Увімкнути"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Конфіденційність датчиків"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Значок додатка"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Зображення фірмової символіки додатка"</string>
</resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index c10f3e9..10f787b 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"ایپ کو آپ کی تصویر کے مجموعے میں ترمیم کی اجازت دیتا ہے۔"</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"اپنی میڈيا کے مجموعے سے مقامات پڑھیں"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"ایپ کو آپ کی میڈيا کے مجموعے سے مقامات پڑھنے کی اجازت دیتا ہے۔"</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"توثیق کریں کہ یہ آپ ہیں"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"بایومیٹرک ہارڈ ویئر دستیاب نہیں ہے"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"تصدیق کا عمل منسوخ ہو گیا"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"تسلیم شدہ نہیں ہے"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"تصدیق کا عمل منسوخ ہو گیا"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"کوئی پن، پیٹرن، یا پاس ورڈ سیٹ نہیں ہے"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"خرابی کی توثیق ہو رہی ہے"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"جزوی فنگر پرنٹ کی شناخت ہوئی۔ براہ کرم دوبارہ کوشش کریں۔"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"فنگر پرنٹ پر کارروائی نہیں کی جا سکی۔ براہ کرم دوبارہ کوشش کریں۔"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"فنگر پرنٹ سینسر گندا ہے۔ براہ کرم صاف کریں اور دوبارہ کوشش کریں۔"</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"اس آلہ میں فنگر پرنٹ سینسر نہیں ہے۔"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"سینسر عارضی طور غیر فعال ہے۔"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"انگلی <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"جاری رکھنے کیلئے اپنا فنگر پرنٹ استعمال کریں"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"اب چہرے کی شناخت نہیں کر سکتے۔ پھر آزمائيں۔"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"کافی ملتا جلتا ہے، براہ کرم اپنا پوز بدلیں۔"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"اپنا سر تھوڑا کم کریں۔"</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"اپنا سر تھوڑا کم جھکائیں۔"</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"اپنا سر تھوڑا کم کریں۔"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"آپ کے چہرہ کو چھپانے والی ہر چیز کو ہٹائیں۔"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"سیاہ بار سمیت، اپنی اسکرین کے اوپری حصے کو صاف کریں"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"اس آلہ پر چہرے کے ذریعے غیر مقفل کرنا تعاون یافتہ نہیں ہے۔"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"سینسر عارضی طور غیر فعال ہے۔"</string>
<string name="face_name_template" msgid="3877037340223318119">"چہرہ <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"چہرے کا آئیکن"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"شارٹ کٹ استعمال کریں"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"رنگوں کی تقلیب"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"رنگ کی تصحیح"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"چمک کم کریں"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"والیوم کی کلیدوں کو دبائے رکھا گیا۔ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> آن ہے۔"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"والیوم کی کلیدوں کو دبائے رکھا گیا۔ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> آف ہے۔"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> کا استعمال کرنے کے لیے 3 سیکنڈ تک والیوم کی دونوں کلیدوں کو چھوئیں اور دبائے رکھیں"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"فریب دہی کا الرٹ"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"دفتری پروفائل"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"الرٹ کیا گیا"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"توثیق شدہ"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"پھیلائیں"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"سکیڑیں"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"پھیلاؤ کو ٹوگل کریں"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"خبریں اور میگزین"</string>
<string name="app_category_maps" msgid="6395725487922533156">"نقشے اور نیویگیشن"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"پروڈکٹیوٹی"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"آلہ کی اسٹوریج"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB ڈیبگ کرنا"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"گھنٹہ"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"جاری رکھنے کیلئے <b><xliff:g id="APP">%s</xliff:g></b> کو آپ کے آلے کے کیمرے تک رسائی درکار ہے۔"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"آن کریں"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"سینسر کی رازداری"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"ایپلیکیشن کا آئیکن"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"ایپلیکیشن کی برانڈنگ تصویر"</string>
</resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index f77de7d..f2c5589 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -550,13 +550,18 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Ilovaga suratlar to‘plamingizni o‘zgartirishga ruxsat beradi."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"multimedia to‘plamidan joylashuv axborotini o‘qish"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Ilovaga multimedia to‘plamingizdan joylashuv axborotini o‘qishga ruxsat beradi."</string>
+ <string name="biometric_app_setting_name" msgid="3339209978734534457">"Biometrik tasdiqlash"</string>
+ <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biometrika yoki ekran qulfi"</string>
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Oʻzingizni taniting"</string>
+ <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Davob etish uchun biometrik tasdiqlang"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Biometrik sensor ishlamayapti"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentifikatsiya bekor qilindi"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Aniqlanmadi"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Autentifikatsiya bekor qilindi"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"PIN kod, grafik kalit yoki parol sozlanmagan"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Autentifikatsiya amalga oshmadi"</string>
+ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Ekran qulfi"</string>
+ <string name="screen_lock_dialog_default_subtitle" msgid="8638638125397857315">"Davom etish uchun qurilma kalitini kiritish"</string>
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Barmoq izi qisman aniqlandi. Qayta urinib ko‘ring."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Barmoq izi aniqlanmadi. Qaytadan urining."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Barmoq izi skanerini tozalab, keyin qaytadan urining."</string>
@@ -579,6 +584,8 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu qurilmada barmoq izi skaneri mavjud emas."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor vaqtincha faol emas."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Barmoq izi <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Barmoq izi ishlatish"</string>
+ <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Barmoq izi yoki ekran qulfi"</string>
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Davom etish uchun barmoq izingizdan foydalaning"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -624,6 +631,9 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Yuz bilan ochish bu qurilmada ishlamaydi"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor vaqtincha faol emas."</string>
<string name="face_name_template" msgid="3877037340223318119">"Yuz <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <string name="face_app_setting_name" msgid="8130135875458467243">"Yuz bilan ochish"</string>
+ <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Yuz bilan ochish yoki ekran qulfi"</string>
+ <string name="face_dialog_default_subtitle" msgid="4979205739418564856">"Davom etish uchun yuz bilan oching"</string>
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Yuz belgisi"</string>
@@ -1874,6 +1884,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Fishing signali"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Ish profili"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Ogohlantirildi"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Tasdiqlangan"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Yoyish"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Yig‘ish"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"ochish yoki yopish"</string>
@@ -1945,6 +1956,7 @@
<string name="app_category_news" msgid="1172762719574964544">"Yangiliklar va jurnallar"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Xaritalar va navigatsiya"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Ish va unumdorlik"</string>
+ <string name="app_category_accessibility" msgid="6643521607848547683">"Maxsus imkoniyatlar"</string>
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Qurilma xotirasi"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB orqali nosozliklarni aniqlash"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"soat"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index baf0b86d..4d7091c 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Cho phép ứng dụng này sửa đổi bộ sưu tập ảnh của bạn."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"đọc vị trí từ bộ sưu tập phương tiện"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Cho phép ứng dụng này đọc vị trí từ bộ sưu tập phương tiện của bạn."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Xác minh danh tính của bạn"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Không có phần cứng sinh trắc học"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Đã hủy xác thực"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Không nhận dạng được"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Đã hủy xác thực"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Chưa đặt mã PIN, hình mở khóa hoặc mật khẩu"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Lỗi khi xác thực"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Đã phát hiện được một phần vân tay. Vui lòng thử lại."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Không thể xử lý vân tay. Vui lòng thử lại."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Cảm biến vân tay bị bẩn. Hãy làm sạch và thử lại."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Thiết bị này không có cảm biến vân tay."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Đã tạm thời tắt cảm biến."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Ngón tay <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Sử dụng dấu vân tay của bạn để tiếp tục"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Không nhận ra khuôn mặt. Hãy thử lại."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Khuôn mặt quá giống nhau, vui lòng đổi tư thế."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Hãy bớt di chuyển đầu."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Hãy bớt ngửa hoặc cúi đầu."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Hãy bớt di chuyển đầu."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Hãy loại bỏ mọi thứ che khuất khuôn mặt bạn."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Vệ sinh phần đầu màn hình, bao gồm cả thanh màu đen"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"Thiết bị này không hỗ trợ tính năng mở khóa bằng khuôn mặt."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Đã tạm thời tắt cảm biến."</string>
<string name="face_name_template" msgid="3877037340223318119">"Khuôn mặt <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Biểu tượng khuôn mặt"</string>
@@ -986,7 +1005,7 @@
<string name="save_password_remember" msgid="6490888932657708341">"Nhớ"</string>
<string name="save_password_never" msgid="6776808375903410659">"Chưa bao giờ"</string>
<string name="open_permission_deny" msgid="5136793905306987251">"Bạn không được phép mở trang này."</string>
- <string name="text_copied" msgid="2531420577879738860">"Đã sao chép văn bản vào khay nhớ tạm thời."</string>
+ <string name="text_copied" msgid="2531420577879738860">"Đã sao chép văn bản vào bảng nhớ tạm thời."</string>
<string name="copied" msgid="4675902854553014676">"Đã sao chép"</string>
<string name="more_item_label" msgid="7419249600215749115">"Thêm"</string>
<string name="prepend_shortcut_label" msgid="1743716737502867951">"Trình đơn+"</string>
@@ -1111,7 +1130,7 @@
<string name="selectAll" msgid="1532369154488982046">"Chọn tất cả"</string>
<string name="cut" msgid="2561199725874745819">"Cắt"</string>
<string name="copy" msgid="5472512047143665218">"Sao chép"</string>
- <string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"Không sao chép được vào khay nhớ tạm"</string>
+ <string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"Không sao chép được vào bảng nhớ tạm"</string>
<string name="paste" msgid="461843306215520225">"Dán"</string>
<string name="paste_as_plain_text" msgid="7664800665823182587">"Dán dưới dạng văn bản thuần túy"</string>
<string name="replace" msgid="7842675434546657444">"Thay thế..."</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Sử dụng phím tắt"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Đảo màu"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Chỉnh màu"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Giảm độ sáng"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Bạn đã giữ các phím âm lượng. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> đã bật."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Bạn đã giữ các phím âm lượng. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> đã tắt."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Nhấn và giữ đồng thời cả hai phím âm lượng trong 3 giây để sử dụng <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Cảnh báo về hành vi lừa đảo"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Hồ sơ công việc"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Đã phát âm báo"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Đã xác minh"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Mở rộng"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Thu gọn"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"chuyển đổi mở rộng"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Tin tức và tạp chí"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Bản đồ và dẫn đường"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Sản xuất"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Bộ nhớ của thiết bị"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Gỡ lỗi qua USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"giờ"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Để tiếp tục, <b><xliff:g id="APP">%s</xliff:g></b> cần quyền truy cập vào máy ảnh trên thiết bị của bạn."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Bật"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Quyền riêng tư khi sử dụng cảm biến"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Biểu tượng ứng dụng"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Hình ảnh thương hiệu của ứng dụng"</string>
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 9345fc82..1f8f176 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"允许该应用修改您的照片收藏。"</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"从您的媒体收藏中读取位置信息"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"允许该应用从您的媒体收藏中读取位置信息。"</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"验证是您本人在操作"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"生物识别硬件无法使用"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"身份验证已取消"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"无法识别"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"身份验证已取消"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"未设置任何 PIN 码、图案和密码"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"进行身份验证时出错"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"仅检测到部分指纹,请重试。"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"无法处理指纹,请重试。"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"指纹传感器有脏污。请擦拭干净,然后重试。"</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"此设备没有指纹传感器。"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"传感器已暂时停用。"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"使用指纹完成验证才能继续"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"已无法识别人脸,请重试。"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"与先前的姿势太相近,请换一个姿势。"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"请将您的头稍微上下倾斜。"</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"请稍微抬头或低头。"</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"请将您的头稍微左右旋转。"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"请移除所有遮挡您面部的物体。"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"请将屏幕顶部(包括黑色条栏)清理干净"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"此设备不支持人脸解锁。"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"传感器已暂时停用。"</string>
<string name="face_name_template" msgid="3877037340223318119">"面孔 <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"面孔图标"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"使用快捷方式"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"颜色反转"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"色彩校正"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"调低亮度"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"已按住音量键。<xliff:g id="SERVICE_NAME">%1$s</xliff:g>已开启。"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"已按住音量键。<xliff:g id="SERVICE_NAME">%1$s</xliff:g>已关闭。"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"同时按住两个音量键 3 秒钟即可使用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"网上诱骗警报"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"工作资料"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"已提醒"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"已验证"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"展开"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"收起"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"切换展开模式"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"新闻和杂志"</string>
<string name="app_category_maps" msgid="6395725487922533156">"地图和导航"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"办公"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"设备存储空间"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB 调试"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"点"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"如要继续操作,请向<b><xliff:g id="APP">%s</xliff:g></b>授予设备的相机使用权。"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"开启"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"传感器隐私权"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"应用图标"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"应用品牌图片"</string>
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 1187f00..ebc02c50 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"允許應用程式修改您的相片集。"</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"讀取媒體集的位置"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"允許應用程式讀取媒體集的位置。"</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"驗證是你本人"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"無法使用生物識別硬件"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"已取消驗證"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"未能識別"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"已取消驗證"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"未設定 PIN、圖案或密碼"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"驗證時發生錯誤"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"只偵測到部分指紋。請再試一次。"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"無法處理指紋。請再試一次。"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"指紋感應器不乾淨。請清潔後再試一次。"</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"此裝置沒有指紋感應器。"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"感應器已暫時停用。"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"請使用您的指紋繼續"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"無法再識別臉孔。請再試一次。"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"臉孔位置太相近,請改變您的姿勢。"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"減少頭部左右轉動幅度。"</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"減少頭部傾斜幅度。"</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"減少頭部左右轉動幅度。"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"移除遮住您臉孔的任何東西。"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"請清理螢幕頂部,包括黑色列"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"此裝置不支援「臉孔解鎖」。"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"感應器已暫時停用。"</string>
<string name="face_name_template" msgid="3877037340223318119">"臉孔 <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"臉孔圖示"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"使用快速鍵"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"色彩反轉"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"色彩校正"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"調低亮度"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"已按住音量鍵。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> 已開啟。"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"已按住音量鍵。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> 已關閉。"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"㩒住兩個音量鍵 3 秒就可以用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"仿冒詐騙警示"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"工作設定檔"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"已提醒"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"已驗證"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"展開"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"收合"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"切換展開"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"新聞和雜誌"</string>
<string name="app_category_maps" msgid="6395725487922533156">"地圖和導航"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"生產力應用程式"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"裝置儲存空間"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB 偵錯"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"時"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"如要繼續,<b><xliff:g id="APP">%s</xliff:g></b> 需要裝置的相機存取權。"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"開啟"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"感應器私隱"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"應用程式圖示"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"應用程式品牌形象"</string>
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 9492572..10d05c1 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"允許應用程式修改你的相片收藏。"</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"讀取你的媒體收藏的位置資訊"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"允許應用程式讀取你的媒體收藏的位置資訊。"</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"驗證你的身分"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"無法使用生物特徵辨識硬體"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"已取消驗證"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"無法辨識"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"已取消驗證"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"未設定 PIN 碼、解鎖圖案或密碼"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"驗證時發生錯誤"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"僅偵測到部分指紋,請再試一次。"</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"無法處理指紋,請再試一次。"</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"指紋感應器有髒汙。請清潔感應器,然後再試一次。"</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"這個裝置沒有指紋感應器。"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"感應器已暫時停用。"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"使用指紋完成驗證才能繼續操作"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"已無法辨識臉孔,請再試一次。"</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"與先前的姿勢太相似,請換一個姿勢。"</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"請將你的頭部稍微向左或向右轉動。"</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"請稍微抬頭或低頭。"</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"請將你的頭部稍微向左或向右旋轉。"</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"請移除任何會遮住臉孔的物體。"</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"請清理螢幕頂端,包括黑色橫列"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"這個裝置不支援人臉解鎖功能。"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"感應器已暫時停用。"</string>
<string name="face_name_template" msgid="3877037340223318119">"臉孔 <xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"臉孔圖示"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"使用捷徑"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"色彩反轉"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"色彩校正"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"調低亮度"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"已按住音量鍵。「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」已開啟。"</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"已按住音量鍵。「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」已關閉。"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"同時按住調低及調高音量鍵三秒即可使用「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"網路詐騙警示"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"工作資料夾"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"已提醒"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"已驗證"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"展開"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"收合"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"切換展開模式"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"新聞和雜誌"</string>
<string name="app_category_maps" msgid="6395725487922533156">"地圖和導航"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"工作效率"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"裝置儲存空間"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB 偵錯"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"點"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"如要繼續操作,請將裝置的相機存取權授予「<xliff:g id="APP">%s</xliff:g>」<b></b>。"</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"開啟"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"感應器隱私權"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"應用程式圖示"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"應用程式品牌圖片"</string>
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index e5a026bd..976b97a2 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -550,13 +550,23 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Ivumela uhlelo lwakho lokusebenza ukuthi lilungise iqoqo lakho lesithombe."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"funda izindawo kusukela kuqoqo lakho lemidiya"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Ivumela uhlelo lokusebenza ukuthi lifunde izindawo kusukela kuqoqo lakho lemidiya."</string>
+ <!-- no translation found for biometric_app_setting_name (3339209978734534457) -->
+ <skip />
+ <!-- no translation found for biometric_or_screen_lock_app_setting_name (5348462421758257752) -->
+ <skip />
<string name="biometric_dialog_default_title" msgid="55026799173208210">"Qinisekisa ukuthi nguwe"</string>
+ <!-- no translation found for biometric_dialog_default_subtitle (8457232339298571992) -->
+ <skip />
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"I-Biometric hardware ayitholakali"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Ukufakazela ubuqiniso kukhanseliwe"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Akwaziwa"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"Ukufakazela ubuqiniso kukhanseliwe"</string>
<string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Ayikho iphinikhodi, iphethini, noma iphasiwedi esethiwe"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Iphutha lokufakazela ubuqiniso"</string>
+ <!-- no translation found for screen_lock_app_setting_name (6054944352976789228) -->
+ <skip />
+ <!-- no translation found for screen_lock_dialog_default_subtitle (8638638125397857315) -->
+ <skip />
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Izigxivizo zeminwe ezincane zitholiwe. Sicela uzame futhi."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Ayikwazanga ukucubungula izigxivizo zeminwe. Sicela uzame futhi."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Inzwa yezigxivizo zeminwe ingcolile. Sicela uyihlanze uphinde uzame futhi."</string>
@@ -579,6 +589,10 @@
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Le divayisi ayinayo inzwa yezigxivizo zeminwe."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Inzwa ikhutshazwe okwesikhashana."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Umunwe ongu-<xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <!-- no translation found for fingerprint_app_setting_name (4253767877095495844) -->
+ <skip />
+ <!-- no translation found for fingerprint_or_screen_lock_app_setting_name (3501743523487644907) -->
+ <skip />
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Sebenzisa izigxivizo zakho zeminwe ukuze uqhubeke"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -606,8 +620,7 @@
<string name="face_acquired_too_different" msgid="4699657338753282542">"Ayisakwazi ukubona ubuso. Zama futhi."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"Kufana kakhulu, sicela ushintshe ukuma kwakho."</string>
<string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Jikisa ikhanda lakho kancane."</string>
- <!-- no translation found for face_acquired_tilt_too_extreme (8618210742620248049) -->
- <skip />
+ <string name="face_acquired_tilt_too_extreme" msgid="8618210742620248049">"Tshekisa kancane ikhanda lakho."</string>
<string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"Jikisa ikhanda lakho kancane."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"Susa noma yini efihle ubuso bakho."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Hlanza okuphezulu kwesikrini sakho, kufaka phakathi ibha emnyama"</string>
@@ -625,6 +638,12 @@
<string name="face_error_hw_not_present" msgid="1070600921591729944">"I-face unlock ayisekelwe kule divayisi."</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Inzwa ikhutshazwe okwesikhashana."</string>
<string name="face_name_template" msgid="3877037340223318119">"Ubuso be-<xliff:g id="FACEID">%d</xliff:g>"</string>
+ <!-- no translation found for face_app_setting_name (8130135875458467243) -->
+ <skip />
+ <!-- no translation found for face_or_screen_lock_app_setting_name (1603149075605709106) -->
+ <skip />
+ <!-- no translation found for face_dialog_default_subtitle (4979205739418564856) -->
+ <skip />
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="465030547475916280">"Isithonjana sobuso"</string>
@@ -1668,8 +1687,7 @@
<string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Sebenzisa isinqamuleli"</string>
<string name="color_inversion_feature_name" msgid="326050048927789012">"Ukuguqulwa kombala"</string>
<string name="color_correction_feature_name" msgid="3655077237805422597">"Ukulungiswa kombala"</string>
- <!-- no translation found for reduce_bright_colors_feature_name (8978255324027479398) -->
- <skip />
+ <string name="reduce_bright_colors_feature_name" msgid="8978255324027479398">"Nciphisa ukukhanya"</string>
<string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ubambe okhiye bevolumu. I-<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ivuliwe."</string>
<string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ubambe okhiye bevolumu. I-<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ivaliwe."</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Cindezela uphinde ubambe bobabili okhiye bevolumu ngamasekhondi amathathu ukuze usebenzise i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
@@ -1876,6 +1894,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Isexwayiso sobugebengu bokweba imininingwane ebucayi"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Iphrofayela yomsebenzi"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Kuxwayisiwe"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Iqinisekisiwe"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Nweba"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Goqa"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"guqula ukunwebisa"</string>
@@ -1947,6 +1966,8 @@
<string name="app_category_news" msgid="1172762719574964544">"Izindaba nomagazini"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Amamephu nokuzula"</string>
<string name="app_category_productivity" msgid="1844422703029557883">"Ukukhiqiza"</string>
+ <!-- no translation found for app_category_accessibility (6643521607848547683) -->
+ <skip />
<string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Isitoreji sedivayisi"</string>
<string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"Ukulungisa iphutha le-USB"</string>
<string name="time_picker_hour_label" msgid="4208590187662336864">"ihora"</string>
@@ -2221,8 +2242,6 @@
<string name="sensor_privacy_start_use_camera_notification_content" msgid="4738005643315863736">"Ukuze uqhubeke, <b>i-<xliff:g id="APP">%s</xliff:g></b> idinga ukufinyelela ikhamera yakho."</string>
<string name="sensor_privacy_start_use_dialog_turn_on_button" msgid="7921147002346108119">"Vula"</string>
<string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Ubumfihlo Benzwa"</string>
- <!-- no translation found for splash_screen_view_icon_description (180638751260598187) -->
- <skip />
- <!-- no translation found for splash_screen_view_branding_description (7911129347402728216) -->
- <skip />
+ <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Isithonjana sohlelo lokusebenza"</string>
+ <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Isithombe sokubhrenda i-application"</string>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 100983b..efc8fe9 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8424,6 +8424,9 @@
<!-- Fully qualified class name of an activity that allows the user to modify
the settings for this service. -->
<attr name="settingsActivity" />
+ <!-- Fully qualified class name of an activity that allows the user to view any passwords
+ saved by this service. -->
+ <attr name="passwordsActivity" format="string" />
<!-- Specifies whether the AutofillService supports inline suggestions-->
<attr name="supportsInlineSuggestions" format="boolean" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d61d19a..247ca16 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1761,13 +1761,6 @@
<item>com.android.location.fused</item>
</string-array>
- <!-- Gnss Psds Servers -->
- <string name="config_longterm_psds_server_1" translatable="false"></string>
- <string name="config_longterm_psds_server_2" translatable="false"></string>
- <string name="config_longterm_psds_server_3" translatable="false"></string>
- <string name="config_normal_psds_server" translatable="false"></string>
- <string name="config_realtime_psds_server" translatable="false"></string>
-
<!-- This string array can be overriden to enable test location providers initially. -->
<!-- Array of "[locationProviderName],[requiresNetwork],
[requiresSatellite],[requiresCell],[hasMonetaryCost],
@@ -1964,6 +1957,8 @@
<string name="config_systemContacts" translatable="false">com.android.contacts</string>
<!-- The name of the package that will hold the speech recognizer role by default. -->
<string name="config_systemSpeechRecognizer" translatable="false"></string>
+ <!-- The name of the package that will hold the system Wi-Fi coex manager role. -->
+ <string name="config_systemWifiCoexManager" translateable="false"></string>
<!-- The name of the package that will be allowed to change its components' label/icon. -->
<string name="config_overrideComponentUiPackage" translatable="false"></string>
@@ -4666,11 +4661,11 @@
<!-- WindowsManager JetPack display features -->
<string name="config_display_features" translatable="false" />
- <!-- Aspect ratio of task level letterboxing. Values <= 1.0 will be ignored.
- Note: Activity min/max aspect ratio restrictions will still be respected by the
- activity-level letterboxing (size-compat mode). Therefore this override can control the
- maximum screen area that can be occupied by the app in the letterbox mode. -->
- <item name="config_taskLetterboxAspectRatio" format="float" type="dimen">0.0</item>
+ <!-- Aspect ratio of letterboxing for fixed orientation. Values <= 1.0 will be ignored.
+ Note: Activity min/max aspect ratio restrictions will still be respected.
+ Therefore this override can control the maximum screen area that can be occupied by
+ the app in the letterbox mode. -->
+ <item name="config_fixedOrientationLetterboxAspectRatio" format="float" type="dimen">0.0</item>
<!-- Corners radius for activity presented the letterbox mode. Values < 0 will be ignored and
corners of the activity won't be rounded. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 2004d0a..7702ee4 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3085,6 +3085,7 @@
<public name="hand_secondTint"/>
<public name="hand_secondTintMode"/>
<public name="dataExtractionRules"/>
+ <public name="passwordsActivity"/>
</public-group>
<public-group type="drawable" first-id="0x010800b5">
@@ -3168,6 +3169,8 @@
<public name="config_customMediaSessionPolicyProvider" />
<!-- @hide @SystemApi -->
<public name="config_systemSpeechRecognizer" />
+ <!-- @hide @SystemApi -->
+ <public name="config_systemWifiCoexManager" />
</public-group>
<public-group type="id" first-id="0x01020055">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 5a19649..2b1168f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1524,8 +1524,15 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_mediaLocation">Allows the app to read locations from your media collection.</string>
+ <!-- Name for an app setting that lets the user authenticate for that app using biometrics (e.g. fingerprint or face). [CHAR LIMIT=30] -->
+ <string name="biometric_app_setting_name">Use biometrics</string>
+ <!-- Name for an app setting that lets the user authenticate for that app using biometrics (e.g. fingerprint or face) or their screen lock credential (i.e. PIN, pattern, or password). [CHAR LIMIT=70] -->
+ <string name="biometric_or_screen_lock_app_setting_name">Use biometrics or screen lock</string>
<!-- Title shown when the system-provided biometric dialog is shown, asking the user to authenticate. [CHAR LIMIT=40] -->
<string name="biometric_dialog_default_title">Verify it\u2019s you</string>
+ <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with a biometric (e.g. fingerprint or face). [CHAR LIMIT=70] -->
+ <string name="biometric_dialog_default_subtitle">Use your biometric to continue</string>
+
<!-- Message shown when biometric hardware is not available [CHAR LIMIT=50] -->
<string name="biometric_error_hw_unavailable">Biometric hardware unavailable</string>
<!-- Message shown when biometric authentication was canceled by the user [CHAR LIMIT=50] -->
@@ -1539,6 +1546,11 @@
<!-- Message returned to applications when an unexpected/unknown error occurs. [CHAR LIMIT=50]-->
<string name="biometric_error_generic">Error authenticating</string>
+ <!-- Name for an app setting that lets the user authenticate for that app with their screen lock credential (i.e. PIN, pattern, or password). [CHAR LIMIT=30] -->
+ <string name="screen_lock_app_setting_name">Use screen lock</string>
+ <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with their screen lock credential (i.e. PIN, pattern, or password). [CHAR LIMIT=70] -->
+ <string name="screen_lock_dialog_default_subtitle">Enter your device credential to continue</string>
+
<!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
<string name="fingerprint_acquired_partial">Partial fingerprint detected. Please try again.</string>
<!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
@@ -1585,6 +1597,11 @@
<!-- Template to be used to name enrolled fingerprints by default. -->
<string name="fingerprint_name_template">Finger <xliff:g id="fingerId" example="1">%d</xliff:g></string>
+
+ <!-- Name for an app setting that lets the user authenticate for that app with their fingerprint. [CHAR LIMIT=30] -->
+ <string name="fingerprint_app_setting_name">Use fingerprint</string>
+ <!-- Name for an app setting that lets the user authenticate for that app with their fingerprint or screen lock credential (i.e. PIN, pattern, or password). [CHAR LIMIT=70] -->
+ <string name="fingerprint_or_screen_lock_app_setting_name">Use fingerprint or screen lock</string>
<!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with their fingerprint. [CHAR LIMIT=70] -->
<string name="fingerprint_dialog_default_subtitle">Use your fingerprint to continue</string>
@@ -1681,6 +1698,13 @@
<!-- Template to be used to name enrolled faces by default. [CHAR LIMIT=10] -->
<string name="face_name_template">Face <xliff:g id="faceId" example="1">%d</xliff:g></string>
+ <!-- Name for an app setting that lets the user authenticate for that app with their face. [CHAR LIMIT=30] -->
+ <string name="face_app_setting_name">Use face unlock</string>
+ <!-- Name for an app setting that lets the user authenticate for that app with their face or screen lock credential (i.e. PIN, pattern, or password). [CHAR LIMIT=70] -->
+ <string name="face_or_screen_lock_app_setting_name">Use face or screen lock</string>
+ <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with their face. [CHAR LIMIT=70] -->
+ <string name="face_dialog_default_subtitle">Use face unlock to continue</string>
+
<!-- Array containing custom error messages from vendor. Vendor is expected to add and translate these strings -->
<string-array name="face_error_vendor">
</string-array>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b6685aa..b0894dc 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1877,11 +1877,6 @@
<java-symbol type="array" name="config_locationProviderPackageNames" />
<java-symbol type="array" name="config_locationExtraPackageNames" />
<java-symbol type="array" name="config_testLocationProviders" />
- <java-symbol type="string" name="config_longterm_psds_server_1" />
- <java-symbol type="string" name="config_longterm_psds_server_2" />
- <java-symbol type="string" name="config_longterm_psds_server_3" />
- <java-symbol type="string" name="config_normal_psds_server" />
- <java-symbol type="string" name="config_realtime_psds_server" />
<java-symbol type="array" name="config_defaultNotificationVibePattern" />
<java-symbol type="array" name="config_notificationFallbackVibePattern" />
<java-symbol type="bool" name="config_enableServerNotificationEffectsForAutomotive" />
@@ -2472,7 +2467,10 @@
<java-symbol type="string" name="config_keyguardComponent" />
<!-- Biometric messages -->
+ <java-symbol type="string" name="biometric_app_setting_name" />
+ <java-symbol type="string" name="biometric_or_screen_lock_app_setting_name" />
<java-symbol type="string" name="biometric_dialog_default_title" />
+ <java-symbol type="string" name="biometric_dialog_default_subtitle" />
<java-symbol type="string" name="biometric_error_hw_unavailable" />
<java-symbol type="string" name="biometric_error_user_canceled" />
<java-symbol type="string" name="biometric_not_recognized" />
@@ -2480,6 +2478,10 @@
<java-symbol type="string" name="biometric_error_device_not_secured" />
<java-symbol type="string" name="biometric_error_generic" />
+ <!-- Device credential strings for BiometricManager -->
+ <java-symbol type="string" name="screen_lock_app_setting_name" />
+ <java-symbol type="string" name="screen_lock_dialog_default_subtitle" />
+
<!-- Fingerprint messages -->
<java-symbol type="string" name="fingerprint_error_unable_to_process" />
<java-symbol type="string" name="fingerprint_error_hw_not_available" />
@@ -2497,6 +2499,8 @@
<java-symbol type="string" name="fingerprint_error_lockout" />
<java-symbol type="string" name="fingerprint_error_lockout_permanent" />
<java-symbol type="string" name="fingerprint_name_template" />
+ <java-symbol type="string" name="fingerprint_app_setting_name" />
+ <java-symbol type="string" name="fingerprint_or_screen_lock_app_setting_name" />
<java-symbol type="string" name="fingerprint_dialog_default_subtitle" />
<java-symbol type="string" name="fingerprint_authenticated" />
<java-symbol type="string" name="fingerprint_error_no_fingerprints" />
@@ -2544,6 +2548,9 @@
<java-symbol type="string" name="face_acquired_sensor_dirty" />
<java-symbol type="array" name="face_acquired_vendor" />
<java-symbol type="string" name="face_name_template" />
+ <java-symbol type="string" name="face_app_setting_name" />
+ <java-symbol type="string" name="face_or_screen_lock_app_setting_name" />
+ <java-symbol type="string" name="face_dialog_default_subtitle" />
<java-symbol type="string" name="face_authenticated_no_confirmation_required" />
<java-symbol type="string" name="face_authenticated_confirmation_required" />
<java-symbol type="string" name="face_error_security_update_required" />
@@ -4169,7 +4176,7 @@
<java-symbol type="dimen" name="controls_thumbnail_image_max_height" />
<java-symbol type="dimen" name="controls_thumbnail_image_max_width" />
- <java-symbol type="dimen" name="config_taskLetterboxAspectRatio" />
+ <java-symbol type="dimen" name="config_fixedOrientationLetterboxAspectRatio" />
<java-symbol type="integer" name="config_letterboxActivityCornersRadius" />
<java-symbol type="integer" name="config_letterboxBackgroundType" />
<java-symbol type="color" name="config_letterboxBackgroundColor" />
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
index 3706e4b..b0c1f25 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
@@ -24,6 +24,7 @@
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
+import android.net.TetheringManager;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
@@ -141,7 +142,7 @@
mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
mIntentFilter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
- mIntentFilter.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
+ mIntentFilter.addAction(TetheringManager.ACTION_TETHER_STATE_CHANGED);
mContext.registerReceiver(mWifiReceiver, mIntentFilter);
logv("Clear Wifi before we start the test.");
diff --git a/core/tests/GameManagerTests/Android.bp b/core/tests/GameManagerTests/Android.bp
index 2789e9f..8c5d6d5 100644
--- a/core/tests/GameManagerTests/Android.bp
+++ b/core/tests/GameManagerTests/Android.bp
@@ -29,6 +29,7 @@
"androidx.test.rules",
"frameworks-base-testutils",
"junit",
+ "platform-test-annotations",
"truth-prebuilt",
],
libs: ["android.test.runner"],
diff --git a/core/tests/GameManagerTests/src/android/app/GameManagerTests.java b/core/tests/GameManagerTests/src/android/app/GameManagerTests.java
index 8f50051..0c96411 100644
--- a/core/tests/GameManagerTests/src/android/app/GameManagerTests.java
+++ b/core/tests/GameManagerTests/src/android/app/GameManagerTests.java
@@ -16,13 +16,13 @@
package android.app;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
import static junit.framework.Assert.assertEquals;
-import android.app.GameManager.GameMode;
-import android.util.ArrayMap;
-import android.util.Pair;
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -35,22 +35,43 @@
*/
@RunWith(AndroidJUnit4.class)
@SmallTest
+@Presubmit
public final class GameManagerTests {
private static final String PACKAGE_NAME_0 = "com.android.app0";
private static final String PACKAGE_NAME_1 = "com.android.app1";
- private TestGameManagerService mService;
+ protected Context mContext;
private GameManager mGameManager;
+ private String mPackageName;
@Before
public void setUp() {
- mService = new TestGameManagerService();
- mGameManager = new GameManager(
- InstrumentationRegistry.getContext(), mService);
+ mContext = getInstrumentation().getContext();
+ mGameManager = mContext.getSystemService(GameManager.class);
+ mPackageName = mContext.getPackageName();
+
+ // Reset the Game Mode for the test app, since it persists across invocations.
+ mGameManager.setGameMode(mPackageName, GameManager.GAME_MODE_UNSUPPORTED);
+ mGameManager.setGameMode(PACKAGE_NAME_0, GameManager.GAME_MODE_UNSUPPORTED);
+ mGameManager.setGameMode(PACKAGE_NAME_1, GameManager.GAME_MODE_UNSUPPORTED);
}
@Test
- public void testGameModeGetterSetter() {
+ public void testPublicApiGameModeGetterSetter() {
+ assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
+ mGameManager.getGameMode());
+
+ mGameManager.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD);
+ assertEquals(GameManager.GAME_MODE_STANDARD,
+ mGameManager.getGameMode());
+
+ mGameManager.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE);
+ assertEquals(GameManager.GAME_MODE_PERFORMANCE,
+ mGameManager.getGameMode());
+ }
+
+ @Test
+ public void testPrivilegedGameModeGetterSetter() {
assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
mGameManager.getGameMode(PACKAGE_NAME_0));
@@ -62,22 +83,4 @@
assertEquals(GameManager.GAME_MODE_PERFORMANCE,
mGameManager.getGameMode(PACKAGE_NAME_1));
}
-
- private final class TestGameManagerService extends IGameManagerService.Stub {
- private final ArrayMap<Pair<String, Integer>, Integer> mGameModes = new ArrayMap<>();
-
- @Override
- public @GameMode int getGameMode(String packageName, int userId) {
- final Pair key = Pair.create(packageName, userId);
- if (mGameModes.containsKey(key)) {
- return mGameModes.get(key);
- }
- return GameManager.GAME_MODE_UNSUPPORTED;
- }
-
- @Override
- public void setGameMode(String packageName, @GameMode int gameMode, int userId) {
- mGameModes.put(Pair.create(packageName, userId), gameMode);
- }
- }
}
diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/SearchSpecTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/SearchSpecTest.java
index 0fe44630..9e88373 100644
--- a/core/tests/coretests/src/android/app/appsearch/external/app/SearchSpecTest.java
+++ b/core/tests/coretests/src/android/app/appsearch/external/app/SearchSpecTest.java
@@ -21,6 +21,8 @@
import android.os.Bundle;
+import com.google.common.collect.ImmutableList;
+
import org.junit.Test;
import java.util.List;
@@ -67,9 +69,9 @@
SearchSpec searchSpec =
new SearchSpec.Builder()
.setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
- .addProjection("TypeA", "field1", "field2.subfield2")
- .addProjection("TypeB", "field7")
- .addProjection("TypeC")
+ .addProjection("TypeA", ImmutableList.of("field1", "field2.subfield2"))
+ .addProjection("TypeB", ImmutableList.of("field7"))
+ .addProjection("TypeC", ImmutableList.of())
.build();
Map<String, List<String>> typePropertyPathMap = searchSpec.getProjections();
diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaRequestTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaRequestTest.java
index bf6b07f..677f4bd 100644
--- a/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaRequestTest.java
+++ b/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaRequestTest.java
@@ -42,13 +42,13 @@
}
@Test
- public void testInvalidSchemaReferences_fromSystemUiVisibility() {
+ public void testInvalidSchemaReferences_fromDisplayedBySystem() {
IllegalArgumentException expected =
expectThrows(
IllegalArgumentException.class,
() ->
new SetSchemaRequest.Builder()
- .setSchemaTypeVisibilityForSystemUi("InvalidSchema", false)
+ .setSchemaTypeDisplayedBySystem("InvalidSchema", false)
.build());
assertThat(expected).hasMessageThat().contains("referenced, but were not added");
}
@@ -71,30 +71,30 @@
}
@Test
- public void testSchemaTypeVisibilityForSystemUi_visible() {
+ public void testSetSchemaTypeDisplayedBySystem_displayed() {
AppSearchSchema schema = new AppSearchSchema.Builder("Schema").build();
- // By default, the schema is visible.
+ // By default, the schema is displayed.
SetSchemaRequest request = new SetSchemaRequest.Builder().addSchemas(schema).build();
- assertThat(request.getSchemasNotVisibleToSystemUi()).isEmpty();
+ assertThat(request.getSchemasNotDisplayedBySystem()).isEmpty();
request =
new SetSchemaRequest.Builder()
.addSchemas(schema)
- .setSchemaTypeVisibilityForSystemUi("Schema", true)
+ .setSchemaTypeDisplayedBySystem("Schema", true)
.build();
- assertThat(request.getSchemasNotVisibleToSystemUi()).isEmpty();
+ assertThat(request.getSchemasNotDisplayedBySystem()).isEmpty();
}
@Test
- public void testSchemaTypeVisibilityForSystemUi_notVisible() {
+ public void testSetSchemaTypeDisplayedBySystem_notDisplayed() {
AppSearchSchema schema = new AppSearchSchema.Builder("Schema").build();
SetSchemaRequest request =
new SetSchemaRequest.Builder()
.addSchemas(schema)
- .setSchemaTypeVisibilityForSystemUi("Schema", false)
+ .setSchemaTypeDisplayedBySystem("Schema", false)
.build();
- assertThat(request.getSchemasNotVisibleToSystemUi()).containsExactly("Schema");
+ assertThat(request.getSchemasNotDisplayedBySystem()).containsExactly("Schema");
}
@Test
diff --git a/core/tests/coretests/src/android/app/usage/UsageStatsPersistenceTest.java b/core/tests/coretests/src/android/app/usage/UsageStatsPersistenceTest.java
index 4d04a7a..8de9454 100644
--- a/core/tests/coretests/src/android/app/usage/UsageStatsPersistenceTest.java
+++ b/core/tests/coretests/src/android/app/usage/UsageStatsPersistenceTest.java
@@ -78,15 +78,15 @@
"VALID_FLAG_BITS", "UNASSIGNED_TOKEN", "MAX_EVENT_TYPE"};
// All fields in this list are final constants defining event types and not persisted
private static final String[] EVENT_TYPES = {"NONE", "ACTIVITY_DESTROYED", "ACTIVITY_PAUSED",
- "ACTIVITY_RESUMED", "ACTIVITY_STOPPED", "CHOOSER_ACTION", "CONFIGURATION_CHANGE",
- "CONTINUE_PREVIOUS_DAY", "CONTINUING_FOREGROUND_SERVICE", "DEVICE_SHUTDOWN",
- "DEVICE_STARTUP", "END_OF_DAY", "FLUSH_TO_DISK", "FOREGROUND_SERVICE_START",
- "FOREGROUND_SERVICE_STOP", "KEYGUARD_HIDDEN", "KEYGUARD_SHOWN", "LOCUS_ID_SET",
- "MOVE_TO_BACKGROUND", "MOVE_TO_FOREGROUND", "NOTIFICATION_INTERRUPTION",
- "NOTIFICATION_SEEN", "ROLLOVER_FOREGROUND_SERVICE", "SCREEN_INTERACTIVE",
- "SCREEN_NON_INTERACTIVE", "SHORTCUT_INVOCATION", "SLICE_PINNED", "SLICE_PINNED_PRIV",
- "STANDBY_BUCKET_CHANGED", "SYSTEM_INTERACTION", "USER_INTERACTION", "USER_STOPPED",
- "USER_UNLOCKED"};
+ "ACTIVITY_RESUMED", "ACTIVITY_STOPPED", "APP_COMPONENT_USED", "CHOOSER_ACTION",
+ "CONFIGURATION_CHANGE", "CONTINUE_PREVIOUS_DAY", "CONTINUING_FOREGROUND_SERVICE",
+ "DEVICE_SHUTDOWN", "DEVICE_STARTUP", "END_OF_DAY", "FLUSH_TO_DISK",
+ "FOREGROUND_SERVICE_START", "FOREGROUND_SERVICE_STOP", "KEYGUARD_HIDDEN",
+ "KEYGUARD_SHOWN", "LOCUS_ID_SET", "MOVE_TO_BACKGROUND", "MOVE_TO_FOREGROUND",
+ "NOTIFICATION_INTERRUPTION", "NOTIFICATION_SEEN", "ROLLOVER_FOREGROUND_SERVICE",
+ "SCREEN_INTERACTIVE", "SCREEN_NON_INTERACTIVE", "SHORTCUT_INVOCATION", "SLICE_PINNED",
+ "SLICE_PINNED_PRIV", "STANDBY_BUCKET_CHANGED", "SYSTEM_INTERACTION", "USER_INTERACTION",
+ "USER_STOPPED", "USER_UNLOCKED"};
@Test
public void testUsageEventsFields() {
diff --git a/core/tests/coretests/src/android/os/BytesMatcherTest.java b/core/tests/coretests/src/android/os/BytesMatcherTest.java
new file mode 100644
index 0000000..67c1b3c9
--- /dev/null
+++ b/core/tests/coretests/src/android/os/BytesMatcherTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2021 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 android.os;
+
+import static com.android.internal.util.HexDump.hexStringToByteArray;
+
+import android.bluetooth.BluetoothUuid;
+import android.net.MacAddress;
+
+import androidx.test.filters.SmallTest;
+
+import junit.framework.TestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+@SmallTest
+public class BytesMatcherTest extends TestCase {
+ @Test
+ public void testEmpty() throws Exception {
+ BytesMatcher matcher = BytesMatcher.decode("");
+ assertFalse(matcher.test(hexStringToByteArray("cafe")));
+ assertFalse(matcher.test(hexStringToByteArray("")));
+ }
+
+ @Test
+ public void testExact() throws Exception {
+ BytesMatcher matcher = BytesMatcher.decode("+cafe");
+ assertTrue(matcher.test(hexStringToByteArray("cafe")));
+ assertFalse(matcher.test(hexStringToByteArray("beef")));
+ assertFalse(matcher.test(hexStringToByteArray("ca")));
+ assertFalse(matcher.test(hexStringToByteArray("cafe00")));
+ }
+
+ @Test
+ public void testMask() throws Exception {
+ BytesMatcher matcher = BytesMatcher.decode("+cafe/ff00");
+ assertTrue(matcher.test(hexStringToByteArray("cafe")));
+ assertTrue(matcher.test(hexStringToByteArray("ca88")));
+ assertFalse(matcher.test(hexStringToByteArray("beef")));
+ assertFalse(matcher.test(hexStringToByteArray("ca")));
+ assertFalse(matcher.test(hexStringToByteArray("cafe00")));
+ }
+
+ @Test
+ public void testMacAddress() throws Exception {
+ BytesMatcher matcher = BytesMatcher.decode("+cafe00112233/ffffff000000");
+ assertTrue(matcher.testMacAddress(
+ MacAddress.fromString("ca:fe:00:00:00:00")));
+ assertFalse(matcher.testMacAddress(
+ MacAddress.fromString("f0:0d:00:00:00:00")));
+ }
+
+ @Test
+ public void testBluetoothUuid() throws Exception {
+ BytesMatcher matcher = BytesMatcher.decode("+cafe/ff00");
+ assertTrue(matcher.testBluetoothUuid(
+ BluetoothUuid.parseUuidFrom(hexStringToByteArray("cafe"))));
+ assertFalse(matcher.testBluetoothUuid(
+ BluetoothUuid.parseUuidFrom(hexStringToByteArray("beef"))));
+ }
+
+ /**
+ * Verify that single matcher can be configured to match Bluetooth UUIDs of
+ * varying lengths.
+ */
+ @Test
+ public void testBluetoothUuid_Mixed() throws Exception {
+ BytesMatcher matcher = BytesMatcher.decode("+aaaa/ff00,+bbbbbbbb/ffff0000");
+ assertTrue(matcher.testBluetoothUuid(
+ BluetoothUuid.parseUuidFrom(hexStringToByteArray("aaaa"))));
+ assertFalse(matcher.testBluetoothUuid(
+ BluetoothUuid.parseUuidFrom(hexStringToByteArray("bbbb"))));
+ assertTrue(matcher.testBluetoothUuid(
+ BluetoothUuid.parseUuidFrom(hexStringToByteArray("bbbbbbbb"))));
+ assertFalse(matcher.testBluetoothUuid(
+ BluetoothUuid.parseUuidFrom(hexStringToByteArray("aaaaaaaa"))));
+ }
+
+ @Test
+ public void testSerialize() throws Exception {
+ BytesMatcher matcher = new BytesMatcher();
+ matcher.addRejectRule(hexStringToByteArray("cafe00112233"),
+ hexStringToByteArray("ffffff000000"));
+ matcher.addRejectRule(hexStringToByteArray("beef00112233"),
+ null);
+ matcher.addAcceptRule(hexStringToByteArray("000000000000"),
+ hexStringToByteArray("000000000000"));
+
+ assertFalse(matcher.test(hexStringToByteArray("cafe00ffffff")));
+ assertFalse(matcher.test(hexStringToByteArray("beef00112233")));
+ assertTrue(matcher.test(hexStringToByteArray("beef00ffffff")));
+
+ // Bounce through serialization pass and confirm it still works
+ matcher = BytesMatcher.decode(BytesMatcher.encode(matcher));
+
+ assertFalse(matcher.test(hexStringToByteArray("cafe00ffffff")));
+ assertFalse(matcher.test(hexStringToByteArray("beef00112233")));
+ assertTrue(matcher.test(hexStringToByteArray("beef00ffffff")));
+ }
+
+ @Test
+ public void testOrdering_RejectFirst() throws Exception {
+ BytesMatcher matcher = BytesMatcher.decode("-ff/0f,+ff/f0");
+ assertFalse(matcher.test(hexStringToByteArray("ff")));
+ assertTrue(matcher.test(hexStringToByteArray("f0")));
+ assertFalse(matcher.test(hexStringToByteArray("0f")));
+ }
+
+ @Test
+ public void testOrdering_AcceptFirst() throws Exception {
+ BytesMatcher matcher = BytesMatcher.decode("+ff/f0,-ff/0f");
+ assertTrue(matcher.test(hexStringToByteArray("ff")));
+ assertTrue(matcher.test(hexStringToByteArray("f0")));
+ assertFalse(matcher.test(hexStringToByteArray("0f")));
+ }
+}
diff --git a/core/tests/coretests/src/android/os/VibratorInfoTest.java b/core/tests/coretests/src/android/os/VibratorInfoTest.java
index 8941190..c06405a 100644
--- a/core/tests/coretests/src/android/os/VibratorInfoTest.java
+++ b/core/tests/coretests/src/android/os/VibratorInfoTest.java
@@ -20,6 +20,7 @@
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+import android.hardware.vibrator.IVibrator;
import android.platform.test.annotations.Presubmit;
import org.junit.Test;
@@ -33,16 +34,16 @@
@Test
public void testHasAmplitudeControl() {
assertFalse(createInfo(/* capabilities= */ 0).hasAmplitudeControl());
- assertTrue(createInfo(VibratorInfo.CAPABILITY_COMPOSE_EFFECTS
- | VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL).hasAmplitudeControl());
+ assertTrue(createInfo(IVibrator.CAP_COMPOSE_EFFECTS
+ | IVibrator.CAP_AMPLITUDE_CONTROL).hasAmplitudeControl());
}
@Test
public void testHasCapabilities() {
- assertTrue(createInfo(VibratorInfo.CAPABILITY_COMPOSE_EFFECTS)
- .hasCapability(VibratorInfo.CAPABILITY_COMPOSE_EFFECTS));
- assertFalse(createInfo(VibratorInfo.CAPABILITY_COMPOSE_EFFECTS)
- .hasCapability(VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL));
+ assertTrue(createInfo(IVibrator.CAP_COMPOSE_EFFECTS)
+ .hasCapability(IVibrator.CAP_COMPOSE_EFFECTS));
+ assertFalse(createInfo(IVibrator.CAP_COMPOSE_EFFECTS)
+ .hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL));
}
@Test
@@ -59,7 +60,7 @@
@Test
public void testIsPrimitiveSupported() {
- VibratorInfo info = new VibratorInfo(/* id= */ 0, VibratorInfo.CAPABILITY_COMPOSE_EFFECTS,
+ VibratorInfo info = new VibratorInfo(/* id= */ 0, IVibrator.CAP_COMPOSE_EFFECTS,
null, new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK});
assertTrue(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_TICK));
@@ -73,30 +74,30 @@
@Test
public void testEquals() {
VibratorInfo empty = new VibratorInfo(1, 0, null, null);
- VibratorInfo complete = new VibratorInfo(1, VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL,
+ VibratorInfo complete = new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL,
new int[]{VibrationEffect.EFFECT_CLICK},
new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK});
assertEquals(complete, complete);
- assertEquals(complete, new VibratorInfo(1, VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL,
+ assertEquals(complete, new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL,
new int[]{VibrationEffect.EFFECT_CLICK},
new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK}));
assertFalse(empty.equals(new VibratorInfo(1, 0, new int[]{}, new int[]{})));
- assertFalse(complete.equals(new VibratorInfo(1, VibratorInfo.CAPABILITY_COMPOSE_EFFECTS,
+ assertFalse(complete.equals(new VibratorInfo(1, IVibrator.CAP_COMPOSE_EFFECTS,
new int[]{VibrationEffect.EFFECT_CLICK},
new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK})));
- assertFalse(complete.equals(new VibratorInfo(1, VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL,
+ assertFalse(complete.equals(new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL,
new int[]{}, new int[]{})));
- assertFalse(complete.equals(new VibratorInfo(1, VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL,
+ assertFalse(complete.equals(new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL,
null, new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK})));
- assertFalse(complete.equals(new VibratorInfo(1, VibratorInfo.CAPABILITY_AMPLITUDE_CONTROL,
+ assertFalse(complete.equals(new VibratorInfo(1, IVibrator.CAP_AMPLITUDE_CONTROL,
new int[]{VibrationEffect.EFFECT_CLICK}, null)));
}
@Test
public void testSerialization() {
- VibratorInfo original = new VibratorInfo(1, VibratorInfo.CAPABILITY_COMPOSE_EFFECTS,
+ VibratorInfo original = new VibratorInfo(1, IVibrator.CAP_COMPOSE_EFFECTS,
new int[]{VibrationEffect.EFFECT_CLICK}, null);
Parcel parcel = Parcel.obtain();
diff --git a/core/tests/coretests/src/android/security/CredentialManagementAppTest.java b/core/tests/coretests/src/android/security/CredentialManagementAppTest.java
index 366aabd..fa824b1 100644
--- a/core/tests/coretests/src/android/security/CredentialManagementAppTest.java
+++ b/core/tests/coretests/src/android/security/CredentialManagementAppTest.java
@@ -37,8 +37,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
-import java.util.Iterator;
-import java.util.Map;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -149,37 +147,6 @@
private void assertCredentialManagementAppsEqual(CredentialManagementApp actual,
CredentialManagementApp expected) {
assertThat(actual.getPackageName(), is(expected.getPackageName()));
- assertAuthenticationPoliciesEqual(actual.getAuthenticationPolicy(),
- expected.getAuthenticationPolicy());
- }
-
- private void assertAuthenticationPoliciesEqual(AppUriAuthenticationPolicy actual,
- AppUriAuthenticationPolicy expected) {
- Iterator<Map.Entry<String, Map<Uri, String>>> actualIter =
- actual.getAppAndUriMappings().entrySet().iterator();
- Iterator<Map.Entry<String, Map<Uri, String>>> expectedIter =
- expected.getAppAndUriMappings().entrySet().iterator();
-
- assertThat(actual.getAppAndUriMappings().size(),
- is(expected.getAppAndUriMappings().size()));
- while (actualIter.hasNext()) {
- Map.Entry<String, Map<Uri, String>> actualAppToUri = actualIter.next();
- Map.Entry<String, Map<Uri, String>> expectedAppToUri = expectedIter.next();
- assertThat(actualAppToUri.getKey(), is(expectedAppToUri.getKey()));
- assertUrisToAliasesEqual(actualAppToUri.getValue(), expectedAppToUri.getValue());
- }
- }
-
- private void assertUrisToAliasesEqual(Map<Uri, String> actual, Map<Uri, String> expected) {
- Iterator<Map.Entry<Uri, String>> actualIter = actual.entrySet().iterator();
- Iterator<Map.Entry<Uri, String>> expectedIter = expected.entrySet().iterator();
-
- assertThat(actual.size(), is(expected.size()));
- while (actualIter.hasNext()) {
- Map.Entry<Uri, String> actualUriToAlias = actualIter.next();
- Map.Entry<Uri, String> expectedUriToAlias = expectedIter.next();
- assertThat(actualUriToAlias.getKey(), is(expectedUriToAlias.getKey()));
- assertThat(actualUriToAlias.getValue(), is(expectedUriToAlias.getValue()));
- }
+ assertThat(actual.getAuthenticationPolicy(), is(expected.getAuthenticationPolicy()));
}
}
diff --git a/core/tests/coretests/src/android/view/SurfaceControlFpsListenerTest.java b/core/tests/coretests/src/android/view/SurfaceControlFpsListenerTest.java
index 36104cf..c15fc3a 100644
--- a/core/tests/coretests/src/android/view/SurfaceControlFpsListenerTest.java
+++ b/core/tests/coretests/src/android/view/SurfaceControlFpsListenerTest.java
@@ -39,7 +39,7 @@
}
};
- listener.register(new SurfaceControl());
+ listener.register(0);
listener.unregister();
}
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
index ab24f89..7e1e7f4 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
@@ -33,9 +33,6 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import java.util.Arrays;
-import java.util.List;
-
/**
* Tests for AccessibilityInteractionClient
*/
@@ -65,7 +62,7 @@
final long accessibilityNodeId = 0x4321L;
AccessibilityNodeInfo nodeFromConnection = AccessibilityNodeInfo.obtain();
nodeFromConnection.setSourceNodeId(accessibilityNodeId, windowId);
- mMockConnection.mInfosToReturn = Arrays.asList(nodeFromConnection);
+ mMockConnection.mInfoToReturn = nodeFromConnection;
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
AccessibilityNodeInfo node = client.findAccessibilityNodeInfoByAccessibilityId(
MOCK_CONNECTION_ID, windowId, accessibilityNodeId, true, 0, null);
@@ -75,7 +72,7 @@
}
private static class MockConnection extends AccessibilityServiceConnectionImpl {
- List<AccessibilityNodeInfo> mInfosToReturn;
+ AccessibilityNodeInfo mInfoToReturn;
@Override
public String[] findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
@@ -83,7 +80,7 @@
IAccessibilityInteractionConnectionCallback callback, int flags, long threadId,
Bundle arguments) {
try {
- callback.setFindAccessibilityNodeInfosResult(mInfosToReturn, interactionId);
+ callback.setFindAccessibilityNodeInfoResult(mInfoToReturn, interactionId);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
diff --git a/core/tests/coretests/src/com/android/internal/os/DischargedPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryChargeCalculatorTest.java
similarity index 65%
rename from core/tests/coretests/src/com/android/internal/os/DischargedPowerCalculatorTest.java
rename to core/tests/coretests/src/com/android/internal/os/BatteryChargeCalculatorTest.java
index bec3d16..cf126c6 100644
--- a/core/tests/coretests/src/com/android/internal/os/DischargedPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryChargeCalculatorTest.java
@@ -31,7 +31,7 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
-public class DischargedPowerCalculatorTest {
+public class BatteryChargeCalculatorTest {
private static final double PRECISION = 0.00001;
@Rule
@@ -40,27 +40,41 @@
@Test
public void testDischargeTotals() {
+ BatteryChargeCalculator calculator =
+ new BatteryChargeCalculator(mStatsRule.getPowerProfile());
+
final BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
mStatsRule.setTime(1000, 1000);
batteryStats.resetAllStatsCmdLocked();
batteryStats.setNoAutoReset(true);
batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
- /* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0, 1_000_000,
- 1_000_000, 1_000_000);
+ /* plugType */ 0, 90, 72, 3700, 3_600_000, 4_000_000, 0,
+ 1_000_000, 1_000_000, 1_000_000);
batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
- /* plugType */ 0, 80, 72, 3700, 2_400_000, 4_000_000, 0, 2_000_000,
- 2_000_000, 2_000_000);
+ /* plugType */ 0, 85, 72, 3700, 3_000_000, 4_000_000, 0,
+ 1_500_000, 1_500_000, 1_500_000);
+ batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
+ /* plugType */ 0, 80, 72, 3700, 2_400_000, 4_000_000, 0,
+ 2_000_000, 2_000_000, 2_000_000);
- DischargedPowerCalculator calculator =
- new DischargedPowerCalculator(mStatsRule.getPowerProfile());
-
- final BatteryUsageStats batteryUsageStats = mStatsRule.apply(calculator);
+ BatteryUsageStats batteryUsageStats = mStatsRule.apply(calculator);
assertThat(batteryUsageStats.getDischargePercentage()).isEqualTo(10);
assertThat(batteryUsageStats.getDischargedPowerRange().getLower())
.isWithin(PRECISION).of(360.0);
assertThat(batteryUsageStats.getDischargedPowerRange().getUpper())
.isWithin(PRECISION).of(400.0);
+ assertThat(batteryUsageStats.getBatteryTimeRemainingMs()).isEqualTo(8_000_000);
+ assertThat(batteryUsageStats.getChargeTimeRemainingMs()).isEqualTo(-1);
+
+ // Plug in
+ batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_CHARGING, 100,
+ BatteryManager.BATTERY_PLUGGED_USB, 80, 72, 3700, 2_400_000, 4_000_000, 100,
+ 4_000_000, 4_000_000, 4_000_000);
+
+ batteryUsageStats = mStatsRule.apply(calculator);
+
+ assertThat(batteryUsageStats.getChargeTimeRemainingMs()).isEqualTo(100_000);
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index 74c37ada..ee472880 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -23,6 +23,7 @@
@Suite.SuiteClasses({
AmbientDisplayPowerCalculatorTest.class,
AudioPowerCalculatorTest.class,
+ BatteryChargeCalculatorTest.class,
BatteryStatsCpuTimesTest.class,
BatteryStatsBackgroundStatsTest.class,
BatteryStatsBinderCallStatsTest.class,
@@ -49,7 +50,6 @@
CameraPowerCalculatorTest.class,
CpuPowerCalculatorTest.class,
CustomMeasuredPowerCalculatorTest.class,
- DischargedPowerCalculatorTest.class,
FlashlightPowerCalculatorTest.class,
GnssPowerCalculatorTest.class,
IdlePowerCalculatorTest.class,
diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp
index 2f41b90..89644e2 100644
--- a/data/etc/car/Android.bp
+++ b/data/etc/car/Android.bp
@@ -146,6 +146,13 @@
}
prebuilt_etc {
+ name: "allowed_privapp_com.android.car.rotary",
+ sub_dir: "permissions",
+ src: "com.android.car.rotary.xml",
+ filename_from_src: true,
+}
+
+prebuilt_etc {
name: "allowed_privapp_com.android.car.ui.paintbooth",
sub_dir: "permissions",
src: "com.android.car.ui.paintbooth.xml",
diff --git a/data/etc/car/com.android.car.rotary.xml b/data/etc/car/com.android.car.rotary.xml
new file mode 100644
index 0000000..eddef1a
--- /dev/null
+++ b/data/etc/car/com.android.car.rotary.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+<permissions>
+ <privapp-permissions package="com.android.car.rotary">
+ <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
+ <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+ </privapp-permissions>
+</permissions>
+
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index ea42246..77a38a9 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -166,6 +166,7 @@
<assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="audioserver" />
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="audioserver" />
<assign-permission name="android.permission.INTERACT_ACROSS_USERS" uid="audioserver" />
+ <assign-permission name="android.permission.OBSERVE_SENSOR_PRIVACY" uid="audioserver" />
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="cameraserver" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="cameraserver" />
@@ -176,6 +177,7 @@
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="cameraserver" />
<assign-permission name="android.permission.WATCH_APPOPS" uid="cameraserver" />
<assign-permission name="android.permission.MANAGE_APP_OPS_MODES" uid="cameraserver" />
+ <assign-permission name="android.permission.OBSERVE_SENSOR_PRIVACY" uid="cameraserver" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index cabfad4..b7bf8ab 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -43,6 +43,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-2093859262": {
+ "message": "setClientVisible: %s clientVisible=%b Callers=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_APP_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/WindowToken.java"
+ },
"-2072089308": {
"message": "Attempted to add window with token that is a sub-window: %s. Aborting.",
"level": "WARN",
@@ -811,6 +817,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/Task.java"
},
+ "-1159577965": {
+ "message": "Focus requested for input consumer=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_FOCUS_LIGHT",
+ "at": "com\/android\/server\/wm\/InputMonitor.java"
+ },
"-1156118957": {
"message": "Updated config=%s",
"level": "DEBUG",
@@ -823,12 +835,6 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java"
},
- "-1144293044": {
- "message": "SURFACE SET FREEZE LAYER: %s",
- "level": "INFO",
- "group": "WM_SHOW_TRANSACTIONS",
- "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
- },
"-1142279614": {
"message": "Looking for focus: %s, flags=%d, canReceive=%b, reason=%s",
"level": "VERBOSE",
@@ -1831,6 +1837,12 @@
"group": "WM_DEBUG_TASKS",
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
},
+ "63329306": {
+ "message": "commitVisibility: %s: visible=%b mVisibleRequested=%b",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/WallpaperWindowToken.java"
+ },
"73987756": {
"message": "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s",
"level": "INFO",
@@ -2461,6 +2473,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "691515534": {
+ "message": " Commit wallpaper becoming invisible: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"693423992": {
"message": "setAnimationLocked: setting mFocusMayChange true",
"level": "INFO",
diff --git a/errorprone/Android.bp b/errorprone/Android.bp
index d1e94df..a927f53 100644
--- a/errorprone/Android.bp
+++ b/errorprone/Android.bp
@@ -36,11 +36,12 @@
java_test_host {
name: "error_prone_android_framework_test",
- test_suites: ["general-tests"],
srcs: ["tests/java/**/*.java"],
java_resource_dirs: ["tests/res"],
java_resources: [":error_prone_android_framework_testdata"],
static_libs: [
+ "truth-prebuilt",
+ "kxml2-2.3.0",
"error_prone_android_framework_lib",
"error_prone_test_helpers",
"hamcrest-library",
@@ -48,6 +49,9 @@
"platform-test-annotations",
"junit",
],
+ test_options: {
+ unit_test: true,
+ },
}
filegroup {
diff --git a/errorprone/TEST_MAPPING b/errorprone/TEST_MAPPING
deleted file mode 100644
index ee4552f..0000000
--- a/errorprone/TEST_MAPPING
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "presubmit": [
- {
- "name": "error_prone_android_framework_test"
- }
- ]
-}
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index f6f770b..da5162b 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -719,11 +719,11 @@
/** @hide */
public boolean stretch(float left, float top, float right, float bottom,
float vecX, float vecY, float maxStretchAmount) {
- if (1.0 < vecX || vecX < -1.0) {
- throw new IllegalArgumentException("vecX must be in the range [-1, 1], was " + vecX);
+ if (Float.isInfinite(vecX) || Float.isNaN(vecX)) {
+ throw new IllegalArgumentException("vecX must be a finite, non-NaN value " + vecX);
}
- if (1.0 < vecY || vecY < -1.0) {
- throw new IllegalArgumentException("vecY must be in the range [-1, 1], was " + vecY);
+ if (Float.isInfinite(vecY) || Float.isNaN(vecY)) {
+ throw new IllegalArgumentException("vecY must be a finite, non-NaN value " + vecY);
}
if (top >= bottom || left >= right) {
throw new IllegalArgumentException(
@@ -734,7 +734,16 @@
throw new IllegalArgumentException(
"The max stretch amount must be >0, got " + maxStretchAmount);
}
- return nStretch(mNativeRenderNode, left, top, right, bottom, vecX, vecY, maxStretchAmount);
+ return nStretch(
+ mNativeRenderNode,
+ left,
+ top,
+ right,
+ bottom,
+ vecX,
+ vecY,
+ maxStretchAmount
+ );
}
/**
diff --git a/keystore/java/android/security/AppUriAuthenticationPolicy.java b/keystore/java/android/security/AppUriAuthenticationPolicy.java
index 0244ce9..df79912 100644
--- a/keystore/java/android/security/AppUriAuthenticationPolicy.java
+++ b/keystore/java/android/security/AppUriAuthenticationPolicy.java
@@ -238,4 +238,21 @@
return aliases;
}
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof AppUriAuthenticationPolicy)) {
+ return false;
+ }
+ AppUriAuthenticationPolicy other = (AppUriAuthenticationPolicy) obj;
+ return Objects.equals(mAppToUris, other.mAppToUris);
+ }
+
+ @Override
+ public int hashCode() {
+ return mAppToUris.hashCode();
+ }
+
}
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index 684eebe..091f579 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -68,4 +68,7 @@
// APIs used by KeyChainActivity
void setGrant(int uid, String alias, boolean value);
boolean hasGrant(int uid, String alias);
+
+ // API used by Wifi
+ String getWifiKeyGrantAsUser(String alias);
}
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 65a81cd..11cb2b7 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -23,6 +23,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.WorkerThread;
import android.app.Activity;
@@ -1013,6 +1014,54 @@
}
/**
+ * Returns a persistable grant string that allows WiFi stack to access the key using Keystore
+ * SSL engine.
+ *
+ * @return grant string or null if key is not granted or doesn't exist.
+ *
+ * The key should be granted to Process.WIFI_UID.
+ * @hide
+ */
+ @SystemApi
+ @Nullable
+ @WorkerThread
+ public static String getWifiKeyGrantAsUser(
+ @NonNull Context context, @NonNull UserHandle user, @NonNull String alias) {
+ try (KeyChainConnection keyChainConnection =
+ bindAsUser(context.getApplicationContext(), user)) {
+ return keyChainConnection.getService().getWifiKeyGrantAsUser(alias);
+ } catch (RemoteException | RuntimeException e) {
+ Log.i(LOG, "Couldn't get grant for wifi", e);
+ return null;
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ Log.i(LOG, "Interrupted while getting grant for wifi", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns whether the key is granted to WiFi stack.
+ * @hide
+ */
+ @SystemApi
+ @WorkerThread
+ public static boolean hasWifiKeyGrantAsUser(
+ @NonNull Context context, @NonNull UserHandle user, @NonNull String alias) {
+ try (KeyChainConnection keyChainConnection =
+ bindAsUser(context.getApplicationContext(), user)) {
+ return keyChainConnection.getService().hasGrant(Process.WIFI_UID, alias);
+ } catch (RemoteException | RuntimeException e) {
+ Log.i(LOG, "Couldn't query grant for wifi", e);
+ return false;
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ Log.i(LOG, "Interrupted while querying grant for wifi", e);
+ return false;
+ }
+ }
+
+ /**
* Bind to KeyChainService in the target user.
* Caller should call unbindService on the result when finished.
*
diff --git a/keystore/java/android/security/UrisToAliases.java b/keystore/java/android/security/UrisToAliases.java
index 65d433a..9a8b659 100644
--- a/keystore/java/android/security/UrisToAliases.java
+++ b/keystore/java/android/security/UrisToAliases.java
@@ -30,6 +30,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
/**
* The mapping from URI to alias, which determines the alias to use when the user visits a URI.
@@ -135,4 +136,21 @@
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeMap(mUrisToAliases);
}
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof UrisToAliases)) {
+ return false;
+ }
+ UrisToAliases other = (UrisToAliases) obj;
+ return Objects.equals(mUrisToAliases, other.mUrisToAliases);
+ }
+
+ @Override
+ public int hashCode() {
+ return mUrisToAliases.hashCode();
+ }
}
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index c79c12c..72735a7 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -279,8 +279,10 @@
* }
*/
public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAuthArgs {
- private static final X500Principal DEFAULT_CERT_SUBJECT =
+ private static final X500Principal DEFAULT_ATTESTATION_CERT_SUBJECT =
new X500Principal("CN=Android Keystore Key");
+ private static final X500Principal DEFAULT_SELF_SIGNED_CERT_SUBJECT =
+ new X500Principal("CN=Fake");
private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1");
private static final Date DEFAULT_CERT_NOT_BEFORE = new Date(0L); // Jan 1 1970
private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048
@@ -366,7 +368,11 @@
}
if (certificateSubject == null) {
- certificateSubject = DEFAULT_CERT_SUBJECT;
+ if (attestationChallenge == null) {
+ certificateSubject = DEFAULT_SELF_SIGNED_CERT_SUBJECT;
+ } else {
+ certificateSubject = DEFAULT_ATTESTATION_CERT_SUBJECT;
+ }
}
if (certificateNotBefore == null) {
certificateNotBefore = DEFAULT_CERT_NOT_BEFORE;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 1320780..d31e637b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -327,6 +327,10 @@
return mImpl;
}
+ public ShellExecutor getMainExecutor() {
+ return mMainExecutor;
+ }
+
/**
* Hides the current input method, wherever it may be focused, via InputMethodManagerInternal.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index 2f31acd..9ef3fb5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -340,7 +340,7 @@
mSettingsIcon.setVisibility(GONE);
} else {
mTaskView = new TaskView(mContext, mController.getTaskOrganizer());
- mTaskView.setListener(mContext.getMainExecutor(), mTaskViewListener);
+ mTaskView.setListener(mController.getMainExecutor(), mTaskViewListener);
mExpandedViewContainer.addView(mTaskView);
bringChildToFront(mTaskView);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index 6f5f2eb..aab2334 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -234,8 +234,8 @@
final UserHandle user = intent.getParcelableExtra(EXTRA_USER);
mStarter.startShortcut(packageName, id, stage, position, opts, user);
} else {
- mStarter.startIntent(intent.getParcelableExtra(EXTRA_PENDING_INTENT), stage, position,
- opts);
+ mStarter.startIntent(intent.getParcelableExtra(EXTRA_PENDING_INTENT),
+ mContext, null, stage, position, opts);
}
}
@@ -295,7 +295,8 @@
@Nullable Bundle options);
void startShortcut(String packageName, String shortcutId, @StageType int stage,
@StagePosition int position, @Nullable Bundle options, UserHandle user);
- void startIntent(PendingIntent intent, @StageType int stage, @StagePosition int position,
+ void startIntent(PendingIntent intent, Context context, Intent fillInIntent,
+ @StageType int stage, @StagePosition int position,
@Nullable Bundle options);
void enterSplitScreen(int taskId, boolean leftOrTop);
void exitSplitScreen();
@@ -336,10 +337,11 @@
}
@Override
- public void startIntent(PendingIntent intent, int stage, int position,
+ public void startIntent(PendingIntent intent, Context context,
+ @Nullable Intent fillInIntent, int stage, int position,
@Nullable Bundle options) {
try {
- intent.send(null, 0, null, null, null, null, options);
+ intent.send(mContext, 0, fillInIntent, null, null, null, options);
} catch (PendingIntent.CanceledException e) {
Slog.e(TAG, "Failed to launch activity", e);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java
index 0552601..f4c0f93 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java
@@ -52,6 +52,9 @@
private final SyncTransactionQueue mSyncQueue;
private final SparseArray<SurfaceControl> mLeashByTaskId = new SparseArray<>();
+ // TODO(shell-transitions): Remove when switched to shell-transitions.
+ private final SparseArray<Point> mPositionByTaskId = new SparseArray<>();
+
RunningTaskInfo mPrimary;
RunningTaskInfo mSecondary;
SurfaceControl mPrimarySurface;
@@ -167,6 +170,7 @@
@Override
public void onTaskVanished(RunningTaskInfo taskInfo) {
synchronized (this) {
+ mPositionByTaskId.remove(taskInfo.taskId);
if (taskInfo.hasParentTask()) {
mLeashByTaskId.remove(taskInfo.taskId);
return;
@@ -200,16 +204,24 @@
}
synchronized (this) {
if (taskInfo.hasParentTask()) {
+ // changed messages are noisy since it reports on every ensureVisibility. This
+ // conflicts with legacy app-transitions which "swaps" the position to a
+ // leash. For now, only update when position actually changes to avoid
+ // poorly-timed duplicate calls.
+ if (taskInfo.positionInParent.equals(mPositionByTaskId.get(taskInfo.taskId))) {
+ return;
+ }
handleChildTaskChanged(taskInfo);
- return;
+ } else {
+ handleTaskInfoChanged(taskInfo);
}
-
- handleTaskInfoChanged(taskInfo);
+ mPositionByTaskId.put(taskInfo.taskId, new Point(taskInfo.positionInParent));
}
}
private void handleChildTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
mLeashByTaskId.put(taskInfo.taskId, leash);
+ mPositionByTaskId.put(taskInfo.taskId, new Point(taskInfo.positionInParent));
if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
updateChildTaskSurface(taskInfo, leash, true /* firstAppeared */);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
index 37a91d0c..d90cc47 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
@@ -16,17 +16,14 @@
package com.android.wm.shell.onehanded;
-import static android.view.Display.DEFAULT_DISPLAY;
-
import android.content.Context;
import android.content.res.Resources;
import android.graphics.PixelFormat;
-import android.graphics.Point;
import android.graphics.Rect;
-import android.os.Handler;
import android.util.Log;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
+import android.view.WindowManager;
import android.window.DisplayAreaAppearedInfo;
import android.window.DisplayAreaInfo;
import android.window.DisplayAreaOrganizer;
@@ -57,7 +54,7 @@
private final float mAlpha;
private final Rect mRect;
private final Executor mMainExecutor;
- private final Point mDisplaySize = new Point();
+ private final Rect mDisplaySize;
private final OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory
mSurfaceControlTransactionFactory;
@@ -85,15 +82,15 @@
mMainExecutor.execute(() -> removeBackgroundPanelLayer());
}
- public OneHandedBackgroundPanelOrganizer(Context context, DisplayController displayController,
- Executor executor) {
+ public OneHandedBackgroundPanelOrganizer(Context context, WindowManager windowManager,
+ DisplayController displayController, Executor executor) {
super(executor);
- displayController.getDisplay(DEFAULT_DISPLAY).getRealSize(mDisplaySize);
+ mDisplaySize = windowManager.getCurrentWindowMetrics().getBounds();
final Resources res = context.getResources();
final float defaultRGB = res.getFloat(R.dimen.config_one_handed_background_rgb);
mColor = new float[]{defaultRGB, defaultRGB, defaultRGB};
mAlpha = res.getFloat(R.dimen.config_one_handed_background_alpha);
- mRect = new Rect(0, 0, mDisplaySize.x, mDisplaySize.y);
+ mRect = new Rect(0, 0, mDisplaySize.width(), mDisplaySize.height());
mMainExecutor = executor;
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index a1b1de3..d2eb361 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -17,7 +17,6 @@
package com.android.wm.shell.onehanded;
import static android.os.UserHandle.USER_CURRENT;
-import static android.view.Display.DEFAULT_DISPLAY;
import android.content.ComponentName;
import android.content.Context;
@@ -25,7 +24,7 @@
import android.content.om.OverlayInfo;
import android.content.res.Configuration;
import android.database.ContentObserver;
-import android.graphics.Point;
+import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -33,6 +32,7 @@
import android.provider.Settings;
import android.util.Slog;
import android.view.ViewConfiguration;
+import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import androidx.annotation.NonNull;
@@ -82,6 +82,7 @@
private final ShellExecutor mMainExecutor;
private final Handler mMainHandler;
private final OneHandedImpl mImpl = new OneHandedImpl();
+ private final WindowManager mWindowManager;
private OneHandedDisplayAreaOrganizer mDisplayAreaOrganizer;
private final AccessibilityManager mAccessibilityManager;
@@ -141,7 +142,7 @@
*/
@Nullable
public static OneHandedController create(
- Context context, DisplayController displayController,
+ Context context, WindowManager windowManager, DisplayController displayController,
TaskStackListenerImpl taskStackListener, UiEventLogger uiEventLogger,
ShellExecutor mainExecutor, Handler mainHandler) {
if (!SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) {
@@ -151,22 +152,24 @@
OneHandedTimeoutHandler timeoutHandler = new OneHandedTimeoutHandler(mainExecutor);
OneHandedTutorialHandler tutorialHandler = new OneHandedTutorialHandler(context,
- mainExecutor);
+ windowManager, mainExecutor);
OneHandedAnimationController animationController =
new OneHandedAnimationController(context);
OneHandedTouchHandler touchHandler = new OneHandedTouchHandler(timeoutHandler,
mainExecutor);
OneHandedGestureHandler gestureHandler = new OneHandedGestureHandler(
- context, displayController, ViewConfiguration.get(context), mainExecutor);
+ context, windowManager, displayController, ViewConfiguration.get(context),
+ mainExecutor);
OneHandedBackgroundPanelOrganizer oneHandedBackgroundPanelOrganizer =
- new OneHandedBackgroundPanelOrganizer(context, displayController, mainExecutor);
+ new OneHandedBackgroundPanelOrganizer(context, windowManager, displayController,
+ mainExecutor);
OneHandedDisplayAreaOrganizer organizer = new OneHandedDisplayAreaOrganizer(
- context, displayController, animationController, tutorialHandler,
+ context, windowManager, displayController, animationController, tutorialHandler,
oneHandedBackgroundPanelOrganizer, mainExecutor);
OneHandedUiEventLogger oneHandedUiEventsLogger = new OneHandedUiEventLogger(uiEventLogger);
IOverlayManager overlayManager = IOverlayManager.Stub.asInterface(
ServiceManager.getService(Context.OVERLAY_SERVICE));
- return new OneHandedController(context, displayController,
+ return new OneHandedController(context, windowManager, displayController,
oneHandedBackgroundPanelOrganizer, organizer, touchHandler, tutorialHandler,
gestureHandler, timeoutHandler, oneHandedUiEventsLogger, overlayManager,
taskStackListener, mainExecutor, mainHandler);
@@ -174,6 +177,7 @@
@VisibleForTesting
OneHandedController(Context context,
+ WindowManager windowManager,
DisplayController displayController,
OneHandedBackgroundPanelOrganizer backgroundPanelOrganizer,
OneHandedDisplayAreaOrganizer displayAreaOrganizer,
@@ -187,6 +191,7 @@
ShellExecutor mainExecutor,
Handler mainHandler) {
mContext = context;
+ mWindowManager = windowManager;
mBackgroundPanelOrganizer = backgroundPanelOrganizer;
mDisplayAreaOrganizer = displayAreaOrganizer;
mDisplayController = displayController;
@@ -269,7 +274,7 @@
return;
}
if (!mDisplayAreaOrganizer.isInOneHanded()) {
- final int yOffSet = Math.round(getDisplaySize().y * mOffSetFraction);
+ final int yOffSet = Math.round(getDisplaySize().height() * mOffSetFraction);
mDisplayAreaOrganizer.scheduleOffset(0, yOffSet);
mTimeoutHandler.resetTimer();
@@ -426,14 +431,19 @@
}
/**
- * Query the current display real size from {@link DisplayController}
+ * Query the current display real size from {@link WindowManager}
*
- * @return {@link DisplayController#getDisplay(int)#getDisplaySize()}
+ * @return {@link WindowManager#getCurrentWindowMetrics()#getBounds()}
*/
- private Point getDisplaySize() {
- Point displaySize = new Point();
- if (mDisplayController != null && mDisplayController.getDisplay(DEFAULT_DISPLAY) != null) {
- mDisplayController.getDisplay(DEFAULT_DISPLAY).getRealSize(displaySize);
+ private Rect getDisplaySize() {
+ if (mWindowManager == null) {
+ Slog.e(TAG, "WindowManager instance is null! Can not get display size!");
+ return new Rect();
+ }
+ final Rect displaySize = mWindowManager.getCurrentWindowMetrics().getBounds();
+ if (displaySize.width() == 0 || displaySize.height() == 0) {
+ Slog.e(TAG, "Display size error! width = " + displaySize.width()
+ + ", height = " + displaySize.height());
}
return displaySize;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
index 4c5cc22..0238fa8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -16,17 +16,16 @@
package com.android.wm.shell.onehanded;
-import static android.view.Display.DEFAULT_DISPLAY;
-
import static com.android.wm.shell.onehanded.OneHandedAnimationController.TRANSITION_DIRECTION_EXIT;
import static com.android.wm.shell.onehanded.OneHandedAnimationController.TRANSITION_DIRECTION_TRIGGER;
import android.content.Context;
-import android.graphics.Point;
import android.graphics.Rect;
import android.os.SystemProperties;
import android.util.ArrayMap;
+import android.util.Slog;
import android.view.SurfaceControl;
+import android.view.WindowManager;
import android.window.DisplayAreaAppearedInfo;
import android.window.DisplayAreaInfo;
import android.window.DisplayAreaOrganizer;
@@ -60,6 +59,7 @@
private static final String ONE_HANDED_MODE_TRANSLATE_ANIMATION_DURATION =
"persist.debug.one_handed_translate_animation_duration";
+ private final WindowManager mWindowManager;
private final Rect mLastVisualDisplayBounds = new Rect();
private final Rect mDefaultDisplayBounds = new Rect();
@@ -110,12 +110,14 @@
* Constructor of OneHandedDisplayAreaOrganizer
*/
public OneHandedDisplayAreaOrganizer(Context context,
+ WindowManager windowManager,
DisplayController displayController,
OneHandedAnimationController animationController,
OneHandedTutorialHandler tutorialHandler,
OneHandedBackgroundPanelOrganizer oneHandedBackgroundGradientOrganizer,
ShellExecutor mainExecutor) {
super(mainExecutor);
+ mWindowManager = windowManager;
mAnimationController = animationController;
mDisplayController = displayController;
mLastVisualDisplayBounds.set(getDisplayBounds());
@@ -292,11 +294,16 @@
@Nullable
private Rect getDisplayBounds() {
- Point realSize = new Point(0, 0);
- if (mDisplayController != null && mDisplayController.getDisplay(DEFAULT_DISPLAY) != null) {
- mDisplayController.getDisplay(DEFAULT_DISPLAY).getRealSize(realSize);
+ if (mWindowManager == null) {
+ Slog.e(TAG, "WindowManager instance is null! Can not get display size!");
+ return new Rect();
}
- return new Rect(0, 0, realSize.x, realSize.y);
+ final Rect displayBounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+ if (displayBounds.width() == 0 || displayBounds.height() == 0) {
+ Slog.e(TAG, "Display size error! width = " + displayBounds.width()
+ + ", height = " + displayBounds.height());
+ }
+ return displayBounds;
}
@VisibleForTesting
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java
index 91e649f..b86b954 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedGestureHandler.java
@@ -20,7 +20,6 @@
import android.annotation.Nullable;
import android.content.Context;
-import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.hardware.input.InputManager;
@@ -34,6 +33,7 @@
import android.view.MotionEvent;
import android.view.Surface;
import android.view.ViewConfiguration;
+import android.view.WindowManager;
import android.window.WindowContainerTransaction;
import androidx.annotation.VisibleForTesting;
@@ -59,8 +59,9 @@
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
private final PointF mStartDragPos = new PointF();
- private boolean mPassedSlop;
+ private final WindowManager mWindowManager;
+ private boolean mPassedSlop;
private boolean mAllowGesture;
private boolean mIsEnabled;
private int mNavGestureHeight;
@@ -86,9 +87,10 @@
* @param context {@link Context}
* @param displayController {@link DisplayController}
*/
- public OneHandedGestureHandler(Context context, DisplayController displayController,
- ViewConfiguration viewConfig,
+ public OneHandedGestureHandler(Context context, WindowManager windowManager,
+ DisplayController displayController, ViewConfiguration viewConfig,
ShellExecutor mainExecutor) {
+ mWindowManager = windowManager;
mDisplayController = displayController;
mMainExecutor = mainExecutor;
displayController.addDisplayChangingController(this);
@@ -210,16 +212,10 @@
disposeInputChannel();
if (mIsEnabled && mIsThreeButtonModeEnabled) {
- final Point displaySize = new Point();
- if (mDisplayController != null) {
- final Display display = mDisplayController.getDisplay(DEFAULT_DISPLAY);
- if (display != null) {
- display.getRealSize(displaySize);
- }
- }
+ final Rect displaySize = mWindowManager.getCurrentWindowMetrics().getBounds();
// Register input event receiver to monitor the touch region of NavBar gesture height
- mGestureRegion.set(0, displaySize.y - mNavGestureHeight, displaySize.x,
- displaySize.y);
+ mGestureRegion.set(0, displaySize.height() - mNavGestureHeight, displaySize.width(),
+ displaySize.height());
mInputMonitor = InputManager.getInstance().monitorGestureInput(
"onehanded-gesture-offset", DEFAULT_DISPLAY);
try {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
index 3f72b80..d539835 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
@@ -20,7 +20,6 @@
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
-import android.graphics.Point;
import android.graphics.Rect;
import android.os.SystemProperties;
import android.provider.Settings;
@@ -51,14 +50,13 @@
private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE =
"persist.debug.one_handed_offset_percentage";
private static final int MAX_TUTORIAL_SHOW_COUNT = 2;
- private final Rect mLastUpdatedBounds = new Rect();
private final WindowManager mWindowManager;
private final AccessibilityManager mAccessibilityManager;
private final String mPackageName;
+ private final Rect mDisplaySize;
private Context mContext;
private View mTutorialView;
- private Point mDisplaySize = new Point();
private ContentResolver mContentResolver;
private boolean mCanShowTutorial;
private String mStartOneHandedDescription;
@@ -101,14 +99,14 @@
}
};
- public OneHandedTutorialHandler(Context context, ShellExecutor mainExecutor) {
+ public OneHandedTutorialHandler(Context context, WindowManager windowManager,
+ ShellExecutor mainExecutor) {
mContext = context;
- context.getDisplay().getRealSize(mDisplaySize);
+ mWindowManager = windowManager;
+ mDisplaySize = windowManager.getCurrentWindowMetrics().getBounds();
mPackageName = context.getPackageName();
mContentResolver = context.getContentResolver();
- mWindowManager = context.getSystemService(WindowManager.class);
mAccessibilityManager = AccessibilityManager.getInstance(context);
-
mStartOneHandedDescription = context.getResources().getString(
R.string.accessibility_action_start_one_handed);
mStopOneHandedDescription = context.getResources().getString(
@@ -121,7 +119,8 @@
R.fraction.config_one_handed_offset, 1, 1);
final int sysPropPercentageConfig = SystemProperties.getInt(
ONE_HANDED_MODE_OFFSET_PERCENTAGE, Math.round(offsetPercentageConfig * 100.0f));
- mTutorialAreaHeight = Math.round(mDisplaySize.y * (sysPropPercentageConfig / 100.0f));
+ mTutorialAreaHeight = Math.round(
+ mDisplaySize.height() * (sysPropPercentageConfig / 100.0f));
mainExecutor.execute(() -> {
recreateTutorialView(mContext);
@@ -214,7 +213,7 @@
*/
private WindowManager.LayoutParams getTutorialTargetLayoutParams() {
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- mDisplaySize.x, mTutorialAreaHeight, 0, 0,
+ mDisplaySize.width(), mTutorialAreaHeight, 0, 0,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
@@ -228,9 +227,13 @@
void dump(@NonNull PrintWriter pw) {
final String innerPrefix = " ";
- pw.println(TAG + "states: ");
- pw.print(innerPrefix + "mLastUpdatedBounds=");
- pw.println(mLastUpdatedBounds);
+ pw.println(TAG + " states: ");
+ pw.print(innerPrefix + "mTriggerState=");
+ pw.println(mTriggerState);
+ pw.print(innerPrefix + "mDisplaySize=");
+ pw.println(mDisplaySize);
+ pw.print(innerPrefix + "mTutorialAreaHeight=");
+ pw.println(mTutorialAreaHeight);
}
private boolean canShowTutorial() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 843e27f..7ed7fd0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -172,6 +172,10 @@
};
private ActivityManager.RunningTaskInfo mTaskInfo;
+ // To handle the edge case that onTaskInfoChanged callback is received during the entering
+ // PiP transition, where we do not want to intercept the transition but still want to apply the
+ // changed RunningTaskInfo when it finishes.
+ private ActivityManager.RunningTaskInfo mDeferredTaskInfo;
private WindowContainerToken mToken;
private SurfaceControl mLeash;
private State mState = State.UNDEFINED;
@@ -520,12 +524,18 @@
mPipTransitionController.sendOnPipTransitionStarted(direction);
}
- private void sendOnPipTransitionFinished(
+ @VisibleForTesting
+ void sendOnPipTransitionFinished(
@PipAnimationController.TransitionDirection int direction) {
if (direction == TRANSITION_DIRECTION_TO_PIP) {
mState = State.ENTERED_PIP;
}
mPipTransitionController.sendOnPipTransitionFinished(direction);
+ // Apply the deferred RunningTaskInfo if applicable after all proper callbacks are sent.
+ if (direction == TRANSITION_DIRECTION_TO_PIP && mDeferredTaskInfo != null) {
+ onTaskInfoChanged(mDeferredTaskInfo);
+ mDeferredTaskInfo = null;
+ }
}
private void sendOnPipTransitionCancelled(
@@ -567,6 +577,11 @@
@Override
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
Objects.requireNonNull(mToken, "onTaskInfoChanged requires valid existing mToken");
+ if (mState != State.ENTERED_PIP) {
+ Log.d(TAG, "Defer onTaskInfoChange in current state: " + mState);
+ mDeferredTaskInfo = info;
+ return;
+ }
mPipBoundsState.setLastPipComponentName(info.topActivity);
mPipBoundsState.setOverrideMinSize(
mPipBoundsAlgorithm.getMinimalSize(info.topActivityInfo));
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index 31057f8..c726c01 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -65,6 +65,8 @@
private static final int PINCH_RESIZE_SNAP_DURATION = 250;
private static final int PINCH_RESIZE_MAX_ANGLE_ROTATION = 45;
private static final float PINCH_RESIZE_AUTO_MAX_RATIO = 0.9f;
+ private static final float OVERROTATE_DAMP_FACTOR = 0.4f;
+ private static final float ANGLE_THRESHOLD = 5f;
private final Context mContext;
private final PipBoundsAlgorithm mPipBoundsAlgorithm;
@@ -423,26 +425,28 @@
float down1X = mDownSecondaryPoint.x;
float down1Y = mDownSecondaryPoint.y;
+ float angle = 0;
if (down0X > focusX && down0Y < focusY && down1X < focusX && down1Y > focusY) {
// Top right + Bottom left pinch to zoom.
- mAngle = calculateRotationAngle(mLastResizeBounds.centerX(),
+ angle = calculateRotationAngle(mLastResizeBounds.centerX(),
mLastResizeBounds.centerY(), x0, y0, x1, y1, true);
} else if (down1X > focusX && down1Y < focusY
&& down0X < focusX && down0Y > focusY) {
// Top right + Bottom left pinch to zoom.
- mAngle = calculateRotationAngle(mLastResizeBounds.centerX(),
+ angle = calculateRotationAngle(mLastResizeBounds.centerX(),
mLastResizeBounds.centerY(), x1, y1, x0, y0, true);
} else if (down0X < focusX && down0Y < focusY
&& down1X > focusX && down1Y > focusY) {
// Top left + bottom right pinch to zoom.
- mAngle = calculateRotationAngle(mLastResizeBounds.centerX(),
+ angle = calculateRotationAngle(mLastResizeBounds.centerX(),
mLastResizeBounds.centerY(), x0, y0, x1, y1, false);
} else if (down1X < focusX && down1Y < focusY
&& down0X > focusX && down0Y > focusY) {
// Top left + bottom right pinch to zoom.
- mAngle = calculateRotationAngle(mLastResizeBounds.centerX(),
+ angle = calculateRotationAngle(mLastResizeBounds.centerX(),
mLastResizeBounds.centerY(), x1, y1, x0, y0, false);
}
+ mAngle = angle;
mLastResizeBounds.set(PipPinchResizingAlgorithm.pinchResize(x0, y0, x1, y1,
mDownPoint.x, mDownPoint.y, mDownSecondaryPoint.x, mDownSecondaryPoint.y,
@@ -477,10 +481,40 @@
}
// Calculate the percentage difference of [0, 90] compare to the base angle.
- double diff0 = (Math.max(0, Math.min(angle0, 90)) - baseAngle) / 90;
- double diff1 = (Math.max(0, Math.min(angle1, 90)) - baseAngle) / 90;
+ double diff0 = (Math.max(-90, Math.min(angle0, 90)) - baseAngle) / 90;
+ double diff1 = (Math.max(-90, Math.min(angle1, 90)) - baseAngle) / 90;
- return (float) (diff0 + diff1) / 2 * PINCH_RESIZE_MAX_ANGLE_ROTATION * (positive ? 1 : -1);
+ final float angle =
+ (float) (diff0 + diff1) / 2 * PINCH_RESIZE_MAX_ANGLE_ROTATION * (positive ? 1 : -1);
+
+ // Remove some degrees so that user doesn't immediately start rotating until a threshold
+ return angle / Math.abs(angle)
+ * Math.max(0, (Math.abs(dampedRotate(angle)) - ANGLE_THRESHOLD));
+ }
+
+ /**
+ * Given the current rotation angle, dampen it so that as it approaches the maximum angle,
+ * dampen it.
+ */
+ private float dampedRotate(float amount) {
+ if (Float.compare(amount, 0) == 0) return 0;
+
+ float f = amount / PINCH_RESIZE_MAX_ANGLE_ROTATION;
+ f = f / (Math.abs(f)) * (overRotateInfluenceCurve(Math.abs(f)));
+
+ // Clamp this factor, f, to -1 < f < 1
+ if (Math.abs(f) >= 1) {
+ f /= Math.abs(f);
+ }
+ return OVERROTATE_DAMP_FACTOR * f * PINCH_RESIZE_MAX_ANGLE_ROTATION;
+ }
+
+ /**
+ * Returns a value that corresponds to y = (f - 1)^3 + 1.
+ */
+ private float overRotateInfluenceCurve(float f) {
+ f -= 1.0f;
+ return f * f * f + 1.0f;
}
private void onDragCornerResize(MotionEvent ev) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index 7ca5693..25a84bd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -19,18 +19,17 @@
import android.annotation.IntDef;
import android.app.ActivityManager;
import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.UserHandle;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.draganddrop.DragAndDropPolicy;
-import java.io.PrintWriter;
-
/**
* Interface to engage split-screen feature.
* TODO: Figure out which of these are actually needed outside of the Shell
@@ -87,7 +86,7 @@
/** Callback interface for listening to changes in a split-screen stage. */
interface SplitScreenListener {
void onStagePositionChanged(@StageType int stage, @StagePosition int position);
- void onTaskStageChanged(int taskId, @StageType int stage);
+ void onTaskStageChanged(int taskId, @StageType int stage, boolean visible);
}
/** @return {@code true} if split-screen is currently visible. */
@@ -118,6 +117,7 @@
@StageType int stage, @StagePosition int position, @Nullable Bundle options);
void startShortcut(String packageName, String shortcutId, @StageType int stage,
@StagePosition int position, @Nullable Bundle options, UserHandle user);
- void startIntent(PendingIntent intent,
- @StageType int stage, @StagePosition int position, @Nullable Bundle options);
+ void startIntent(PendingIntent intent, Context context,
+ @Nullable Intent fillInIntent, @StageType int stage,
+ @StagePosition int position, @Nullable Bundle options);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 11548ad..bb6f6f2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -30,6 +30,7 @@
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.LauncherApps;
import android.graphics.Rect;
import android.os.Bundle;
@@ -171,12 +172,13 @@
}
}
- public void startIntent(PendingIntent intent, @SplitScreen.StageType int stage,
+ public void startIntent(PendingIntent intent, Context context,
+ Intent fillInIntent, @SplitScreen.StageType int stage,
@SplitScreen.StagePosition int position, @Nullable Bundle options) {
options = resolveStartStage(stage, position, options);
try {
- intent.send(null, 0, null, null, null, null, options);
+ intent.send(context, 0, fillInIntent, null, null, null, options);
} catch (PendingIntent.CanceledException e) {
Slog.e(TAG, "Failed to launch activity", e);
}
@@ -348,10 +350,11 @@
}
@Override
- public void startIntent(PendingIntent intent, int stage, int position,
- @Nullable Bundle options) {
+ public void startIntent(PendingIntent intent, Context context, Intent fillInIntent,
+ int stage, int position, @Nullable Bundle options) {
mMainExecutor.execute(() -> {
- SplitScreenController.this.startIntent(intent, stage, position, options);
+ SplitScreenController.this.startIntent(intent, context, fillInIntent, stage,
+ position, options);
});
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index bbfbc40..b180bb5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -225,7 +225,7 @@
}
private void onStageChildTaskStatusChanged(
- StageListenerImpl stageListener, int taskId, boolean present) {
+ StageListenerImpl stageListener, int taskId, boolean present, boolean visible) {
int stage;
if (present) {
@@ -236,7 +236,7 @@
}
for (int i = mListeners.size() - 1; i >= 0; --i) {
- mListeners.get(i).onTaskStageChanged(taskId, stage);
+ mListeners.get(i).onTaskStageChanged(taskId, stage, visible);
}
}
@@ -495,8 +495,8 @@
}
@Override
- public void onChildTaskStatusChanged(int taskId, boolean present) {
- StageCoordinator.this.onStageChildTaskStatusChanged(this, taskId, present);
+ public void onChildTaskStatusChanged(int taskId, boolean present, boolean visible) {
+ StageCoordinator.this.onStageChildTaskStatusChanged(this, taskId, present, visible);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 10c742b..b8cdc4ab4d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -58,7 +58,7 @@
public interface StageListenerCallbacks {
void onRootTaskAppeared();
void onStatusChanged(boolean visible, boolean hasChildren);
- void onChildTaskStatusChanged(int taskId, boolean present);
+ void onChildTaskStatusChanged(int taskId, boolean present, boolean visible);
void onRootTaskVanished();
}
private final StageListenerCallbacks mCallbacks;
@@ -88,7 +88,7 @@
mChildrenLeashes.put(taskId, leash);
mChildrenTaskInfo.put(taskId, taskInfo);
updateChildTaskSurface(taskInfo, leash, true /* firstAppeared */);
- mCallbacks.onChildTaskStatusChanged(taskId, true /* present */);
+ mCallbacks.onChildTaskStatusChanged(taskId, true /* present */, taskInfo.isVisible);
} else {
throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo
+ "\n mRootTaskInfo: " + mRootTaskInfo);
@@ -105,6 +105,8 @@
mChildrenTaskInfo.put(taskInfo.taskId, taskInfo);
updateChildTaskSurface(
taskInfo, mChildrenLeashes.get(taskInfo.taskId), false /* firstAppeared */);
+ mCallbacks.onChildTaskStatusChanged(taskInfo.taskId, true /* present */,
+ taskInfo.isVisible);
} else {
throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo
+ "\n mRootTaskInfo: " + mRootTaskInfo);
@@ -123,7 +125,7 @@
mChildrenTaskInfo.remove(taskId);
mChildrenLeashes.remove(taskId);
sendStatusChanged();
- mCallbacks.onChildTaskStatusChanged(taskId, false /* present */);
+ mCallbacks.onChildTaskStatusChanged(taskId, false /* present */, taskInfo.isVisible);
} else {
throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo
+ "\n mRootTaskInfo: " + mRootTaskInfo);
@@ -152,7 +154,9 @@
void onSplitScreenListenerRegistered(SplitScreen.SplitScreenListener listener,
@SplitScreen.StageType int stage) {
for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
- listener.onTaskStageChanged(mChildrenTaskInfo.keyAt(i), stage);
+ int taskId = mChildrenTaskInfo.keyAt(i);
+ listener.onTaskStageChanged(taskId, stage,
+ mChildrenTaskInfo.get(taskId).isVisible);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
index 2c4ceff..a594a9f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
@@ -19,6 +19,7 @@
import android.os.IBinder;
import android.window.StartingWindowInfo;
+import java.util.function.BiConsumer;
/**
* Interface to engage starting window feature.
*/
@@ -36,4 +37,11 @@
* @param taskId
*/
void copySplashScreenView(int taskId);
+
+ /**
+ * Registers the starting window listener.
+ *
+ * @param listener The callback when need a starting window.
+ */
+ void setStartingWindowListener(BiConsumer<Integer, Integer> listener);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
index 73bf8ac..1ac05fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -25,6 +25,7 @@
import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
+import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
import android.content.Context;
import android.os.IBinder;
@@ -36,6 +37,8 @@
import com.android.wm.shell.common.ShellExecutor;
+import java.util.function.BiConsumer;
+
/**
* Implementation to draw the starting window to an application, and remove the starting window
* until the application displays its own window.
@@ -53,6 +56,8 @@
private final StartingSurfaceDrawer mStartingSurfaceDrawer;
private final StartingTypeChecker mStartingTypeChecker = new StartingTypeChecker();
+
+ private BiConsumer<Integer, Integer> mTaskLaunchingCallback;
private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl();
public StartingWindowController(Context context, ShellExecutor mainExecutor) {
@@ -151,11 +156,24 @@
}
}
+ /*
+ * Registers the starting window listener.
+ *
+ * @param listener The callback when need a starting window.
+ */
+ void setStartingWindowListener(BiConsumer<Integer, Integer> listener) {
+ mTaskLaunchingCallback = listener;
+ }
+
/**
* Called when a task need a starting window.
*/
void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
final int suggestionType = mStartingTypeChecker.estimateStartingWindowType(windowInfo);
+ final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo;
+ if (mTaskLaunchingCallback != null) {
+ mTaskLaunchingCallback.accept(runningTaskInfo.taskId, suggestionType);
+ }
if (suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken);
} else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) {
@@ -192,5 +210,10 @@
public void copySplashScreenView(int taskId) {
StartingWindowController.this.copySplashScreenView(taskId);
}
+
+ @Override
+ public void setStartingWindowListener(BiConsumer<Integer, Integer> listener) {
+ StartingWindowController.this.setStartingWindowListener(listener);
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 2182ee5..629ff0d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -97,8 +97,8 @@
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
- // Don't animate anything with an animating parent
- if (change.getParent() != null) continue;
+ // Don't animate anything that isn't independent.
+ if (!TransitionInfo.isIndependent(change, info)) continue;
Animation a = loadAnimation(info.getType(), change);
if (a != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 89eee67..677db10 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -214,8 +214,8 @@
final SurfaceControl leash = change.getLeash();
final int mode = info.getChanges().get(i).getMode();
- // Don't move anything with an animating parent
- if (change.getParent() != null) {
+ // Don't move anything that isn't independent within its parents
+ if (!TransitionInfo.isIndependent(change, info)) {
if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT || mode == TRANSIT_CHANGE) {
t.show(leash);
t.setMatrix(leash, 1, 0, 0, 1);
@@ -225,9 +225,13 @@
continue;
}
- t.reparent(leash, info.getRootLeash());
- t.setPosition(leash, change.getStartAbsBounds().left - info.getRootOffset().x,
- change.getStartAbsBounds().top - info.getRootOffset().y);
+ boolean hasParent = change.getParent() != null;
+
+ if (!hasParent) {
+ t.reparent(leash, info.getRootLeash());
+ t.setPosition(leash, change.getStartAbsBounds().left - info.getRootOffset().x,
+ change.getStartAbsBounds().top - info.getRootOffset().y);
+ }
// Put all the OPEN/SHOW on top
if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
t.show(leash);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index 19ecc49..c1c4c6d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -205,7 +205,7 @@
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
}
@@ -217,12 +217,12 @@
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
}
@@ -234,12 +234,12 @@
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
}
@@ -251,7 +251,7 @@
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
}
@@ -263,7 +263,7 @@
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
}
@@ -276,13 +276,13 @@
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter);
// TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
}
@@ -295,13 +295,13 @@
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter);
// TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
- verify(mSplitScreenStarter).startIntent(any(),
+ verify(mSplitScreenStarter).startIntent(any(), any(), any(),
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java
index b0f52cf..d6bcf03 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizerTest.java
@@ -69,7 +69,7 @@
mDisplayAreaInfo = new DisplayAreaInfo(mToken, DEFAULT_DISPLAY,
FEATURE_ONE_HANDED_BACKGROUND_PANEL);
- mBackgroundPanelOrganizer = new OneHandedBackgroundPanelOrganizer(mContext,
+ mBackgroundPanelOrganizer = new OneHandedBackgroundPanelOrganizer(mContext, mWindowManager,
mMockDisplayController, Runnable::run);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index 1ad8fd3..c5221de 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -100,6 +100,7 @@
mSpiedOneHandedController = spy(new OneHandedController(
mContext,
+ mWindowManager,
mMockDisplayController,
mMockBackgroundOrganizer,
mMockDisplayAreaOrganizer,
@@ -120,8 +121,8 @@
final OneHandedAnimationController animationController = new OneHandedAnimationController(
mContext);
OneHandedDisplayAreaOrganizer displayAreaOrganizer = new OneHandedDisplayAreaOrganizer(
- mContext, mMockDisplayController, animationController, mMockTutorialHandler,
- mMockBackgroundOrganizer, mMockShellMainExecutor);
+ mContext, mWindowManager, mMockDisplayController, animationController,
+ mMockTutorialHandler, mMockBackgroundOrganizer, mMockShellMainExecutor);
assertThat(displayAreaOrganizer.isInOneHanded()).isFalse();
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
index 7a826c1..1fa1e2f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
@@ -121,6 +121,7 @@
when(mMockLeash.getHeight()).thenReturn(DISPLAY_HEIGHT);
mSpiedDisplayAreaOrganizer = spy(new OneHandedDisplayAreaOrganizer(mContext,
+ mWindowManager,
mMockDisplayController,
mMockAnimationController,
mTutorialHandler,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedGestureHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedGestureHandlerTest.java
index b275b70..f58affc 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedGestureHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedGestureHandlerTest.java
@@ -44,8 +44,9 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mGestureHandler = new OneHandedGestureHandler(mContext, mMockDisplayController,
- ViewConfiguration.get(mTestContext), mMockShellMainExecutor);
+ mGestureHandler = new OneHandedGestureHandler(mContext, mWindowManager,
+ mMockDisplayController, ViewConfiguration.get(mTestContext),
+ mMockShellMainExecutor);
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTestCase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTestCase.java
index 32a188d..8b03dc5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTestCase.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTestCase.java
@@ -26,6 +26,7 @@
import android.hardware.display.DisplayManager;
import android.os.SystemProperties;
import android.testing.TestableContext;
+import android.view.WindowManager;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -45,6 +46,9 @@
public TestableContext mTestContext = new TestableContext(
InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ protected WindowManager mWindowManager;
+
@Before
public void setUpContext() {
assumeTrue(SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false));
@@ -53,6 +57,12 @@
mContext = getTestContext().createDisplayContext(dm.getDisplay(DEFAULT_DISPLAY));
}
+ @Before
+ public void setUpWindowManager() {
+ assumeTrue(SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false));
+ mWindowManager = getTestContext().getSystemService(WindowManager.class);
+ }
+
/** return testable context */
protected TestableContext getTestContext() {
return mTestContext;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
index 024cf7f..69c537c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
@@ -65,7 +65,6 @@
@Mock
OneHandedUiEventLogger mMockUiEventLogger;
-
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -73,7 +72,8 @@
when(mMockDisplayAreaOrganizer.getDisplayAreaTokenMap()).thenReturn(new ArrayMap<>());
mOneHandedController = new OneHandedController(
- getContext(),
+ mContext,
+ mWindowManager,
mMockDisplayController,
mMockBackgroundOrganizer,
mMockDisplayAreaOrganizer,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 79ec624..195b701 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -16,6 +16,8 @@
package com.android.wm.shell.pip;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
+
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -162,12 +164,30 @@
}
@Test
- public void onTaskInfoChanged_updatesAspectRatioIfChanged() {
+ public void onTaskInfoChanged_notInPip_deferUpdatesAspectRatio() {
final Rational startAspectRatio = new Rational(2, 1);
final Rational newAspectRatio = new Rational(1, 2);
mSpiedPipTaskOrganizer.onTaskAppeared(createTaskInfo(mComponent1,
createPipParams(startAspectRatio)), null /* leash */);
+ // It is in entering transition, should defer onTaskInfoChanged callback in this case.
+ mSpiedPipTaskOrganizer.onTaskInfoChanged(createTaskInfo(mComponent1,
+ createPipParams(newAspectRatio)));
+ assertEquals(startAspectRatio.floatValue(), mPipBoundsState.getAspectRatio(), 0.01f);
+
+ // Once the entering transition finishes, the new aspect ratio applies in a deferred manner
+ mSpiedPipTaskOrganizer.sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
+ assertEquals(newAspectRatio.floatValue(), mPipBoundsState.getAspectRatio(), 0.01f);
+ }
+
+ @Test
+ public void onTaskInfoChanged_inPip_updatesAspectRatioIfChanged() {
+ final Rational startAspectRatio = new Rational(2, 1);
+ final Rational newAspectRatio = new Rational(1, 2);
+ mSpiedPipTaskOrganizer.onTaskAppeared(createTaskInfo(mComponent1,
+ createPipParams(startAspectRatio)), null /* leash */);
+ mSpiedPipTaskOrganizer.sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
+
mSpiedPipTaskOrganizer.onTaskInfoChanged(createTaskInfo(mComponent1,
createPipParams(newAspectRatio)));
@@ -175,9 +195,10 @@
}
@Test
- public void onTaskInfoChanged_updatesLastPipComponentName() {
+ public void onTaskInfoChanged_inPip_updatesLastPipComponentName() {
mSpiedPipTaskOrganizer.onTaskAppeared(createTaskInfo(mComponent1,
createPipParams(null)), null /* leash */);
+ mSpiedPipTaskOrganizer.sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
mSpiedPipTaskOrganizer.onTaskInfoChanged(createTaskInfo(mComponent2,
createPipParams(null)));
@@ -186,9 +207,10 @@
}
@Test
- public void onTaskInfoChanged_updatesOverrideMinSize() {
+ public void onTaskInfoChanged_inPip_updatesOverrideMinSize() {
mSpiedPipTaskOrganizer.onTaskAppeared(createTaskInfo(mComponent1,
createPipParams(null)), null /* leash */);
+ mSpiedPipTaskOrganizer.sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
final Size minSize = new Size(400, 320);
mSpiedPipTaskOrganizer.onTaskInfoChanged(createTaskInfo(mComponent2,
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 77ceda9..d663c52 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -421,7 +421,6 @@
"libstatspull",
"libstatssocket",
"libpdfium",
- "libbinder_ndk",
],
static_libs: [
"libgif",
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index 912d04c5..e9b2f4a 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -80,6 +80,10 @@
explicit UiFrameInfoBuilder(int64_t* buffer) : mBuffer(buffer) {
memset(mBuffer, 0, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
set(FrameInfoIndex::FrameTimelineVsyncId) = INVALID_VSYNC_ID;
+ // The struct is zeroed by memset above. That also sets FrameInfoIndex::InputEventId to
+ // equal android::os::IInputConstants::INVALID_INPUT_EVENT_ID == 0.
+ // Therefore, we can skip setting the value for InputEventId here. If the value for
+ // INVALID_INPUT_EVENT_ID changes, this code would have to be updated, as well.
set(FrameInfoIndex::FrameDeadline) = std::numeric_limits<int64_t>::max();
}
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 609706e..5540e2d 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -552,8 +552,8 @@
bool promotedToLayer() const {
return mLayerProperties.mType == LayerType::None && fitsOnLayer() &&
- (mComputedFields.mNeedLayerForFunctors ||
- mLayerProperties.mImageFilter != nullptr ||
+ (mComputedFields.mNeedLayerForFunctors || mLayerProperties.mImageFilter != nullptr ||
+ !mLayerProperties.getStretchEffect().isEmpty() ||
(!MathUtils::isZero(mPrimitiveFields.mAlpha) && mPrimitiveFields.mAlpha < 1 &&
mPrimitiveFields.mHasOverlappingRendering));
}
diff --git a/libs/hwui/effects/StretchEffect.cpp b/libs/hwui/effects/StretchEffect.cpp
index 51cbc75..d4fd105 100644
--- a/libs/hwui/effects/StretchEffect.cpp
+++ b/libs/hwui/effects/StretchEffect.cpp
@@ -15,13 +15,195 @@
*/
#include "StretchEffect.h"
+#include <SkImageFilter.h>
+#include <SkRefCnt.h>
+#include <SkRuntimeEffect.h>
+#include <SkString.h>
+#include <SkSurface.h>
+#include <include/effects/SkImageFilters.h>
+
+#include <memory>
namespace android::uirenderer {
-sk_sp<SkImageFilter> StretchEffect::getImageFilter() const {
- // TODO: Implement & Cache
- // Probably need to use mutable to achieve caching
- return nullptr;
+static const SkString stretchShader = SkString(R"(
+ uniform shader uContentTexture;
+
+ // multiplier to apply to scale effect
+ uniform float uMaxStretchIntensity;
+
+ // Maximum percentage to stretch beyond bounds of target
+ uniform float uStretchAffectedDist;
+
+ // Distance stretched as a function of the normalized overscroll times
+ // scale intensity
+ uniform float uDistanceStretchedX;
+ uniform float uDistanceStretchedY;
+ uniform float uDistDiffX;
+
+ // Difference between the peak stretch amount and overscroll amount normalized
+ uniform float uDistDiffY;
+
+ // Horizontal offset represented as a ratio of pixels divided by the target width
+ uniform float uScrollX;
+ // Vertical offset represented as a ratio of pixels divided by the target height
+ uniform float uScrollY;
+
+ // Normalized overscroll amount in the horizontal direction
+ uniform float uOverscrollX;
+
+ // Normalized overscroll amount in the vertical direction
+ uniform float uOverscrollY;
+ uniform float viewportWidth; // target height in pixels
+ uniform float viewportHeight; // target width in pixels
+
+ void computeOverscrollStart(
+ out float outPos,
+ float inPos,
+ float overscroll,
+ float uStretchAffectedDist,
+ float distanceStretched
+ ) {
+ float offsetPos = uStretchAffectedDist - inPos;
+ float posBasedVariation = smoothstep(0., uStretchAffectedDist, offsetPos);
+ float stretchIntensity = overscroll * posBasedVariation;
+ outPos = distanceStretched - (offsetPos / (1. + stretchIntensity));
+ }
+
+ void computeOverscrollEnd(
+ out float outPos,
+ float inPos,
+ float overscroll,
+ float reverseStretchDist,
+ float uStretchAffectedDist,
+ float distanceStretched
+ ) {
+ float offsetPos = inPos - reverseStretchDist;
+ float posBasedVariation = (smoothstep(0., uStretchAffectedDist, offsetPos));
+ float stretchIntensity = (-overscroll) * posBasedVariation;
+ outPos = 1 - (distanceStretched - (offsetPos / (1. + stretchIntensity)));
+ }
+
+ void computeOverscroll(
+ out float outPos,
+ float inPos,
+ float overscroll,
+ float uStretchAffectedDist,
+ float distanceStretched,
+ float distanceDiff
+ ) {
+ if (overscroll > 0) {
+ if (inPos <= uStretchAffectedDist) {
+ computeOverscrollStart(
+ outPos,
+ inPos,
+ overscroll,
+ uStretchAffectedDist,
+ distanceStretched
+ );
+ } else if (inPos >= distanceStretched) {
+ outPos = distanceDiff + inPos;
+ }
+ }
+ if (overscroll < 0) {
+ float stretchAffectedDist = 1. - uStretchAffectedDist;
+ if (inPos >= stretchAffectedDist) {
+ computeOverscrollEnd(
+ outPos,
+ inPos,
+ overscroll,
+ stretchAffectedDist,
+ uStretchAffectedDist,
+ distanceStretched
+ );
+ } else if (inPos < stretchAffectedDist) {
+ outPos = -distanceDiff + inPos;
+ }
+ }
+ }
+
+ vec4 main(vec2 coord) {
+ // Normalize SKSL pixel coordinate into a unit vector
+ float inU = coord.x / viewportWidth;
+ float inV = coord.y / viewportHeight;
+ float outU;
+ float outV;
+ float stretchIntensity;
+ // Add the normalized scroll position within scrolling list
+ inU += uScrollX;
+ inV += uScrollY;
+ outU = inU;
+ outV = inV;
+ computeOverscroll(
+ outU,
+ inU,
+ uOverscrollX,
+ uStretchAffectedDist,
+ uDistanceStretchedX,
+ uDistDiffX
+ );
+ computeOverscroll(
+ outV,
+ inV,
+ uOverscrollY,
+ uStretchAffectedDist,
+ uDistanceStretchedY,
+ uDistDiffY
+ );
+ coord.x = outU * viewportWidth;
+ coord.y = outV * viewportHeight;
+ return sample(uContentTexture, coord);
+ })");
+
+static const float ZERO = 0.f;
+
+sk_sp<SkImageFilter> StretchEffect::getImageFilter(const sk_sp<SkImage>& snapshotImage) const {
+ if (isEmpty()) {
+ return nullptr;
+ }
+
+ if (mStretchFilter != nullptr) {
+ return mStretchFilter;
+ }
+
+ float distanceNotStretchedX = maxStretchAmount / stretchArea.width();
+ float distanceNotStretchedY = maxStretchAmount / stretchArea.height();
+ float normOverScrollDistX = mStretchDirection.x();
+ float normOverScrollDistY = mStretchDirection.y();
+ float distanceStretchedX = maxStretchAmount / (1 + abs(normOverScrollDistX));
+ float distanceStretchedY = maxStretchAmount / (1 + abs(normOverScrollDistY));
+ float diffX = distanceStretchedX - distanceNotStretchedX;
+ float diffY = distanceStretchedY - distanceNotStretchedY;
+ float viewportWidth = stretchArea.width();
+ float viewportHeight = stretchArea.height();
+
+ if (mBuilder == nullptr) {
+ mBuilder = std::make_unique<SkRuntimeShaderBuilder>(getStretchEffect());
+ }
+
+ mBuilder->child("uContentTexture") = snapshotImage->makeShader(
+ SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions(SkFilterMode::kLinear));
+ mBuilder->uniform("uStretchAffectedDist").set(&maxStretchAmount, 1);
+ mBuilder->uniform("uDistanceStretchedX").set(&distanceStretchedX, 1);
+ mBuilder->uniform("uDistanceStretchedY").set(&distanceStretchedY, 1);
+ mBuilder->uniform("uDistDiffX").set(&diffX, 1);
+ mBuilder->uniform("uDistDiffY").set(&diffY, 1);
+ mBuilder->uniform("uOverscrollX").set(&normOverScrollDistX, 1);
+ mBuilder->uniform("uOverscrollY").set(&normOverScrollDistY, 1);
+ mBuilder->uniform("uScrollX").set(&ZERO, 1);
+ mBuilder->uniform("uScrollY").set(&ZERO, 1);
+ mBuilder->uniform("viewportWidth").set(&viewportWidth, 1);
+ mBuilder->uniform("viewportHeight").set(&viewportHeight, 1);
+
+ mStretchFilter = SkImageFilters::Shader(mBuilder->makeShader(nullptr, false),
+ SkRect{0, 0, viewportWidth, viewportHeight});
+
+ return mStretchFilter;
+}
+
+sk_sp<SkRuntimeEffect> StretchEffect::getStretchEffect() {
+ const static SkRuntimeEffect::Result instance = SkRuntimeEffect::Make(stretchShader);
+ return instance.effect;
}
} // namespace android::uirenderer
\ No newline at end of file
diff --git a/libs/hwui/effects/StretchEffect.h b/libs/hwui/effects/StretchEffect.h
index 7dfd639..d2da06b 100644
--- a/libs/hwui/effects/StretchEffect.h
+++ b/libs/hwui/effects/StretchEffect.h
@@ -18,9 +18,11 @@
#include "utils/MathUtils.h"
+#include <SkImage.h>
+#include <SkImageFilter.h>
#include <SkPoint.h>
#include <SkRect.h>
-#include <SkImageFilter.h>
+#include <SkRuntimeEffect.h>
namespace android::uirenderer {
@@ -31,15 +33,27 @@
SmoothStep,
};
+ StretchEffect(const SkRect& area, const SkVector& direction, float maxStretchAmount)
+ : stretchArea(area), maxStretchAmount(maxStretchAmount), mStretchDirection(direction) {}
+
+ StretchEffect() {}
+
bool isEmpty() const {
- return MathUtils::isZero(stretchDirection.x())
- && MathUtils::isZero(stretchDirection.y());
+ return MathUtils::isZero(mStretchDirection.x()) && MathUtils::isZero(mStretchDirection.y());
}
void setEmpty() {
*this = StretchEffect{};
}
+ StretchEffect& operator=(const StretchEffect& other) {
+ this->stretchArea = other.stretchArea;
+ this->mStretchDirection = other.mStretchDirection;
+ this->mStretchFilter = nullptr;
+ this->maxStretchAmount = other.maxStretchAmount;
+ return *this;
+ }
+
void mergeWith(const StretchEffect& other) {
if (other.isEmpty()) {
return;
@@ -48,7 +62,7 @@
*this = other;
return;
}
- stretchDirection += other.stretchDirection;
+ setStretchDirection(mStretchDirection + other.mStretchDirection);
if (isEmpty()) {
return setEmpty();
}
@@ -56,11 +70,23 @@
maxStretchAmount = std::max(maxStretchAmount, other.maxStretchAmount);
}
- sk_sp<SkImageFilter> getImageFilter() const;
+ sk_sp<SkImageFilter> getImageFilter(const sk_sp<SkImage>& snapshotImage) const;
SkRect stretchArea {0, 0, 0, 0};
- SkVector stretchDirection {0, 0};
float maxStretchAmount = 0;
+
+ void setStretchDirection(const SkVector& direction) {
+ mStretchFilter = nullptr;
+ mStretchDirection = direction;
+ }
+
+ const SkVector getStretchDirection() const { return mStretchDirection; }
+
+private:
+ static sk_sp<SkRuntimeEffect> getStretchEffect();
+ mutable SkVector mStretchDirection{0, 0};
+ mutable std::unique_ptr<SkRuntimeShaderBuilder> mBuilder;
+ mutable sk_sp<SkImageFilter> mStretchFilter;
};
} // namespace android::uirenderer
diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp
index 5f60437..fc7d0d1 100644
--- a/libs/hwui/jni/android_graphics_RenderNode.cpp
+++ b/libs/hwui/jni/android_graphics_RenderNode.cpp
@@ -180,14 +180,13 @@
}
static jboolean android_view_RenderNode_stretch(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
- jfloat left, jfloat top, jfloat right, jfloat bottom, jfloat vX, jfloat vY, jfloat max) {
+ jfloat left, jfloat top, jfloat right,
+ jfloat bottom, jfloat vX, jfloat vY, jfloat max) {
+ StretchEffect effect =
+ StretchEffect(SkRect::MakeLTRB(left, top, right, bottom), {.fX = vX, .fY = vY}, max);
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().mutateLayerProperties().mutableStretchEffect().mergeWith(
- StretchEffect{
- .stretchArea = SkRect::MakeLTRB(left, top, right, bottom),
- .stretchDirection = {.fX = vX, .fY = vY},
- .maxStretchAmount = max
- });
+ effect);
renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
return true;
}
@@ -659,10 +658,11 @@
return;
}
#ifdef __ANDROID__ // Layoutlib does not support CanvasContext
+ SkVector stretchDirection = effect->getStretchDirection();
env->CallVoidMethod(localref, gPositionListener_ApplyStretchMethod,
info.canvasContext.getFrameNumber(), area.left, area.top,
- area.right, area.bottom, effect->stretchDirection.fX,
- effect->stretchDirection.fY, effect->maxStretchAmount);
+ area.right, area.bottom, stretchDirection.fX, stretchDirection.fY,
+ effect->maxStretchAmount);
#endif
env->DeleteLocalRef(localref);
}
@@ -702,106 +702,110 @@
const char* const kClassPathName = "android/graphics/RenderNode";
static const JNINativeMethod gMethods[] = {
-// ----------------------------------------------------------------------------
-// Regular JNI
-// ----------------------------------------------------------------------------
- { "nCreate", "(Ljava/lang/String;)J", (void*) android_view_RenderNode_create },
- { "nGetNativeFinalizer", "()J", (void*) android_view_RenderNode_getNativeFinalizer },
- { "nOutput", "(J)V", (void*) android_view_RenderNode_output },
- { "nGetUsageSize", "(J)I", (void*) android_view_RenderNode_getUsageSize },
- { "nGetAllocatedSize", "(J)I", (void*) android_view_RenderNode_getAllocatedSize },
- { "nAddAnimator", "(JJ)V", (void*) android_view_RenderNode_addAnimator },
- { "nEndAllAnimators", "(J)V", (void*) android_view_RenderNode_endAllAnimators },
- { "nRequestPositionUpdates", "(JLandroid/graphics/RenderNode$PositionUpdateListener;)V", (void*) android_view_RenderNode_requestPositionUpdates },
+ // ----------------------------------------------------------------------------
+ // Regular JNI
+ // ----------------------------------------------------------------------------
+ {"nCreate", "(Ljava/lang/String;)J", (void*)android_view_RenderNode_create},
+ {"nGetNativeFinalizer", "()J", (void*)android_view_RenderNode_getNativeFinalizer},
+ {"nOutput", "(J)V", (void*)android_view_RenderNode_output},
+ {"nGetUsageSize", "(J)I", (void*)android_view_RenderNode_getUsageSize},
+ {"nGetAllocatedSize", "(J)I", (void*)android_view_RenderNode_getAllocatedSize},
+ {"nAddAnimator", "(JJ)V", (void*)android_view_RenderNode_addAnimator},
+ {"nEndAllAnimators", "(J)V", (void*)android_view_RenderNode_endAllAnimators},
+ {"nRequestPositionUpdates", "(JLandroid/graphics/RenderNode$PositionUpdateListener;)V",
+ (void*)android_view_RenderNode_requestPositionUpdates},
-// ----------------------------------------------------------------------------
-// Critical JNI via @CriticalNative annotation in RenderNode.java
-// ----------------------------------------------------------------------------
- { "nDiscardDisplayList", "(J)V", (void*) android_view_RenderNode_discardDisplayList },
- { "nIsValid", "(J)Z", (void*) android_view_RenderNode_isValid },
- { "nSetLayerType", "(JI)Z", (void*) android_view_RenderNode_setLayerType },
- { "nGetLayerType", "(J)I", (void*) android_view_RenderNode_getLayerType },
- { "nSetLayerPaint", "(JJ)Z", (void*) android_view_RenderNode_setLayerPaint },
- { "nSetStaticMatrix", "(JJ)Z", (void*) android_view_RenderNode_setStaticMatrix },
- { "nSetAnimationMatrix", "(JJ)Z", (void*) android_view_RenderNode_setAnimationMatrix },
- { "nGetAnimationMatrix", "(JJ)Z", (void*) android_view_RenderNode_getAnimationMatrix },
- { "nSetClipToBounds", "(JZ)Z", (void*) android_view_RenderNode_setClipToBounds },
- { "nGetClipToBounds", "(J)Z", (void*) android_view_RenderNode_getClipToBounds },
- { "nSetClipBounds", "(JIIII)Z", (void*) android_view_RenderNode_setClipBounds },
- { "nSetClipBoundsEmpty", "(J)Z", (void*) android_view_RenderNode_setClipBoundsEmpty },
- { "nSetProjectBackwards", "(JZ)Z", (void*) android_view_RenderNode_setProjectBackwards },
- { "nSetProjectionReceiver","(JZ)Z", (void*) android_view_RenderNode_setProjectionReceiver },
+ // ----------------------------------------------------------------------------
+ // Critical JNI via @CriticalNative annotation in RenderNode.java
+ // ----------------------------------------------------------------------------
+ {"nDiscardDisplayList", "(J)V", (void*)android_view_RenderNode_discardDisplayList},
+ {"nIsValid", "(J)Z", (void*)android_view_RenderNode_isValid},
+ {"nSetLayerType", "(JI)Z", (void*)android_view_RenderNode_setLayerType},
+ {"nGetLayerType", "(J)I", (void*)android_view_RenderNode_getLayerType},
+ {"nSetLayerPaint", "(JJ)Z", (void*)android_view_RenderNode_setLayerPaint},
+ {"nSetStaticMatrix", "(JJ)Z", (void*)android_view_RenderNode_setStaticMatrix},
+ {"nSetAnimationMatrix", "(JJ)Z", (void*)android_view_RenderNode_setAnimationMatrix},
+ {"nGetAnimationMatrix", "(JJ)Z", (void*)android_view_RenderNode_getAnimationMatrix},
+ {"nSetClipToBounds", "(JZ)Z", (void*)android_view_RenderNode_setClipToBounds},
+ {"nGetClipToBounds", "(J)Z", (void*)android_view_RenderNode_getClipToBounds},
+ {"nSetClipBounds", "(JIIII)Z", (void*)android_view_RenderNode_setClipBounds},
+ {"nSetClipBoundsEmpty", "(J)Z", (void*)android_view_RenderNode_setClipBoundsEmpty},
+ {"nSetProjectBackwards", "(JZ)Z", (void*)android_view_RenderNode_setProjectBackwards},
+ {"nSetProjectionReceiver", "(JZ)Z", (void*)android_view_RenderNode_setProjectionReceiver},
- { "nSetOutlineRoundRect", "(JIIIIFF)Z", (void*) android_view_RenderNode_setOutlineRoundRect },
- { "nSetOutlinePath", "(JJF)Z", (void*) android_view_RenderNode_setOutlinePath },
- { "nSetOutlineEmpty", "(J)Z", (void*) android_view_RenderNode_setOutlineEmpty },
- { "nSetOutlineNone", "(J)Z", (void*) android_view_RenderNode_setOutlineNone },
- { "nClearStretch", "(J)Z", (void*) android_view_RenderNode_clearStretch },
- { "nStretch", "(JFFFFFFF)Z", (void*) android_view_RenderNode_stretch },
- { "nHasShadow", "(J)Z", (void*) android_view_RenderNode_hasShadow },
- { "nSetSpotShadowColor", "(JI)Z", (void*) android_view_RenderNode_setSpotShadowColor },
- { "nGetSpotShadowColor", "(J)I", (void*) android_view_RenderNode_getSpotShadowColor },
- { "nSetAmbientShadowColor","(JI)Z", (void*) android_view_RenderNode_setAmbientShadowColor },
- { "nGetAmbientShadowColor","(J)I", (void*) android_view_RenderNode_getAmbientShadowColor },
- { "nSetClipToOutline", "(JZ)Z", (void*) android_view_RenderNode_setClipToOutline },
- { "nSetRevealClip", "(JZFFF)Z", (void*) android_view_RenderNode_setRevealClip },
+ {"nSetOutlineRoundRect", "(JIIIIFF)Z", (void*)android_view_RenderNode_setOutlineRoundRect},
+ {"nSetOutlinePath", "(JJF)Z", (void*)android_view_RenderNode_setOutlinePath},
+ {"nSetOutlineEmpty", "(J)Z", (void*)android_view_RenderNode_setOutlineEmpty},
+ {"nSetOutlineNone", "(J)Z", (void*)android_view_RenderNode_setOutlineNone},
+ {"nClearStretch", "(J)Z", (void*)android_view_RenderNode_clearStretch},
+ {"nStretch", "(JFFFFFFF)Z", (void*)android_view_RenderNode_stretch},
+ {"nHasShadow", "(J)Z", (void*)android_view_RenderNode_hasShadow},
+ {"nSetSpotShadowColor", "(JI)Z", (void*)android_view_RenderNode_setSpotShadowColor},
+ {"nGetSpotShadowColor", "(J)I", (void*)android_view_RenderNode_getSpotShadowColor},
+ {"nSetAmbientShadowColor", "(JI)Z", (void*)android_view_RenderNode_setAmbientShadowColor},
+ {"nGetAmbientShadowColor", "(J)I", (void*)android_view_RenderNode_getAmbientShadowColor},
+ {"nSetClipToOutline", "(JZ)Z", (void*)android_view_RenderNode_setClipToOutline},
+ {"nSetRevealClip", "(JZFFF)Z", (void*)android_view_RenderNode_setRevealClip},
- { "nSetAlpha", "(JF)Z", (void*) android_view_RenderNode_setAlpha },
- { "nSetRenderEffect", "(JJ)Z", (void*) android_view_RenderNode_setRenderEffect },
- { "nSetHasOverlappingRendering", "(JZ)Z",
- (void*) android_view_RenderNode_setHasOverlappingRendering },
- { "nSetUsageHint", "(JI)V", (void*) android_view_RenderNode_setUsageHint },
- { "nSetElevation", "(JF)Z", (void*) android_view_RenderNode_setElevation },
- { "nSetTranslationX", "(JF)Z", (void*) android_view_RenderNode_setTranslationX },
- { "nSetTranslationY", "(JF)Z", (void*) android_view_RenderNode_setTranslationY },
- { "nSetTranslationZ", "(JF)Z", (void*) android_view_RenderNode_setTranslationZ },
- { "nSetRotation", "(JF)Z", (void*) android_view_RenderNode_setRotation },
- { "nSetRotationX", "(JF)Z", (void*) android_view_RenderNode_setRotationX },
- { "nSetRotationY", "(JF)Z", (void*) android_view_RenderNode_setRotationY },
- { "nSetScaleX", "(JF)Z", (void*) android_view_RenderNode_setScaleX },
- { "nSetScaleY", "(JF)Z", (void*) android_view_RenderNode_setScaleY },
- { "nSetPivotX", "(JF)Z", (void*) android_view_RenderNode_setPivotX },
- { "nSetPivotY", "(JF)Z", (void*) android_view_RenderNode_setPivotY },
- { "nResetPivot", "(J)Z", (void*) android_view_RenderNode_resetPivot },
- { "nSetCameraDistance", "(JF)Z", (void*) android_view_RenderNode_setCameraDistance },
- { "nSetLeft", "(JI)Z", (void*) android_view_RenderNode_setLeft },
- { "nSetTop", "(JI)Z", (void*) android_view_RenderNode_setTop },
- { "nSetRight", "(JI)Z", (void*) android_view_RenderNode_setRight },
- { "nSetBottom", "(JI)Z", (void*) android_view_RenderNode_setBottom },
- { "nGetLeft", "(J)I", (void*) android_view_RenderNode_getLeft },
- { "nGetTop", "(J)I", (void*) android_view_RenderNode_getTop },
- { "nGetRight", "(J)I", (void*) android_view_RenderNode_getRight },
- { "nGetBottom", "(J)I", (void*) android_view_RenderNode_getBottom },
- { "nSetLeftTopRightBottom","(JIIII)Z", (void*) android_view_RenderNode_setLeftTopRightBottom },
- { "nOffsetLeftAndRight", "(JI)Z", (void*) android_view_RenderNode_offsetLeftAndRight },
- { "nOffsetTopAndBottom", "(JI)Z", (void*) android_view_RenderNode_offsetTopAndBottom },
+ {"nSetAlpha", "(JF)Z", (void*)android_view_RenderNode_setAlpha},
+ {"nSetRenderEffect", "(JJ)Z", (void*)android_view_RenderNode_setRenderEffect},
+ {"nSetHasOverlappingRendering", "(JZ)Z",
+ (void*)android_view_RenderNode_setHasOverlappingRendering},
+ {"nSetUsageHint", "(JI)V", (void*)android_view_RenderNode_setUsageHint},
+ {"nSetElevation", "(JF)Z", (void*)android_view_RenderNode_setElevation},
+ {"nSetTranslationX", "(JF)Z", (void*)android_view_RenderNode_setTranslationX},
+ {"nSetTranslationY", "(JF)Z", (void*)android_view_RenderNode_setTranslationY},
+ {"nSetTranslationZ", "(JF)Z", (void*)android_view_RenderNode_setTranslationZ},
+ {"nSetRotation", "(JF)Z", (void*)android_view_RenderNode_setRotation},
+ {"nSetRotationX", "(JF)Z", (void*)android_view_RenderNode_setRotationX},
+ {"nSetRotationY", "(JF)Z", (void*)android_view_RenderNode_setRotationY},
+ {"nSetScaleX", "(JF)Z", (void*)android_view_RenderNode_setScaleX},
+ {"nSetScaleY", "(JF)Z", (void*)android_view_RenderNode_setScaleY},
+ {"nSetPivotX", "(JF)Z", (void*)android_view_RenderNode_setPivotX},
+ {"nSetPivotY", "(JF)Z", (void*)android_view_RenderNode_setPivotY},
+ {"nResetPivot", "(J)Z", (void*)android_view_RenderNode_resetPivot},
+ {"nSetCameraDistance", "(JF)Z", (void*)android_view_RenderNode_setCameraDistance},
+ {"nSetLeft", "(JI)Z", (void*)android_view_RenderNode_setLeft},
+ {"nSetTop", "(JI)Z", (void*)android_view_RenderNode_setTop},
+ {"nSetRight", "(JI)Z", (void*)android_view_RenderNode_setRight},
+ {"nSetBottom", "(JI)Z", (void*)android_view_RenderNode_setBottom},
+ {"nGetLeft", "(J)I", (void*)android_view_RenderNode_getLeft},
+ {"nGetTop", "(J)I", (void*)android_view_RenderNode_getTop},
+ {"nGetRight", "(J)I", (void*)android_view_RenderNode_getRight},
+ {"nGetBottom", "(J)I", (void*)android_view_RenderNode_getBottom},
+ {"nSetLeftTopRightBottom", "(JIIII)Z",
+ (void*)android_view_RenderNode_setLeftTopRightBottom},
+ {"nOffsetLeftAndRight", "(JI)Z", (void*)android_view_RenderNode_offsetLeftAndRight},
+ {"nOffsetTopAndBottom", "(JI)Z", (void*)android_view_RenderNode_offsetTopAndBottom},
- { "nHasOverlappingRendering", "(J)Z", (void*) android_view_RenderNode_hasOverlappingRendering },
- { "nGetClipToOutline", "(J)Z", (void*) android_view_RenderNode_getClipToOutline },
- { "nGetAlpha", "(J)F", (void*) android_view_RenderNode_getAlpha },
- { "nGetCameraDistance", "(J)F", (void*) android_view_RenderNode_getCameraDistance },
- { "nGetScaleX", "(J)F", (void*) android_view_RenderNode_getScaleX },
- { "nGetScaleY", "(J)F", (void*) android_view_RenderNode_getScaleY },
- { "nGetElevation", "(J)F", (void*) android_view_RenderNode_getElevation },
- { "nGetTranslationX", "(J)F", (void*) android_view_RenderNode_getTranslationX },
- { "nGetTranslationY", "(J)F", (void*) android_view_RenderNode_getTranslationY },
- { "nGetTranslationZ", "(J)F", (void*) android_view_RenderNode_getTranslationZ },
- { "nGetRotation", "(J)F", (void*) android_view_RenderNode_getRotation },
- { "nGetRotationX", "(J)F", (void*) android_view_RenderNode_getRotationX },
- { "nGetRotationY", "(J)F", (void*) android_view_RenderNode_getRotationY },
- { "nIsPivotExplicitlySet", "(J)Z", (void*) android_view_RenderNode_isPivotExplicitlySet },
- { "nHasIdentityMatrix", "(J)Z", (void*) android_view_RenderNode_hasIdentityMatrix },
+ {"nHasOverlappingRendering", "(J)Z",
+ (void*)android_view_RenderNode_hasOverlappingRendering},
+ {"nGetClipToOutline", "(J)Z", (void*)android_view_RenderNode_getClipToOutline},
+ {"nGetAlpha", "(J)F", (void*)android_view_RenderNode_getAlpha},
+ {"nGetCameraDistance", "(J)F", (void*)android_view_RenderNode_getCameraDistance},
+ {"nGetScaleX", "(J)F", (void*)android_view_RenderNode_getScaleX},
+ {"nGetScaleY", "(J)F", (void*)android_view_RenderNode_getScaleY},
+ {"nGetElevation", "(J)F", (void*)android_view_RenderNode_getElevation},
+ {"nGetTranslationX", "(J)F", (void*)android_view_RenderNode_getTranslationX},
+ {"nGetTranslationY", "(J)F", (void*)android_view_RenderNode_getTranslationY},
+ {"nGetTranslationZ", "(J)F", (void*)android_view_RenderNode_getTranslationZ},
+ {"nGetRotation", "(J)F", (void*)android_view_RenderNode_getRotation},
+ {"nGetRotationX", "(J)F", (void*)android_view_RenderNode_getRotationX},
+ {"nGetRotationY", "(J)F", (void*)android_view_RenderNode_getRotationY},
+ {"nIsPivotExplicitlySet", "(J)Z", (void*)android_view_RenderNode_isPivotExplicitlySet},
+ {"nHasIdentityMatrix", "(J)Z", (void*)android_view_RenderNode_hasIdentityMatrix},
- { "nGetTransformMatrix", "(JJ)V", (void*) android_view_RenderNode_getTransformMatrix },
- { "nGetInverseTransformMatrix","(JJ)V", (void*) android_view_RenderNode_getInverseTransformMatrix },
+ {"nGetTransformMatrix", "(JJ)V", (void*)android_view_RenderNode_getTransformMatrix},
+ {"nGetInverseTransformMatrix", "(JJ)V",
+ (void*)android_view_RenderNode_getInverseTransformMatrix},
- { "nGetPivotX", "(J)F", (void*) android_view_RenderNode_getPivotX },
- { "nGetPivotY", "(J)F", (void*) android_view_RenderNode_getPivotY },
- { "nGetWidth", "(J)I", (void*) android_view_RenderNode_getWidth },
- { "nGetHeight", "(J)I", (void*) android_view_RenderNode_getHeight },
- { "nSetAllowForceDark", "(JZ)Z", (void*) android_view_RenderNode_setAllowForceDark },
- { "nGetAllowForceDark", "(J)Z", (void*) android_view_RenderNode_getAllowForceDark },
- { "nGetUniqueId", "(J)J", (void*) android_view_RenderNode_getUniqueId },
+ {"nGetPivotX", "(J)F", (void*)android_view_RenderNode_getPivotX},
+ {"nGetPivotY", "(J)F", (void*)android_view_RenderNode_getPivotY},
+ {"nGetWidth", "(J)I", (void*)android_view_RenderNode_getWidth},
+ {"nGetHeight", "(J)I", (void*)android_view_RenderNode_getHeight},
+ {"nSetAllowForceDark", "(JZ)Z", (void*)android_view_RenderNode_setAllowForceDark},
+ {"nGetAllowForceDark", "(J)Z", (void*)android_view_RenderNode_getAllowForceDark},
+ {"nGetUniqueId", "(J)J", (void*)android_view_RenderNode_getUniqueId},
};
int register_android_view_RenderNode(JNIEnv* env) {
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index c010212..cb0ff8d 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -169,8 +169,8 @@
displayList->mProjectedOutline = nullptr;
}
-static bool layerNeedsPaint(const LayerProperties& properties, float alphaMultiplier,
- SkPaint* paint) {
+static bool layerNeedsPaint(const sk_sp<SkImage>& snapshotImage, const LayerProperties& properties,
+ float alphaMultiplier, SkPaint* paint) {
if (alphaMultiplier < 1.0f || properties.alpha() < 255 ||
properties.xferMode() != SkBlendMode::kSrcOver || properties.getColorFilter() != nullptr ||
properties.getImageFilter() != nullptr || !properties.getStretchEffect().isEmpty()) {
@@ -179,7 +179,8 @@
paint->setColorFilter(sk_ref_sp(properties.getColorFilter()));
sk_sp<SkImageFilter> imageFilter = sk_ref_sp(properties.getImageFilter());
- sk_sp<SkImageFilter> stretchFilter = properties.getStretchEffect().getImageFilter();
+ sk_sp<SkImageFilter> stretchFilter =
+ properties.getStretchEffect().getImageFilter(snapshotImage);
sk_sp<SkImageFilter> filter;
if (imageFilter && stretchFilter) {
filter = SkImageFilters::Compose(
@@ -240,7 +241,8 @@
if (renderNode->getLayerSurface() && mComposeLayer) {
SkASSERT(properties.effectiveLayerType() == LayerType::RenderLayer);
SkPaint paint;
- layerNeedsPaint(layerProperties, alphaMultiplier, &paint);
+ sk_sp<SkImage> snapshotImage = renderNode->getLayerSurface()->makeImageSnapshot();
+ layerNeedsPaint(snapshotImage, layerProperties, alphaMultiplier, &paint);
SkSamplingOptions sampling(SkFilterMode::kLinear);
// surfaces for layers are created on LAYER_SIZE boundaries (which are >= layer size) so
@@ -254,8 +256,8 @@
canvas->drawAnnotation(bounds, String8::format(
"SurfaceID|%" PRId64, renderNode->uniqueId()).c_str(), nullptr);
}
- canvas->drawImageRect(renderNode->getLayerSurface()->makeImageSnapshot(), bounds,
- bounds, sampling, &paint, SkCanvas::kStrict_SrcRectConstraint);
+ canvas->drawImageRect(snapshotImage, bounds, bounds, sampling, &paint,
+ SkCanvas::kStrict_SrcRectConstraint);
if (!renderNode->getSkiaLayer()->hasRenderedSinceRepaint) {
renderNode->getSkiaLayer()->hasRenderedSinceRepaint = true;
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index c9146b2..3408ffd 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -17,7 +17,7 @@
#include "DrawFrameTask.h"
#include <utils/Log.h>
-#include <utils/Trace.h>
+#include <utils/TraceUtils.h>
#include "../DeferredLayerUpdater.h"
#include "../DisplayList.h"
@@ -82,7 +82,8 @@
}
void DrawFrameTask::run() {
- ATRACE_NAME("DrawFrame");
+ const int64_t vsyncId = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameTimelineVsyncId)];
+ ATRACE_FORMAT("DrawFrames %" PRId64, vsyncId);
bool canUnblockUiThread;
bool canDrawThisFrame;
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index f5b204a..5656dff 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -16,6 +16,7 @@
package android.media;
+import android.annotation.CallbackExecutor;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.graphics.GraphicBuffer;
@@ -24,6 +25,7 @@
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.hardware.HardwareBuffer.Usage;
+import android.hardware.camera2.MultiResolutionImageReader;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -36,7 +38,9 @@
import java.nio.ByteOrder;
import java.nio.NioUtils;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -134,7 +138,8 @@
// If the format is private don't default to USAGE_CPU_READ_OFTEN since it may not
// work, and is inscrutable anyway
return new ImageReader(width, height, format, maxImages,
- format == ImageFormat.PRIVATE ? 0 : HardwareBuffer.USAGE_CPU_READ_OFTEN);
+ format == ImageFormat.PRIVATE ? 0 : HardwareBuffer.USAGE_CPU_READ_OFTEN,
+ /*parent*/ null);
}
/**
@@ -250,18 +255,37 @@
// throw new IllegalArgumentException("The given format=" + Integer.toHexString(format)
// + " & usage=" + Long.toHexString(usage) + " is not supported");
// }
- return new ImageReader(width, height, format, maxImages, usage);
+ return new ImageReader(width, height, format, maxImages, usage, /*parent*/ null);
}
+ /**
+ * @hide
+ */
+ public static @NonNull ImageReader newInstance(
+ @IntRange(from = 1) int width,
+ @IntRange(from = 1) int height,
+ @Format int format,
+ @IntRange(from = 1) int maxImages,
+ @NonNull MultiResolutionImageReader parent) {
+ // If the format is private don't default to USAGE_CPU_READ_OFTEN since it may not
+ // work, and is inscrutable anyway
+ return new ImageReader(width, height, format, maxImages,
+ format == ImageFormat.PRIVATE ? 0 : HardwareBuffer.USAGE_CPU_READ_OFTEN,
+ parent);
+ }
+
+
/**
* @hide
*/
- protected ImageReader(int width, int height, int format, int maxImages, long usage) {
+ protected ImageReader(int width, int height, int format, int maxImages, long usage,
+ MultiResolutionImageReader parent) {
mWidth = width;
mHeight = height;
mFormat = format;
mUsage = usage;
mMaxImages = maxImages;
+ mParent = parent;
if (width < 1 || height < 1) {
throw new IllegalArgumentException(
@@ -433,6 +457,9 @@
if (image != null) {
image.close();
}
+ if (mParent != null) {
+ mParent.flushOther(this);
+ }
}
}
@@ -584,12 +611,38 @@
}
if (mListenerHandler == null || mListenerHandler.getLooper() != looper) {
mListenerHandler = new ListenerHandler(looper);
+ mListenerExecutor = new HandlerExecutor(mListenerHandler);
}
- mListener = listener;
} else {
- mListener = null;
mListenerHandler = null;
+ mListenerExecutor = null;
}
+ mListener = listener;
+ }
+ }
+
+ /**
+ * Register a listener to be invoked when a new image becomes available
+ * from the ImageReader.
+ *
+ * @param listener
+ * The listener that will be run.
+ * @param executor
+ * The executor which will be used to invoke the listener.
+ * @throws IllegalArgumentException
+ * If no handler specified and the calling thread has no looper.
+ *
+ * @hide
+ */
+ public void setOnImageAvailableListenerWithExecutor(@NonNull OnImageAvailableListener listener,
+ @NonNull Executor executor) {
+ if (executor == null) {
+ throw new IllegalArgumentException("executor must not be null");
+ }
+
+ synchronized (mListenerLock) {
+ mListenerExecutor = executor;
+ mListener = listener;
}
}
@@ -763,12 +816,27 @@
return;
}
- final Handler handler;
+ final Executor executor;
+ final OnImageAvailableListener listener;
synchronized (ir.mListenerLock) {
- handler = ir.mListenerHandler;
+ executor = ir.mListenerExecutor;
+ listener = ir.mListener;
}
- if (handler != null) {
- handler.sendEmptyMessage(0);
+ final boolean isReaderValid;
+ synchronized (ir.mCloseLock) {
+ isReaderValid = ir.mIsReaderValid;
+ }
+
+ // It's dangerous to fire onImageAvailable() callback when the ImageReader
+ // is being closed, as application could acquire next image in the
+ // onImageAvailable() callback.
+ if (executor != null && listener != null && isReaderValid) {
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ listener.onImageAvailable(ir);
+ }
+ });
}
}
@@ -785,11 +853,16 @@
private final Object mCloseLock = new Object();
private boolean mIsReaderValid = false;
private OnImageAvailableListener mListener;
+ private Executor mListenerExecutor;
private ListenerHandler mListenerHandler;
// Keep track of the successfully acquired Images. This need to be thread safe as the images
// could be closed by different threads (e.g., application thread and GC thread).
private List<Image> mAcquiredImages = new CopyOnWriteArrayList<>();
+ // Applicable if this isn't a standalone ImageReader, but belongs to a
+ // MultiResolutionImageReader.
+ private final MultiResolutionImageReader mParent;
+
/**
* This field is used by native code, do not access or modify.
*/
@@ -802,23 +875,22 @@
public ListenerHandler(Looper looper) {
super(looper, null, true /*async*/);
}
+ }
+
+ /**
+ * An adapter {@link Executor} that posts all executed tasks onto the
+ * given {@link Handler}.
+ **/
+ private final class HandlerExecutor implements Executor {
+ private final Handler mHandler;
+
+ public HandlerExecutor(@NonNull Handler handler) {
+ mHandler = Objects.requireNonNull(handler);
+ }
@Override
- public void handleMessage(Message msg) {
- OnImageAvailableListener listener;
- synchronized (mListenerLock) {
- listener = mListener;
- }
-
- // It's dangerous to fire onImageAvailable() callback when the ImageReader is being
- // closed, as application could acquire next image in the onImageAvailable() callback.
- boolean isReaderValid = false;
- synchronized (mCloseLock) {
- isReaderValid = mIsReaderValid;
- }
- if (listener != null && isReaderValid) {
- listener.onImageAvailable(ImageReader.this);
- }
+ public void execute(Runnable command) {
+ mHandler.post(command);
}
}
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index f7467a6..548b415 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -558,12 +558,20 @@
public static final int ERROR_PROVISIONING_PARSE = 26;
/**
+ * The provisioning server detected an error in the provisioning
+ * request.
+ * <p>
+ * Check for errors on the provisioning server.
+ */
+ public static final int ERROR_PROVISIONING_REQUEST_REJECTED = 27;
+
+ /**
* Provisioning failed in a way that is likely to succeed on a
* subsequent attempt.
* <p>
* The app should retry the operation.
*/
- public static final int ERROR_PROVISIONING_RETRY = 27;
+ public static final int ERROR_PROVISIONING_RETRY = 28;
/**
* This indicates that apps using MediaDrm sessions are
@@ -572,7 +580,7 @@
* <p>
* The app should retry the operation later.
*/
- public static final int ERROR_RESOURCE_CONTENTION = 28;
+ public static final int ERROR_RESOURCE_CONTENTION = 29;
/**
* Failed to generate a secure stop request because a field in the
@@ -581,7 +589,7 @@
* The secure stop can't be released on the server, but the app may
* remove it explicitly using {@link MediaDrm#removeSecureStop}.
*/
- public static final int ERROR_SECURE_STOP_RELEASE = 29;
+ public static final int ERROR_SECURE_STOP_RELEASE = 30;
/**
* The plugin was unable to read data from the filesystem.
@@ -589,7 +597,7 @@
* Please see the general error handling strategy for unexpected errors
* described in {@link ErrorCodes}.
*/
- public static final int ERROR_STORAGE_READ = 30;
+ public static final int ERROR_STORAGE_READ = 31;
/**
* The plugin was unable to write data to the filesystem.
@@ -597,7 +605,7 @@
* Please see the general error handling strategy for unexpected errors
* described in {@link ErrorCodes}.
*/
- public static final int ERROR_STORAGE_WRITE = 31;
+ public static final int ERROR_STORAGE_WRITE = 32;
/**
* {@link MediaCodec#queueSecureInputBuffer} called with 0 subsamples.
@@ -605,7 +613,7 @@
* Check the {@link MediaCodec.CryptoInfo} object passed to {@link
* MediaCodec#queueSecureInputBuffer}.
*/
- public static final int ERROR_ZERO_SUBSAMPLES = 32;
+ public static final int ERROR_ZERO_SUBSAMPLES = 33;
}
@@ -637,6 +645,7 @@
ErrorCodes.ERROR_PROVISIONING_CERTIFICATE,
ErrorCodes.ERROR_PROVISIONING_CONFIG,
ErrorCodes.ERROR_PROVISIONING_PARSE,
+ ErrorCodes.ERROR_PROVISIONING_REQUEST_REJECTED,
ErrorCodes.ERROR_PROVISIONING_RETRY,
ErrorCodes.ERROR_SECURE_STOP_RELEASE,
ErrorCodes.ERROR_STORAGE_READ,
diff --git a/media/java/android/media/metrics/Event.java b/media/java/android/media/metrics/Event.java
index 5646dcd..96b61d2 100644
--- a/media/java/android/media/metrics/Event.java
+++ b/media/java/android/media/metrics/Event.java
@@ -17,22 +17,30 @@
package android.media.metrics;
import android.annotation.IntRange;
+import android.os.Bundle;
/**
* Abstract class for metrics events.
*/
public abstract class Event {
- private final long mTimeSinceCreatedMillis;
+ final long mTimeSinceCreatedMillis;
+ Bundle mExtras;
// hide default constructor
/* package */ Event() {
mTimeSinceCreatedMillis = MediaMetricsManager.INVALID_TIMESTAMP;
}
+ // TODO: remove
protected Event(long timeSinceCreatedMillis) {
mTimeSinceCreatedMillis = timeSinceCreatedMillis;
}
+ /* package */ Event(long timeSinceCreatedMillis, Bundle extras) {
+ mTimeSinceCreatedMillis = timeSinceCreatedMillis;
+ mExtras = extras;
+ }
+
/**
* Gets time since the corresponding instance is created in millisecond.
* @return the timestamp since the instance is created, or -1 if unknown.
@@ -41,4 +49,9 @@
public long getTimeSinceCreatedMillis() {
return mTimeSinceCreatedMillis;
}
+
+ /** @hide */
+ public Bundle getExtras() {
+ return mExtras;
+ }
}
diff --git a/media/java/android/media/metrics/IMediaMetricsManager.aidl b/media/java/android/media/metrics/IMediaMetricsManager.aidl
index 2cb2ab5..f2c0d44 100644
--- a/media/java/android/media/metrics/IMediaMetricsManager.aidl
+++ b/media/java/android/media/metrics/IMediaMetricsManager.aidl
@@ -28,7 +28,8 @@
*/
interface IMediaMetricsManager {
void reportPlaybackMetrics(in String sessionId, in PlaybackMetrics metrics, int userId);
- String getSessionId(int userId);
+ String getPlaybackSessionId(int userId);
+ String getRecordingSessionId(int userId);
void reportNetworkEvent(in String sessionId, in NetworkEvent event, int userId);
void reportPlaybackErrorEvent(in String sessionId, in PlaybackErrorEvent event, int userId);
void reportPlaybackStateEvent(in String sessionId, in PlaybackStateEvent event, int userId);
diff --git a/media/java/android/media/metrics/LogSessionId.java b/media/java/android/media/metrics/LogSessionId.java
new file mode 100644
index 0000000..7ddb259
--- /dev/null
+++ b/media/java/android/media/metrics/LogSessionId.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021 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 android.media.metrics;
+
+/**
+ * An instances of this class represents the ID of a log session.
+ * @hide
+ */
+public class LogSessionId {
+ private final String mSessionId;
+
+ /* package */ LogSessionId(String id) {
+ mSessionId = id;
+ }
+
+ /** @hide */
+ public String getStringId() {
+ return mSessionId;
+ }
+}
diff --git a/media/java/android/media/metrics/MediaMetricsManager.java b/media/java/android/media/metrics/MediaMetricsManager.java
index de780f6..9710e88 100644
--- a/media/java/android/media/metrics/MediaMetricsManager.java
+++ b/media/java/android/media/metrics/MediaMetricsManager.java
@@ -94,7 +94,7 @@
@NonNull
public PlaybackSession createPlaybackSession() {
try {
- String id = mService.getSessionId(mUserId);
+ String id = mService.getPlaybackSessionId(mUserId);
PlaybackSession session = new PlaybackSession(id, this);
return session;
} catch (RemoteException e) {
@@ -103,6 +103,21 @@
}
/**
+ * Creates a recording session.
+ * @hide
+ */
+ @NonNull
+ public RecordingSession createRecordingSession() {
+ try {
+ String id = mService.getRecordingSessionId(mUserId);
+ RecordingSession session = new RecordingSession(id, this);
+ return session;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Reports error event.
* @hide
*/
diff --git a/media/java/android/media/metrics/NetworkEvent.java b/media/java/android/media/metrics/NetworkEvent.java
index 029edeb..098885c 100644
--- a/media/java/android/media/metrics/NetworkEvent.java
+++ b/media/java/android/media/metrics/NetworkEvent.java
@@ -20,6 +20,7 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -33,6 +34,9 @@
public final class NetworkEvent extends Event implements Parcelable {
/** Network type is not specified. Default type. */
public static final int NETWORK_TYPE_NONE = 0;
+ // TODO: replace NONE with UNKNOWN
+ /** @hide */
+ public static final int NETWORK_TYPE_UNKNOWN = 0;
/** Other network type */
public static final int NETWORK_TYPE_OTHER = 1;
/** Wi-Fi network */
@@ -49,6 +53,9 @@
public static final int NETWORK_TYPE_5G_NSA = 7;
/** 5G SA network */
public static final int NETWORK_TYPE_5G_SA = 8;
+ /** Not network connected */
+ /** @hide */
+ public static final int NETWORK_TYPE_OFFLINE = 9;
private final int mNetworkType;
private final long mTimeSinceCreatedMillis;
@@ -56,6 +63,7 @@
/** @hide */
@IntDef(prefix = "NETWORK_TYPE_", value = {
NETWORK_TYPE_NONE,
+ NETWORK_TYPE_UNKNOWN,
NETWORK_TYPE_OTHER,
NETWORK_TYPE_WIFI,
NETWORK_TYPE_ETHERNET,
@@ -63,7 +71,8 @@
NETWORK_TYPE_3G,
NETWORK_TYPE_4G,
NETWORK_TYPE_5G_NSA,
- NETWORK_TYPE_5G_SA
+ NETWORK_TYPE_5G_SA,
+ NETWORK_TYPE_OFFLINE
})
@Retention(RetentionPolicy.SOURCE)
public @interface NetworkType {}
@@ -92,6 +101,8 @@
return "NETWORK_TYPE_5G_NSA";
case NETWORK_TYPE_5G_SA:
return "NETWORK_TYPE_5G_SA";
+ case NETWORK_TYPE_OFFLINE:
+ return "NETWORK_TYPE_OFFLINE";
default:
return Integer.toHexString(value);
}
@@ -102,9 +113,10 @@
*
* @hide
*/
- public NetworkEvent(@NetworkType int type, long timeSinceCreatedMillis) {
+ public NetworkEvent(@NetworkType int type, long timeSinceCreatedMillis, Bundle extras) {
this.mNetworkType = type;
this.mTimeSinceCreatedMillis = timeSinceCreatedMillis;
+ this.mExtras = extras.deepCopy();
}
/**
@@ -149,8 +161,12 @@
@Override
public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ byte flg = 0;
+ if (mExtras != null) flg |= 0x1;
+ dest.writeByte(flg);
dest.writeInt(mNetworkType);
dest.writeLong(mTimeSinceCreatedMillis);
+ if (mExtras != null) dest.writeBundle(mExtras);
}
@Override
@@ -160,11 +176,14 @@
/** @hide */
/* package-private */ NetworkEvent(@NonNull android.os.Parcel in) {
+ byte flg = in.readByte();
int type = in.readInt();
long timeSinceCreatedMillis = in.readLong();
+ Bundle extras = (flg & 0x2) == 0 ? null : in.readBundle();
this.mNetworkType = type;
this.mTimeSinceCreatedMillis = timeSinceCreatedMillis;
+ this.mExtras = extras;
}
/**
@@ -189,6 +208,7 @@
public static final class Builder {
private int mNetworkType = NETWORK_TYPE_NONE;
private long mTimeSinceCreatedMillis = -1;
+ private Bundle mExtras;
/**
* Creates a new Builder.
@@ -214,9 +234,19 @@
return this;
}
+ /**
+ * Set extras for compatibility.
+ * <p>Should be used by support library only.
+ * @hide
+ */
+ public @NonNull Builder setExtras(@NonNull Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
/** Builds the instance. */
public @NonNull NetworkEvent build() {
- NetworkEvent o = new NetworkEvent(mNetworkType, mTimeSinceCreatedMillis);
+ NetworkEvent o = new NetworkEvent(mNetworkType, mTimeSinceCreatedMillis, mExtras);
return o;
}
}
diff --git a/media/java/android/media/metrics/PlaybackErrorEvent.java b/media/java/android/media/metrics/PlaybackErrorEvent.java
index 5a0820d1..b23b4d2 100644
--- a/media/java/android/media/metrics/PlaybackErrorEvent.java
+++ b/media/java/android/media/metrics/PlaybackErrorEvent.java
@@ -21,6 +21,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -63,11 +64,13 @@
@Nullable String exceptionStack,
int errorCode,
int subErrorCode,
- long timeSinceCreatedMillis) {
+ long timeSinceCreatedMillis,
+ Bundle extras) {
this.mExceptionStack = exceptionStack;
this.mErrorCode = errorCode;
this.mSubErrorCode = subErrorCode;
this.mTimeSinceCreatedMillis = timeSinceCreatedMillis;
+ this.mExtras = extras.deepCopy();
}
/** @hide */
@@ -135,11 +138,13 @@
public void writeToParcel(@NonNull Parcel dest, int flags) {
byte flg = 0;
if (mExceptionStack != null) flg |= 0x1;
+ if (mExtras != null) flg |= 0x2;
dest.writeByte(flg);
if (mExceptionStack != null) dest.writeString(mExceptionStack);
dest.writeInt(mErrorCode);
dest.writeInt(mSubErrorCode);
dest.writeLong(mTimeSinceCreatedMillis);
+ if (mExtras != null) dest.writeBundle(mExtras);
}
@Override
@@ -154,11 +159,13 @@
int errorCode = in.readInt();
int subErrorCode = in.readInt();
long timeSinceCreatedMillis = in.readLong();
+ Bundle extras = (flg & 0x2) == 0 ? null : in.readBundle();
this.mExceptionStack = exceptionStack;
this.mErrorCode = errorCode;
this.mSubErrorCode = subErrorCode;
this.mTimeSinceCreatedMillis = timeSinceCreatedMillis;
+ this.mExtras = extras;
}
@@ -183,6 +190,7 @@
private int mErrorCode;
private int mSubErrorCode;
private long mTimeSinceCreatedMillis = -1;
+ private Bundle mExtras;
/**
* Creates a new Builder.
@@ -226,6 +234,16 @@
return this;
}
+ /**
+ * Set extras for compatibility.
+ * <p>Should be used by support library only.
+ * @hide
+ */
+ public @NonNull Builder setExtras(@NonNull Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
/** Builds the instance. */
public @NonNull PlaybackErrorEvent build() {
@@ -241,7 +259,8 @@
stack,
mErrorCode,
mSubErrorCode,
- mTimeSinceCreatedMillis);
+ mTimeSinceCreatedMillis,
+ mExtras);
return o;
}
}
diff --git a/media/java/android/media/metrics/PlaybackMetrics.java b/media/java/android/media/metrics/PlaybackMetrics.java
index 4aa61662..7e7f44a 100644
--- a/media/java/android/media/metrics/PlaybackMetrics.java
+++ b/media/java/android/media/metrics/PlaybackMetrics.java
@@ -20,6 +20,7 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -58,6 +59,10 @@
/** SS (HTTP Smooth Streaming) stream type. */
public static final int STREAM_TYPE_SS = 5;
+ /** Unknown playback type. */
+ // TODO: change the PLAYBACK_TYPE_ values
+ /** @hide */
+ public static final int PLAYBACK_TYPE_UNKNOWN = 0;
/** VOD (Video on Demand) playback type. */
public static final int PLAYBACK_TYPE_VOD = 0;
/** Live playback type. */
@@ -80,6 +85,10 @@
/** Clear key DRM type. */
public static final int DRM_TYPE_CLEARKEY = 6;
+ /** Unknown content type. */
+ // TODO: change the CONTENT_TYPE_ values
+ /** @hide */
+ public static final int CONTENT_TYPE_UNKNOWN = 0;
/** Main contents. */
public static final int CONTENT_TYPE_MAIN = 0;
/** Advertisement contents. */
@@ -112,6 +121,7 @@
/** @hide */
@IntDef(prefix = "PLAYBACK_TYPE_", value = {
+ PLAYBACK_TYPE_UNKNOWN,
PLAYBACK_TYPE_VOD,
PLAYBACK_TYPE_LIVE,
PLAYBACK_TYPE_OTHER
@@ -134,6 +144,7 @@
/** @hide */
@IntDef(prefix = "CONTENT_TYPE_", value = {
+ CONTENT_TYPE_UNKNOWN,
CONTENT_TYPE_MAIN,
CONTENT_TYPE_AD,
CONTENT_TYPE_OTHER
@@ -158,6 +169,8 @@
private final long mNetworkBytesRead;
private final long mLocalBytesRead;
private final long mNetworkTransferDurationMillis;
+ private final byte[] mDrmSessionId;
+ private final Bundle mExtras;
/**
* Creates a new PlaybackMetrics.
@@ -179,7 +192,9 @@
int audioUnderrunCount,
long networkBytesRead,
long localBytesRead,
- long networkTransferDurationMillis) {
+ long networkTransferDurationMillis,
+ byte[] drmSessionId,
+ Bundle extras) {
this.mMediaDurationMillis = mediaDurationMillis;
this.mStreamSource = streamSource;
this.mStreamType = streamType;
@@ -196,6 +211,8 @@
this.mNetworkBytesRead = networkBytesRead;
this.mLocalBytesRead = localBytesRead;
this.mNetworkTransferDurationMillis = networkTransferDurationMillis;
+ this.mDrmSessionId = drmSessionId;
+ this.mExtras = extras.deepCopy();
}
/**
@@ -321,6 +338,12 @@
return mNetworkTransferDurationMillis;
}
+ /** @hide */
+ @NonNull
+ public byte[] getDrmSessionId() {
+ return mDrmSessionId;
+ }
+
@Override
public String toString() {
return "PlaybackMetrics { "
@@ -339,6 +362,7 @@
+ "networkBytesRead = " + mNetworkBytesRead + ", "
+ "localBytesRead = " + mLocalBytesRead + ", "
+ "networkTransferDurationMillis = " + mNetworkTransferDurationMillis
+ + "drmSessionId = " + Arrays.toString(mDrmSessionId)
+ " }";
}
@@ -361,7 +385,8 @@
&& mAudioUnderrunCount == that.mAudioUnderrunCount
&& mNetworkBytesRead == that.mNetworkBytesRead
&& mLocalBytesRead == that.mLocalBytesRead
- && mNetworkTransferDurationMillis == that.mNetworkTransferDurationMillis;
+ && mNetworkTransferDurationMillis == that.mNetworkTransferDurationMillis
+ && Arrays.equals(mDrmSessionId, that.mDrmSessionId);
}
@Override
@@ -369,7 +394,7 @@
return Objects.hash(mMediaDurationMillis, mStreamSource, mStreamType, mPlaybackType,
mDrmType, mContentType, mPlayerName, mPlayerVersion, mExperimentIds,
mVideoFramesPlayed, mVideoFramesDropped, mAudioUnderrunCount, mNetworkBytesRead,
- mLocalBytesRead, mNetworkTransferDurationMillis);
+ mLocalBytesRead, mNetworkTransferDurationMillis, mDrmSessionId);
}
@Override
@@ -377,6 +402,7 @@
long flg = 0;
if (mPlayerName != null) flg |= 0x80;
if (mPlayerVersion != null) flg |= 0x100;
+ if (mExtras != null) flg |= 0x200;
dest.writeLong(flg);
dest.writeLong(mMediaDurationMillis);
dest.writeInt(mStreamSource);
@@ -386,6 +412,7 @@
dest.writeInt(mContentType);
if (mPlayerName != null) dest.writeString(mPlayerName);
if (mPlayerVersion != null) dest.writeString(mPlayerVersion);
+ if (mExtras != null) dest.writeBundle(mExtras);
dest.writeLongArray(mExperimentIds);
dest.writeInt(mVideoFramesPlayed);
dest.writeInt(mVideoFramesDropped);
@@ -393,6 +420,8 @@
dest.writeLong(mNetworkBytesRead);
dest.writeLong(mLocalBytesRead);
dest.writeLong(mNetworkTransferDurationMillis);
+ dest.writeInt(mDrmSessionId.length);
+ dest.writeByteArray(mDrmSessionId);
}
@Override
@@ -411,6 +440,7 @@
int contentType = in.readInt();
String playerName = (flg & 0x80) == 0 ? null : in.readString();
String playerVersion = (flg & 0x100) == 0 ? null : in.readString();
+ Bundle extras = (flg & 0x200) == 0 ? null : in.readBundle();
long[] experimentIds = in.createLongArray();
int videoFramesPlayed = in.readInt();
int videoFramesDropped = in.readInt();
@@ -418,6 +448,9 @@
long networkBytesRead = in.readLong();
long localBytesRead = in.readLong();
long networkTransferDurationMillis = in.readLong();
+ int drmSessionIdLen = in.readInt();
+ byte[] drmSessionId = new byte[drmSessionIdLen];
+ in.readByteArray(drmSessionId);
this.mMediaDurationMillis = mediaDurationMillis;
this.mStreamSource = streamSource;
@@ -435,6 +468,8 @@
this.mNetworkBytesRead = networkBytesRead;
this.mLocalBytesRead = localBytesRead;
this.mNetworkTransferDurationMillis = networkTransferDurationMillis;
+ this.mDrmSessionId = drmSessionId;
+ this.mExtras = extras;
}
public static final @NonNull Parcelable.Creator<PlaybackMetrics> CREATOR =
@@ -470,6 +505,8 @@
private long mNetworkBytesRead = -1;
private long mLocalBytesRead = -1;
private long mNetworkTransferDurationMillis = -1;
+ private byte[] mDrmSessionId = new byte[0];
+ private Bundle mExtras;
/**
* Creates a new Builder.
@@ -608,6 +645,24 @@
return this;
}
+ /**
+ * @hide
+ */
+ public @NonNull Builder setDrmSessionId(@NonNull byte[] drmSessionId) {
+ mDrmSessionId = drmSessionId;
+ return this;
+ }
+
+ /**
+ * Set extras for compatibility.
+ * <p>Should be used by support library only.
+ * @hide
+ */
+ public @NonNull Builder setExtras(@NonNull Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull PlaybackMetrics build() {
@@ -626,7 +681,9 @@
mAudioUnderrunCount,
mNetworkBytesRead,
mLocalBytesRead,
- mNetworkTransferDurationMillis);
+ mNetworkTransferDurationMillis,
+ mDrmSessionId,
+ mExtras);
return o;
}
diff --git a/media/java/android/media/metrics/PlaybackSession.java b/media/java/android/media/metrics/PlaybackSession.java
index 4ee8a45..272fd9b 100644
--- a/media/java/android/media/metrics/PlaybackSession.java
+++ b/media/java/android/media/metrics/PlaybackSession.java
@@ -29,6 +29,7 @@
public final class PlaybackSession implements AutoCloseable {
private final @NonNull String mId;
private final @NonNull MediaMetricsManager mManager;
+ private final @NonNull LogSessionId mLogSessionId;
private boolean mClosed = false;
/**
@@ -41,6 +42,7 @@
mManager = manager;
AnnotationValidations.validate(NonNull.class, null, mId);
AnnotationValidations.validate(NonNull.class, null, mManager);
+ mLogSessionId = new LogSessionId(mId);
}
/**
@@ -79,9 +81,16 @@
}
public @NonNull String getId() {
+ // TODO: remove this method and use getSessionId();
return mId;
}
+ /** @hide */
+ public @NonNull LogSessionId getSessionId() {
+ // TODO: remove getId() and use this method;
+ return mLogSessionId;
+ }
+
@Override
public boolean equals(@Nullable Object o) {
if (this == o) return true;
diff --git a/media/java/android/media/metrics/PlaybackStateEvent.java b/media/java/android/media/metrics/PlaybackStateEvent.java
index 8ca5b75..dea8c1d 100644
--- a/media/java/android/media/metrics/PlaybackStateEvent.java
+++ b/media/java/android/media/metrics/PlaybackStateEvent.java
@@ -20,6 +20,7 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -136,9 +137,11 @@
*/
public PlaybackStateEvent(
int state,
- long timeSinceCreatedMillis) {
+ long timeSinceCreatedMillis,
+ Bundle extras) {
this.mTimeSinceCreatedMillis = timeSinceCreatedMillis;
this.mState = state;
+ this.mExtras = extras.deepCopy();
}
/**
@@ -174,8 +177,12 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
+ byte flg = 0;
+ if (mExtras != null) flg |= 0x1;
+ dest.writeByte(flg);
dest.writeInt(mState);
dest.writeLong(mTimeSinceCreatedMillis);
+ if (mExtras != null) dest.writeBundle(mExtras);
}
@Override
@@ -185,11 +192,14 @@
/** @hide */
/* package-private */ PlaybackStateEvent(@NonNull Parcel in) {
+ byte flg = in.readByte();
int state = in.readInt();
long timeSinceCreatedMillis = in.readLong();
+ Bundle extras = (flg & 0x1) == 0 ? null : in.readBundle();
this.mState = state;
this.mTimeSinceCreatedMillis = timeSinceCreatedMillis;
+ this.mExtras = extras;
}
public static final @NonNull Parcelable.Creator<PlaybackStateEvent> CREATOR =
@@ -211,6 +221,7 @@
public static final class Builder {
private int mState = STATE_NOT_STARTED;
private long mTimeSinceCreatedMillis = -1;
+ private Bundle mExtras;
/**
* Creates a new Builder.
@@ -236,11 +247,22 @@
return this;
}
+ /**
+ * Set extras for compatibility.
+ * <p>Should be used by support library only.
+ * @hide
+ */
+ public @NonNull Builder setExtras(@NonNull Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
/** Builds the instance. */
public @NonNull PlaybackStateEvent build() {
PlaybackStateEvent o = new PlaybackStateEvent(
mState,
- mTimeSinceCreatedMillis);
+ mTimeSinceCreatedMillis,
+ mExtras);
return o;
}
}
diff --git a/media/java/android/media/metrics/RecordingSession.java b/media/java/android/media/metrics/RecordingSession.java
new file mode 100644
index 0000000..541d129
--- /dev/null
+++ b/media/java/android/media/metrics/RecordingSession.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 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 android.media.metrics;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.util.AnnotationValidations;
+
+import java.util.Objects;
+
+/**
+ * An instances of this class represents a session of media recording.
+ * @hide
+ */
+public final class RecordingSession implements AutoCloseable {
+ private final @NonNull String mId;
+ private final @NonNull MediaMetricsManager mManager;
+ private final @NonNull LogSessionId mLogSessionId;
+ private boolean mClosed = false;
+
+ /** @hide */
+ public RecordingSession(@NonNull String id, @NonNull MediaMetricsManager manager) {
+ mId = id;
+ mManager = manager;
+ AnnotationValidations.validate(NonNull.class, null, mId);
+ AnnotationValidations.validate(NonNull.class, null, mManager);
+ mLogSessionId = new LogSessionId(mId);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ RecordingSession that = (RecordingSession) o;
+ return Objects.equals(mId, that.mId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mId);
+ }
+
+ @Override
+ public void close() {
+ mClosed = true;
+ }
+}
diff --git a/media/java/android/media/metrics/TrackChangeEvent.java b/media/java/android/media/metrics/TrackChangeEvent.java
index ef25357..aa51978 100644
--- a/media/java/android/media/metrics/TrackChangeEvent.java
+++ b/media/java/android/media/metrics/TrackChangeEvent.java
@@ -16,10 +16,12 @@
package android.media.metrics;
+import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -65,9 +67,10 @@
private final @Nullable String mLanguage;
private final @Nullable String mLanguageRegion;
private final int mChannelCount;
- private final int mSampleRate;
+ private final int mAudioSampleRate;
private final int mWidth;
private final int mHeight;
+ private final float mVideoFrameRate;
@@ -99,6 +102,7 @@
@Retention(RetentionPolicy.SOURCE)
public @interface TrackType {}
+ // TODO: remove this constructor. Use the private one below.
public TrackChangeEvent(
int state,
int reason,
@@ -125,9 +129,45 @@
this.mLanguage = language;
this.mLanguageRegion = languageRegion;
this.mChannelCount = channelCount;
- this.mSampleRate = sampleRate;
+ this.mAudioSampleRate = sampleRate;
this.mWidth = width;
this.mHeight = height;
+ this.mVideoFrameRate = -1;
+ }
+
+ private TrackChangeEvent(
+ int state,
+ int reason,
+ @Nullable String containerMimeType,
+ @Nullable String sampleMimeType,
+ @Nullable String codecName,
+ int bitrate,
+ long timeSinceCreatedMillis,
+ int type,
+ @Nullable String language,
+ @Nullable String languageRegion,
+ int channelCount,
+ int sampleRate,
+ int width,
+ int height,
+ float videoFrameRate,
+ @Nullable Bundle extras) {
+ this.mState = state;
+ this.mReason = reason;
+ this.mContainerMimeType = containerMimeType;
+ this.mSampleMimeType = sampleMimeType;
+ this.mCodecName = codecName;
+ this.mBitrate = bitrate;
+ this.mTimeSinceCreatedMillis = timeSinceCreatedMillis;
+ this.mType = type;
+ this.mLanguage = language;
+ this.mLanguageRegion = languageRegion;
+ this.mChannelCount = channelCount;
+ this.mAudioSampleRate = sampleRate;
+ this.mWidth = width;
+ this.mHeight = height;
+ this.mVideoFrameRate = videoFrameRate;
+ this.mExtras = extras.deepCopy();
}
/**
@@ -223,7 +263,7 @@
*/
@IntRange(from = -1, to = Integer.MAX_VALUE)
public int getSampleRate() {
- return mSampleRate;
+ return mAudioSampleRate;
}
/**
@@ -244,6 +284,16 @@
return mHeight;
}
+ /**
+ * Gets video frame rate.
+ * @return the video frame rate, or -1 if unknown.
+ * @hide
+ */
+ @FloatRange(from = -1, to = Float.MAX_VALUE)
+ public float getVideoFrameRate() {
+ return mVideoFrameRate;
+ }
+
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
int flg = 0;
@@ -252,6 +302,7 @@
if (mCodecName != null) flg |= 0x10;
if (mLanguage != null) flg |= 0x100;
if (mLanguageRegion != null) flg |= 0x200;
+ if (mExtras != null) flg |= 0x400;
dest.writeInt(flg);
dest.writeInt(mState);
dest.writeInt(mReason);
@@ -264,9 +315,11 @@
if (mLanguage != null) dest.writeString(mLanguage);
if (mLanguageRegion != null) dest.writeString(mLanguageRegion);
dest.writeInt(mChannelCount);
- dest.writeInt(mSampleRate);
+ dest.writeInt(mAudioSampleRate);
dest.writeInt(mWidth);
dest.writeInt(mHeight);
+ dest.writeFloat(mVideoFrameRate);
+ if (mExtras != null) dest.writeBundle(mExtras);
}
@Override
@@ -291,6 +344,8 @@
int sampleRate = in.readInt();
int width = in.readInt();
int height = in.readInt();
+ float videoFrameRate = in.readFloat();
+ Bundle extras = (flg & 0x400) == 0 ? null : in.readBundle();
this.mState = state;
this.mReason = reason;
@@ -303,9 +358,11 @@
this.mLanguage = language;
this.mLanguageRegion = languageRegion;
this.mChannelCount = channelCount;
- this.mSampleRate = sampleRate;
+ this.mAudioSampleRate = sampleRate;
this.mWidth = width;
this.mHeight = height;
+ this.mVideoFrameRate = videoFrameRate;
+ this.mExtras = extras;
}
public static final @NonNull Parcelable.Creator<TrackChangeEvent> CREATOR =
@@ -335,9 +392,10 @@
+ "language = " + mLanguage + ", "
+ "languageRegion = " + mLanguageRegion + ", "
+ "channelCount = " + mChannelCount + ", "
- + "sampleRate = " + mSampleRate + ", "
+ + "sampleRate = " + mAudioSampleRate + ", "
+ "width = " + mWidth + ", "
- + "height = " + mHeight
+ + "height = " + mHeight + ", "
+ + "videoFrameRate = " + mVideoFrameRate
+ " }";
}
@@ -357,16 +415,17 @@
&& Objects.equals(mLanguage, that.mLanguage)
&& Objects.equals(mLanguageRegion, that.mLanguageRegion)
&& mChannelCount == that.mChannelCount
- && mSampleRate == that.mSampleRate
+ && mAudioSampleRate == that.mAudioSampleRate
&& mWidth == that.mWidth
- && mHeight == that.mHeight;
+ && mHeight == that.mHeight
+ && mVideoFrameRate == that.mVideoFrameRate;
}
@Override
public int hashCode() {
return Objects.hash(mState, mReason, mContainerMimeType, mSampleMimeType, mCodecName,
mBitrate, mTimeSinceCreatedMillis, mType, mLanguage, mLanguageRegion,
- mChannelCount, mSampleRate, mWidth, mHeight);
+ mChannelCount, mAudioSampleRate, mWidth, mHeight, mVideoFrameRate);
}
/**
@@ -385,9 +444,11 @@
private @Nullable String mLanguage;
private @Nullable String mLanguageRegion;
private int mChannelCount = -1;
- private int mSampleRate = -1;
+ private int mAudioSampleRate = -1;
private int mWidth = -1;
private int mHeight = -1;
+ private float mVideoFrameRate = -1;
+ private Bundle mExtras;
private long mBuilderFieldsSet = 0L;
@@ -512,9 +573,10 @@
*/
public @NonNull Builder setSampleRate(
@IntRange(from = -1, to = Integer.MAX_VALUE) int value) {
+ // TODO: rename it to setAudioSampleRate
checkNotUsed();
mBuilderFieldsSet |= 0x800;
- mSampleRate = value;
+ mAudioSampleRate = value;
return this;
}
@@ -540,6 +602,28 @@
return this;
}
+ /**
+ * Sets video frame rate.
+ * @param value the video frame rate. -1 indicates the value is unknown.
+ * @hide
+ */
+ public @NonNull Builder setVideoFrameRate(
+ @FloatRange(from = -1, to = Float.MAX_VALUE) float value) {
+ checkNotUsed();
+ mVideoFrameRate = value;
+ return this;
+ }
+
+ /**
+ * Set extras for compatibility.
+ * <p>Should be used by support library only.
+ * @hide
+ */
+ public @NonNull Builder setExtras(@NonNull Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull TrackChangeEvent build() {
checkNotUsed();
@@ -557,9 +641,11 @@
mLanguage,
mLanguageRegion,
mChannelCount,
- mSampleRate,
+ mAudioSampleRate,
mWidth,
- mHeight);
+ mHeight,
+ mVideoFrameRate,
+ mExtras);
return o;
}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 98a13cf..78db750 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -541,17 +541,6 @@
* Sends a media key event. The receiver will be selected automatically.
*
* @param keyEvent the key event to send
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public void dispatchMediaKeyEvent(@NonNull KeyEvent keyEvent) {
- dispatchMediaKeyEventInternal(keyEvent, /*asSystemService=*/false, /*needWakeLock=*/false);
- }
-
- /**
- * Sends a media key event. The receiver will be selected automatically.
- *
- * @param keyEvent the key event to send
* @param needWakeLock true if a wake lock should be held while sending the key
* @hide
*/
diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp
index 307d80d..07866ac 100644
--- a/media/jni/android_media_MediaCodecList.cpp
+++ b/media/jni/android_media_MediaCodecList.cpp
@@ -105,6 +105,7 @@
// This should never happen unless something is really wrong
jniThrowException(
env, "java/lang/RuntimeException", "cannot get MediaCodecList");
+ return NULL;
}
sListWrapper.reset(new JavaMediaCodecListWrapper(mcl));
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 53f6fe2..4ccbfaf 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -376,6 +376,7 @@
STATUS_CASE(ERROR_DRM_PROVISIONING_CERTIFICATE);
STATUS_CASE(ERROR_DRM_PROVISIONING_CONFIG);
STATUS_CASE(ERROR_DRM_PROVISIONING_PARSE);
+ STATUS_CASE(ERROR_DRM_PROVISIONING_REQUEST_REJECTED);
STATUS_CASE(ERROR_DRM_PROVISIONING_RETRY);
STATUS_CASE(ERROR_DRM_RESOURCE_CONTENTION);
STATUS_CASE(ERROR_DRM_SECURE_STOP_RELEASE);
diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h
index dc0793a..a64e3f2 100644
--- a/media/jni/android_media_MediaDrm.h
+++ b/media/jni/android_media_MediaDrm.h
@@ -58,12 +58,13 @@
JERROR_DRM_PROVISIONING_CERTIFICATE = 24,
JERROR_DRM_PROVISIONING_CONFIG = 25,
JERROR_DRM_PROVISIONING_PARSE = 26,
- JERROR_DRM_PROVISIONING_RETRY = 27,
- JERROR_DRM_RESOURCE_CONTENTION = 28,
- JERROR_DRM_SECURE_STOP_RELEASE = 29,
- JERROR_DRM_STORAGE_READ = 30,
- JERROR_DRM_STORAGE_WRITE = 31,
- JERROR_DRM_ZERO_SUBSAMPLES = 32,
+ JERROR_DRM_PROVISIONING_REQUEST_REJECTED = 27,
+ JERROR_DRM_PROVISIONING_RETRY = 28,
+ JERROR_DRM_RESOURCE_CONTENTION = 29,
+ JERROR_DRM_SECURE_STOP_RELEASE = 30,
+ JERROR_DRM_STORAGE_READ = 31,
+ JERROR_DRM_STORAGE_WRITE = 32,
+ JERROR_DRM_ZERO_SUBSAMPLES = 33,
};
struct ListenerArgs {
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
index a9fd6f2..d2ed73e 100644
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -6,6 +6,7 @@
}
public class ConnectivityManager {
+ method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public java.util.List<android.net.NetworkStateSnapshot> getAllNetworkStateSnapshot();
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @Nullable android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
index 373fa3c..f5972fa 100644
--- a/packages/Connectivity/framework/api/system-current.txt
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -2,7 +2,7 @@
package android.net {
public class CaptivePortal implements android.os.Parcelable {
- method public void logEvent(int, @NonNull String);
+ method @Deprecated public void logEvent(int, @NonNull String);
method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void reevaluateNetwork();
method public void useNetwork();
field public static final int APP_REQUEST_REEVALUATION_REQUIRED = 100; // 0x64
diff --git a/packages/Connectivity/framework/src/android/net/CaptivePortal.java b/packages/Connectivity/framework/src/android/net/CaptivePortal.java
index 269bbf2..4a7b601 100644
--- a/packages/Connectivity/framework/src/android/net/CaptivePortal.java
+++ b/packages/Connectivity/framework/src/android/net/CaptivePortal.java
@@ -160,12 +160,11 @@
* @param eventId one of the CAPTIVE_PORTAL_LOGIN_* constants in metrics_constants.proto.
* @param packageName captive portal application package name.
* @hide
+ * @deprecated The event will not be logged in Android S and above. The
+ * caller is migrating to statsd.
*/
+ @Deprecated
@SystemApi
public void logEvent(int eventId, @NonNull String packageName) {
- try {
- ICaptivePortal.Stub.asInterface(mBinder).logEvent(eventId, packageName);
- } catch (RemoteException e) {
- }
}
}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index 39ec2edc..d7c6854 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -1259,6 +1259,25 @@
}
/**
+ * Return a list of {@link NetworkStateSnapshot}s, one for each network that is currently
+ * connected.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_STACK,
+ android.Manifest.permission.NETWORK_SETTINGS})
+ @NonNull
+ public List<NetworkStateSnapshot> getAllNetworkStateSnapshot() {
+ try {
+ return mService.getAllNetworkStateSnapshot();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns the {@link Network} object currently serving a given type, or
* null if the given type is not connected.
*
diff --git a/packages/Connectivity/framework/src/android/net/ICaptivePortal.aidl b/packages/Connectivity/framework/src/android/net/ICaptivePortal.aidl
index fe21905..e35f8d4 100644
--- a/packages/Connectivity/framework/src/android/net/ICaptivePortal.aidl
+++ b/packages/Connectivity/framework/src/android/net/ICaptivePortal.aidl
@@ -23,5 +23,4 @@
oneway interface ICaptivePortal {
void appRequest(int request);
void appResponse(int response);
- void logEvent(int eventId, String packageName);
}
diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
index 160338d..cd49258 100644
--- a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
+++ b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
@@ -31,6 +31,7 @@
import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.NetworkState;
+import android.net.NetworkStateSnapshot;
import android.net.OemNetworkPreferences;
import android.net.ProxyInfo;
import android.net.UidRange;
@@ -79,6 +80,8 @@
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
NetworkState[] getAllNetworkState();
+ List<NetworkStateSnapshot> getAllNetworkStateSnapshot();
+
boolean isActiveNetworkMetered();
boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress,
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index cd76f40..ab58f1b 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -34,9 +34,9 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.BitUtils;
import com.android.internal.util.Preconditions;
import com.android.net.module.util.CollectionUtils;
+import com.android.net.module.util.NetworkCapabilitiesUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -610,7 +610,7 @@
*/
@UnsupportedAppUsage
public @NetCapability int[] getCapabilities() {
- return BitUtils.unpackBits(mNetworkCapabilities);
+ return NetworkCapabilitiesUtils.unpackBits(mNetworkCapabilities);
}
/**
@@ -620,7 +620,7 @@
* @hide
*/
public @NetCapability int[] getUnwantedCapabilities() {
- return BitUtils.unpackBits(mUnwantedNetworkCapabilities);
+ return NetworkCapabilitiesUtils.unpackBits(mUnwantedNetworkCapabilities);
}
@@ -632,8 +632,8 @@
*/
public void setCapabilities(@NetCapability int[] capabilities,
@NetCapability int[] unwantedCapabilities) {
- mNetworkCapabilities = BitUtils.packBits(capabilities);
- mUnwantedNetworkCapabilities = BitUtils.packBits(unwantedCapabilities);
+ mNetworkCapabilities = NetworkCapabilitiesUtils.packBits(capabilities);
+ mUnwantedNetworkCapabilities = NetworkCapabilitiesUtils.packBits(unwantedCapabilities);
}
/**
@@ -688,7 +688,7 @@
& NON_REQUESTABLE_CAPABILITIES;
if (nonRequestable != 0) {
- return capabilityNameOf(BitUtils.unpackBits(nonRequestable)[0]);
+ return capabilityNameOf(NetworkCapabilitiesUtils.unpackBits(nonRequestable)[0]);
}
if (mLinkUpBandwidthKbps != 0 || mLinkDownBandwidthKbps != 0) return "link bandwidth";
if (hasSignalStrength()) return "signalStrength";
@@ -946,7 +946,7 @@
*/
@SystemApi
@NonNull public @Transport int[] getTransportTypes() {
- return BitUtils.unpackBits(mTransportTypes);
+ return NetworkCapabilitiesUtils.unpackBits(mTransportTypes);
}
/**
@@ -956,7 +956,7 @@
* @hide
*/
public void setTransportTypes(@Transport int[] transportTypes) {
- mTransportTypes = BitUtils.packBits(transportTypes);
+ mTransportTypes = NetworkCapabilitiesUtils.packBits(transportTypes);
}
/**
@@ -1721,8 +1721,10 @@
long oldImmutableCapabilities = this.mNetworkCapabilities & mask;
long newImmutableCapabilities = that.mNetworkCapabilities & mask;
if (oldImmutableCapabilities != newImmutableCapabilities) {
- String before = capabilityNamesOf(BitUtils.unpackBits(oldImmutableCapabilities));
- String after = capabilityNamesOf(BitUtils.unpackBits(newImmutableCapabilities));
+ String before = capabilityNamesOf(NetworkCapabilitiesUtils.unpackBits(
+ oldImmutableCapabilities));
+ String after = capabilityNamesOf(NetworkCapabilitiesUtils.unpackBits(
+ newImmutableCapabilities));
joiner.add(String.format("immutable capabilities changed: %s -> %s", before, after));
}
diff --git a/core/java/android/net/NetworkState.java b/packages/Connectivity/framework/src/android/net/NetworkState.java
similarity index 97%
rename from core/java/android/net/NetworkState.java
rename to packages/Connectivity/framework/src/android/net/NetworkState.java
index 813fde1..d010265 100644
--- a/core/java/android/net/NetworkState.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkState.java
@@ -115,7 +115,8 @@
}
@UnsupportedAppUsage
- public static final @android.annotation.NonNull Creator<NetworkState> CREATOR = new Creator<NetworkState>() {
+ @NonNull
+ public static final Creator<NetworkState> CREATOR = new Creator<NetworkState>() {
@Override
public NetworkState createFromParcel(Parcel in) {
return new NetworkState(in);
diff --git a/packages/Connectivity/framework/src/android/net/util/DnsUtils.java b/packages/Connectivity/framework/src/android/net/util/DnsUtils.java
index 7908353..3fe245e 100644
--- a/packages/Connectivity/framework/src/android/net/util/DnsUtils.java
+++ b/packages/Connectivity/framework/src/android/net/util/DnsUtils.java
@@ -29,8 +29,6 @@
import android.system.Os;
import android.util.Log;
-import com.android.internal.util.BitUtils;
-
import libcore.io.IoUtils;
import java.io.FileDescriptor;
@@ -332,7 +330,7 @@
if (srcByte[i] == dstByte[i]) {
continue;
}
- int x = BitUtils.uint8(srcByte[i]) ^ BitUtils.uint8(dstByte[i]);
+ int x = (srcByte[i] & 0xff) ^ (dstByte[i] & 0xff);
return i * CHAR_BIT + (Integer.numberOfLeadingZeros(x) - 24); // Java ints are 32 bits
}
return dstByte.length * CHAR_BIT;
diff --git a/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java b/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java
index 43fffd7..739ddad 100644
--- a/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java
+++ b/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java
@@ -30,8 +30,8 @@
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
-import android.telephony.PhoneStateListener;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.util.Log;
@@ -92,8 +92,8 @@
}
@VisibleForTesting
- protected class ActiveDataSubscriptionIdChangedListener extends PhoneStateListener
- implements PhoneStateListener.ActiveDataSubscriptionIdChangedListener {
+ protected class ActiveDataSubscriptionIdListener extends TelephonyCallback
+ implements TelephonyCallback.ActiveDataSubscriptionIdListener {
@Override
public void onActiveDataSubscriptionIdChanged(int subId) {
mActiveSubId = subId;
@@ -121,8 +121,8 @@
}
};
- ctx.getSystemService(TelephonyManager.class).registerPhoneStateListener(
- new HandlerExecutor(handler), new ActiveDataSubscriptionIdChangedListener());
+ ctx.getSystemService(TelephonyManager.class).registerTelephonyCallback(
+ new HandlerExecutor(handler), new ActiveDataSubscriptionIdListener());
updateAvoidBadWifi();
updateMeteredMultipathPreference();
diff --git a/packages/InputDevices/res/values-eu/strings.xml b/packages/InputDevices/res/values-eu/strings.xml
index 513eba2..64628a82 100644
--- a/packages/InputDevices/res/values-eu/strings.xml
+++ b/packages/InputDevices/res/values-eu/strings.xml
@@ -41,13 +41,13 @@
<string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabiarra"</string>
<string name="keyboard_layout_greek" msgid="7289253560162386040">"Greziarra"</string>
<string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrearra"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituaniera"</string>
+ <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituaniarra"</string>
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espainiarra (Latinoamerika)"</string>
- <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letoniera"</string>
+ <string name="keyboard_layout_latvian" msgid="4405417142306250595">"Letoniarra"</string>
<string name="keyboard_layout_persian" msgid="3920643161015888527">"Persiarra"</string>
<string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerbaijandarra"</string>
<string name="keyboard_layout_polish" msgid="1121588624094925325">"Poloniarra"</string>
- <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Bielorrusiera"</string>
+ <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Bielorrusiarra"</string>
<string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongoliarra"</string>
- <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgiera"</string>
+ <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgiarra"</string>
</resources>
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
index 139c8e5..63edc77 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
@@ -165,6 +165,9 @@
if (mParameters.isDeviceTransfer()) {
flags |= BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER;
}
+ if (mParameters.isEncrypted()) {
+ flags |= BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
+ }
return flags;
}
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
index 2946db3..1ba1bc6 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
@@ -28,10 +28,12 @@
private static final String KEY_FAKE_ENCRYPTION_FLAG = "fake_encryption_flag";
private static final String KEY_NON_INCREMENTAL_ONLY = "non_incremental_only";
private static final String KEY_IS_DEVICE_TRANSFER = "is_device_transfer";
+ private static final String KEY_IS_ENCRYPTED = "is_encrypted";
private boolean mFakeEncryptionFlag;
private boolean mIsNonIncrementalOnly;
private boolean mIsDeviceTransfer;
+ private boolean mIsEncrypted;
public LocalTransportParameters(Handler handler, ContentResolver resolver) {
super(handler, resolver, Settings.Secure.getUriFor(SETTING));
@@ -49,6 +51,10 @@
return mIsDeviceTransfer;
}
+ boolean isEncrypted() {
+ return mIsEncrypted;
+ }
+
public String getSettingValue(ContentResolver resolver) {
return Settings.Secure.getString(resolver, SETTING);
}
@@ -57,5 +63,6 @@
mFakeEncryptionFlag = parser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, false);
mIsNonIncrementalOnly = parser.getBoolean(KEY_NON_INCREMENTAL_ONLY, false);
mIsDeviceTransfer = parser.getBoolean(KEY_IS_DEVICE_TRANSFER, false);
+ mIsEncrypted = parser.getBoolean(KEY_IS_ENCRYPTED, false);
}
}
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout/toolbar_base_layout.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout/toolbar_base_layout.xml
new file mode 100644
index 0000000..c799b99
--- /dev/null
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout/toolbar_base_layout.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 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.
+-->
+<!-- The main content view -->
+<LinearLayout
+ android:id="@+id/content_parent"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fitsSystemWindows="true"
+ android:transitionGroup="true"
+ android:orientation="vertical">
+ <Toolbar
+ android:id="@+id/action_bar"
+ style="?android:attr/actionBarStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:theme="?android:attr/actionBarTheme" />
+ <FrameLayout
+ android:id="@+id/content_frame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+</LinearLayout>
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
index 637805f..ad94cd03 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
@@ -24,6 +24,7 @@
import android.widget.Toolbar;
import androidx.annotation.Nullable;
+import androidx.core.os.BuildCompat;
import androidx.fragment.app.FragmentActivity;
import com.google.android.material.appbar.CollapsingToolbarLayout;
@@ -40,8 +41,15 @@
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- super.setContentView(R.layout.collapsing_toolbar_base_layout);
- mCollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
+ // TODO(b/181723278): Update the version check after SDK for S is finalized
+ // The collapsing toolbar is only supported if the android platform version is S or higher.
+ // Otherwise the regular action bar will be shown.
+ if (BuildCompat.isAtLeastS()) {
+ super.setContentView(R.layout.collapsing_toolbar_base_layout);
+ mCollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
+ } else {
+ super.setContentView(R.layout.toolbar_base_layout);
+ }
final Toolbar toolbar = findViewById(R.id.action_bar);
setActionBar(toolbar);
@@ -90,6 +98,14 @@
super.setTitle(titleId);
}
+ @Override
+ public boolean onNavigateUp() {
+ if (!super.onNavigateUp()) {
+ finish();
+ }
+ return true;
+ }
+
/**
* Returns an instance of collapsing toolbar.
*/
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 757dc0c..efa9f3c 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -64,8 +64,12 @@
<string name="wifi_security_eap" translatable="false">WPA/WPA2/WPA3-Enterprise</string>
<!-- Do not translate. Concise terminology for wifi with WPA 802.1x EAP security -->
<string name="wifi_security_eap_wpa" translatable="false">WPA-Enterprise</string>
+ <!-- Do not translate. Concise terminology for wifi with 802.1x EAP security -->
+ <string name="wifi_security_eap_wpa_wpa2" translatable="false">WPA/WPA2-Enterprise</string>
<!-- Do not translate. Concise terminology for wifi with WPA2/WPA3 802.1x EAP security -->
<string name="wifi_security_eap_wpa2_wpa3" translatable="false">WPA2/WPA3-Enterprise</string>
+ <!-- Do not translate. Concise terminology for wifi with WPA3 802.1x EAP security -->
+ <string name="wifi_security_eap_wpa3" translatable="false">WPA3-Enterprise</string>
<!-- Do not translate. Concise terminology for Passpoint network -->
<string name="wifi_security_passpoint" translatable="false">Passpoint</string>
<!-- Do not translate. Terminology for wifi with WPA3 security -->
@@ -1302,6 +1306,8 @@
<!-- Name of the phone device. [CHAR LIMIT=30] -->
<string name="media_transfer_this_device_name">Phone speaker</string>
+ <!-- Name of the phone device with an active remote session. [CHAR LIMIT=30] -->
+ <string name="media_transfer_this_phone">This phone</string>
<!-- Warning message to tell user is have problem during profile connect, it need to turn off device and back on. [CHAR_LIMIT=NONE] -->
<string name="profile_connect_timeout_subtext">Problem connecting. Turn device off & back on</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java b/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
index 43717ab..dfde3c7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
@@ -27,7 +27,7 @@
import android.os.Handler;
import android.os.HandlerExecutor;
import android.provider.Settings;
-import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.util.Log;
@@ -72,7 +72,10 @@
checkIfAllSubsystemsRestartsAreDone();
}
};
- private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+ private final MobileTelephonyCallback mTelephonyCallback = new MobileTelephonyCallback();
+
+ private class MobileTelephonyCallback extends TelephonyCallback implements
+ TelephonyCallback.RadioPowerStateListener {
@Override
public void onRadioPowerStateChanged(int state) {
if (!mTelephonyRestartInProgress || mCurrentRecoveryCallback == null) {
@@ -85,7 +88,7 @@
checkIfAllSubsystemsRestartsAreDone();
}
}
- };
+ }
public ConnectivitySubsystemsRecoveryManager(@NonNull Context context,
@NonNull Handler handler) {
@@ -201,12 +204,12 @@
}
private void startTrackingTelephonyRestart() {
- mTelephonyManager.registerPhoneStateListener(new HandlerExecutor(mHandler),
- mPhoneStateListener);
+ mTelephonyManager.registerTelephonyCallback(new HandlerExecutor(mHandler),
+ mTelephonyCallback);
}
private void stopTrackingTelephonyRestart() {
- mTelephonyManager.unregisterPhoneStateListener(mPhoneStateListener);
+ mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback);
}
private void checkIfAllSubsystemsRestartsAreDone() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
index 0cd5e4d..1a08366 100644
--- a/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
@@ -17,11 +17,11 @@
import android.os.Handler;
import android.os.Looper;
-import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
import android.telephony.TelephonyDisplayInfo;
import android.telephony.TelephonyManager;
import android.util.Log;
@@ -40,9 +40,9 @@
private final SubscriptionInfo mSubscriptionInfo;
private final Callback mCallback;
private final MobileStatus mMobileStatus;
- private final PhoneStateListener mPhoneStateListener;
private final SubscriptionDefaults mDefaults;
private final Handler mReceiverHandler;
+ private final MobileTelephonyCallback mTelephonyCallback;
/**
* MobileStatusTracker constructors
@@ -58,7 +58,7 @@
SubscriptionInfo info, SubscriptionDefaults defaults, Callback callback) {
mPhone = phone;
mReceiverHandler = new Handler(receiverLooper);
- mPhoneStateListener = new MobilePhoneStateListener();
+ mTelephonyCallback = new MobileTelephonyCallback();
mSubscriptionInfo = info;
mDefaults = defaults;
mCallback = callback;
@@ -68,8 +68,8 @@
/* updateTelephony= */false, new MobileStatus(mMobileStatus)));
}
- public PhoneStateListener getPhoneStateListener() {
- return mPhoneStateListener;
+ public MobileTelephonyCallback getTelephonyCallback() {
+ return mTelephonyCallback;
}
/**
@@ -77,9 +77,9 @@
*/
public void setListening(boolean listening) {
if (listening) {
- mPhone.registerPhoneStateListener(mReceiverHandler::post, mPhoneStateListener);
+ mPhone.registerTelephonyCallback(mReceiverHandler::post, mTelephonyCallback);
} else {
- mPhone.unregisterPhoneStateListener(mPhoneStateListener);
+ mPhone.unregisterTelephonyCallback(mTelephonyCallback);
}
}
@@ -106,15 +106,14 @@
|| activity == TelephonyManager.DATA_ACTIVITY_OUT;
}
- private class MobilePhoneStateListener extends PhoneStateListener implements
- PhoneStateListener.ServiceStateChangedListener,
- PhoneStateListener.SignalStrengthsChangedListener,
- PhoneStateListener.CallStateChangedListener,
- PhoneStateListener.DataConnectionStateChangedListener,
- PhoneStateListener.DataActivityListener,
- PhoneStateListener.CarrierNetworkChangeListener,
- PhoneStateListener.ActiveDataSubscriptionIdChangedListener,
- PhoneStateListener.DisplayInfoChangedListener{
+ public class MobileTelephonyCallback extends TelephonyCallback implements
+ TelephonyCallback.ServiceStateListener,
+ TelephonyCallback.SignalStrengthsListener,
+ TelephonyCallback.DataConnectionStateListener,
+ TelephonyCallback.DataActivityListener,
+ TelephonyCallback.CarrierNetworkListener,
+ TelephonyCallback.ActiveDataSubscriptionIdListener,
+ TelephonyCallback.DisplayInfoListener{
@Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index a81a05f..303ee3c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -223,7 +223,8 @@
public static final int SECURITY_OWE = 4;
public static final int SECURITY_SAE = 5;
public static final int SECURITY_EAP_SUITE_B = 6;
- public static final int SECURITY_MAX_VAL = 7; // Has to be the last
+ public static final int SECURITY_EAP_WPA3_ENTERPRISE = 7;
+ public static final int SECURITY_MAX_VAL = 8; // Has to be the last
private static final int PSK_UNKNOWN = 0;
private static final int PSK_WPA = 1;
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 1393116..0687191 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -418,6 +418,9 @@
<!-- Permission required for CTS test - PeopleManagerTest -->
<uses-permission android:name="android.permission.READ_PEOPLE_DATA" />
+ <!-- Permission required for CTS test - CtsGameManagerTestCases -->
+ <uses-permission android:name="android.permission.MANAGE_GAME_MODE" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/res/layout/quick_settings_footer.xml b/packages/SystemUI/res/layout/quick_settings_footer.xml
index 13572fa..db712e4 100644
--- a/packages/SystemUI/res/layout/quick_settings_footer.xml
+++ b/packages/SystemUI/res/layout/quick_settings_footer.xml
@@ -17,6 +17,7 @@
<com.android.systemui.util.NeverExactlyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:minHeight="48dp"
android:clickable="true"
android:paddingBottom="@dimen/qs_tile_padding_top"
android:paddingTop="@dimen/qs_tile_padding_top"
diff --git a/packages/SystemUI/res/layout/udfps_animation_view_bp.xml b/packages/SystemUI/res/layout/udfps_animation_view_bp.xml
new file mode 100644
index 0000000..0cfbf2e
--- /dev/null
+++ b/packages/SystemUI/res/layout/udfps_animation_view_bp.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<com.android.systemui.biometrics.UdfpsAnimationViewBp
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/udfps_animation_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+</com.android.systemui.biometrics.UdfpsAnimationViewBp>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index c3a62b0..0623205 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Kanselleer"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Deel"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Skermopname is gekanselleer"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Skermopname is gestoor, tik om te sien"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Kon nie skermopname uitvee nie"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Kon nie toestemmings kry nie"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Kon nie skermopname begin nie"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Tot sonsopkoms"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aan om <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Tot <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Verminder helderheid"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is gedeaktiveer"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is geaktiveer"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ontsluit om NFC te gebruik"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Hierdie toestel behoort aan jou organisasie"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Hierdie toestel behoort aan <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Hierdie toestel word verskaf deur <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Swiep vanaf ikoon vir foon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Swiep vanaf ikoon vir stembystand"</string>
<string name="camera_hint" msgid="4519495795000658637">"Swiep vanaf ikoon vir kamera"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tik om te demp. Toeganklikheidsdienste kan dalk gedemp wees."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tik om op vibreer te stel."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tik om te demp."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Tik om luiermodus te verander"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"demp"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ontdemp"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibreer"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 0c0487d..cf7e9fd 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ይቅር"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"አጋራ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"የማያ ገጽ ቀረጻ ተሰርዟል"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"የማያ ገጽ ቀረጻ ተቀምጧል፣ ለመመልከት መታ ያድርጉ"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"የማያ ገጽ ቀረጻን መሰረዝ ላይ ስህተት"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ፈቃዶችን ማግኘት አልተቻለም"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"የማያ ገጽ ቀረጻን መጀመር ላይ ስህተት"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"ጸሐይ እስክትወጣ ድረስ"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> ላይ ይበራል"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"እስከ <xliff:g id="TIME">%s</xliff:g> ድረስ"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"ብሩህነትን ይቀንሱ"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"ኤንኤፍሲ"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"ኤንኤፍሲ ተሰናክሏል"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"ኤንኤፍሲ ነቅቷል"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCን ለመጠቀም ይክፈቱ"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ይህ መሣሪያ የድርጅትዎ ነው"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"ይህ መሳሪያ ንብረትነቱ የ<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ነው"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"ይህ መሣሪያ በ<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>የሚቀርብ ነው"</string>
<string name="phone_hint" msgid="6682125338461375925">"ለስልክ ከአዶ ላይ ጠረግ ያድርጉ"</string>
<string name="voice_hint" msgid="7476017460191291417">"ለድምጽ ረዳት ከአዶ ጠረግ ያድርጉ"</string>
<string name="camera_hint" msgid="4519495795000658637">"ለካሜራ ከአዶ ላይ ጠረግ ያድርጉ"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s። ድምጸ-ከል ለማድረግ መታ ያድርጉ። የተደራሽነት አገልግሎቶች ድምጸ-ከል ሊደረግባቸው ይችላል።"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s። ወደ ንዝረት ለማቀናበር መታ ያድርጉ።"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s። ድምጸ-ከል ለማድረግ መታ ያድርጉ።"</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"የደዋይ ሁነታን ለመቀየር መታ ያድርጉ"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ድምጸ-ከል አድርግ"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ድምጸ-ከልን አንሳ"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ንዘር"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index ae8df90..db76744 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"إلغاء"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"مشاركة"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"تمّ إلغاء تسجيل الشاشة."</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"تمّ حفظ تسجيل الشاشة، انقر لعرضه."</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"حدث خطأ أثناء حذف تسجيل الشاشة."</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"تعذّر الحصول على أذونات."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"حدث خطأ في بدء تسجيل الشاشة"</string>
@@ -420,8 +423,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"حتى شروق الشمس"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"تفعيل الوضع في <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"حتى <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"تقليل السطوع"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"تم إيقاف الاتصال القريب المدى"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"تم تفعيل الاتصال القريب المدى"</string>
@@ -455,8 +457,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"افتح قفل الشاشة لاستخدام تقنية NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"هذا الجهاز يخص مؤسستك."</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"هذا الجهاز يخص <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>."</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"توفر مؤسسة \"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>\" هذا الجهاز."</string>
<string name="phone_hint" msgid="6682125338461375925">"يمكنك التمرير سريعًا من الرمز لتشغيل الهاتف"</string>
<string name="voice_hint" msgid="7476017460191291417">"يمكنك التمرير سريعًا من الرمز لتشغيل المساعد الصوتي"</string>
<string name="camera_hint" msgid="4519495795000658637">"يمكنك التمرير سريعًا من الرمز لتشغيل الكاميرا"</string>
@@ -640,8 +641,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. انقر للتجاهل. قد يتم تجاهل خدمات \"سهولة الاستخدام\"."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. انقر للتعيين على الاهتزاز."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. انقر لكتم الصوت."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"انقر لتغيير وضع الرنين."</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"كتم الصوت"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"إعادة الصوت"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"اهتزاز"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 1f92570..47c86ec 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"বাতিল কৰক"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"শ্বেয়াৰ কৰক"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"স্ক্রীণ ৰেকৰ্ড কৰাটো বাতিল কৰা হ’ল"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"স্ক্রীণ ৰেকৰ্ডিং ছেভ কৰা হ’ল, চাবলৈ টিপক"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"স্ক্রীণ ৰেকৰ্ডিং মচি থাকোঁতে কিবা আসোঁৱাহ হ’ল"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"অনুমতি পাব পৰা নগ\'ল"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"স্ক্রীন ৰেকৰ্ড কৰা আৰম্ভ কৰোঁতে আসোঁৱাহ হৈছে"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"সূৰ্যোদয়লৈকে"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>ত অন কৰক"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> পৰ্যন্ত"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"উজ্জ্বলতা কমাওক"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC নিষ্ক্ৰিয় হৈ আছে"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC সক্ষম হৈ আছে"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ব্যৱহাৰ কৰিবলৈ আনলক কৰক"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"এই ডিভাইচটো আপোনাৰ প্ৰতিষ্ঠানৰ"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"এই ডিভাইচটো <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>ৰ"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"এই ডিভাইচটো <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>এ প্ৰদান কৰিছে"</string>
<string name="phone_hint" msgid="6682125338461375925">"ফ\'নৰ বাবে আইকনৰপৰা ছোৱাইপ কৰক"</string>
<string name="voice_hint" msgid="7476017460191291417">"কণ্ঠধ্বনিৰে সহায়ৰ বাবে আইকনৰ পৰা ছোৱাইপ কৰক"</string>
<string name="camera_hint" msgid="4519495795000658637">"কেমেৰা খুলিবলৈ আইকনৰপৰা ছোৱাইপ কৰক"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। মিউট কৰিবলৈ টিপক। দিব্য়াংগসকলৰ বাবে থকা সেৱা মিউট হৈ থাকিব পাৰে।"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। কম্পন অৱস্থাত ছেট কৰিবলৈ টিপক।"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। মিউট কৰিবলৈ টিপক।"</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"ৰিংগাৰ ম’ড সলনি কৰিবলৈ টিপক"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"মিউট কৰক"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"আনমিউট কৰক"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"কম্পন কৰক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index e813a90..8b629c1d 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Ləğv edin"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Paylaşın"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekranın video çəkimi ləğv edildi"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Ekranın video çəkimi yadda saxlanıldı. Baxmaq üçün klikləyin"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Ekranın video çəkiminin silinməsi zamanı xəta baş verdi"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"İcazələr əldə edilmədi"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Ekranın yazılması ilə bağlı xəta"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Şəfəq vaxtına qədər"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Bu vaxt aktiv olur: <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Bu vaxtadək: <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Parlaqlığı azaldın"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC deaktiv edilib"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC aktiv edilib"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC istifadə etmək üçün kiliddən çıxarın"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Bu cihaz təşkilatınıza məxsusdur"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Bu cihaz <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> təşkilatına məxsusdur"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Bu cihaz <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> tərəfindən təmin edilib"</string>
<string name="phone_hint" msgid="6682125338461375925">"Telefon üçün ikonadan sürüşdürün"</string>
<string name="voice_hint" msgid="7476017460191291417">"Səs yardımçısı üçün ikonadan sürüşdürün"</string>
<string name="camera_hint" msgid="4519495795000658637">"Kamera üçün ikonadan sürüşdürün"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Səssiz etmək üçün tıklayın. Əlçatımlılıq xidmətləri səssiz edilmiş ola bilər."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Vibrasiyanı ayarlamaq üçün klikləyin."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Səssiz etmək üçün klikləyin."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Zəng rejimini dəyişmək üçün toxunun"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"susdurun"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"səssiz rejimdən çıxarın"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrasiya"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 27d4b18..700484c 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Otkaži"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Deli"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Snimanje ekrana je otkazano"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Snimak ekrana je sačuvan, dodirnite da biste pregledali"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Došlo je do problema pri brisanju snimka ekrana"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Preuzimanje dozvola nije uspelo"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Greška pri pokretanju snimanja ekrana"</string>
@@ -414,8 +417,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do izlaska sunca"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Uključuje se u <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Smanjite osvetljenost"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je onemogućen"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je omogućen"</string>
@@ -449,8 +451,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da biste koristili NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada organizaciji"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Ovaj uređaj pripada organizaciji <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Ovaj uređaj pruža <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Prevucite od ikone za telefon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Prevucite od ikone za glasovnu pomoć"</string>
<string name="camera_hint" msgid="4519495795000658637">"Prevucite od ikone za kameru"</string>
@@ -631,8 +632,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da biste isključili zvuk. Zvuk usluga pristupačnosti će možda biti isključen."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Dodirnite da biste podesili na vibraciju."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Dodirnite da biste isključili zvuk."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Dodirnite da biste promenili režim zvona"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"isključite zvuk"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"uključite zvuk"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibracija"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index ab1cc69..7fe5fb4 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Скасаваць"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Абагуліць"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Запіс экрана скасаваны"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Запіс экрана захаваны. Націсніце, каб прагледзець"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Памылка выдалення запісу экрана"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Не ўдалося атрымаць дазволы"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Памылка пачатку запісу экрана"</string>
@@ -416,8 +419,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Да ўсходу сонца"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Уключана ў <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Да <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Паменшыць яркасць"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC адключаны"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC уключаны"</string>
@@ -451,8 +453,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Разблакіруйце, каб выкарыстоўваць NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Гэта прылада належыць вашай арганізацыі"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Гэта прылада належыць арганізацыі \"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>\""</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Гэта прылада належыць арганізацыі \"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>\""</string>
<string name="phone_hint" msgid="6682125338461375925">"Тэлефон: правядзіце пальцам ад значка"</string>
<string name="voice_hint" msgid="7476017460191291417">"Галасавая дапамога: правядзіце пальцам ад значка"</string>
<string name="camera_hint" msgid="4519495795000658637">"Камера: правядзіце пальцам ад значка"</string>
@@ -634,8 +635,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Дакраніцеся, каб адключыць гук. Можа быць адключаны гук службаў спецыяльных магчымасцей."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Дакраніцеся, каб уключыць вібрацыю."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Дакраніцеся, каб адключыць гук"</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Націсніце, каб змяніць рэжым званка"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"выключыць гук"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"уключыць гук"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вібрыраваць"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 6716e15..4046f0f 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Отказ"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Споделяне"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Записването на екрана е анулирано"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Записът на екрана е запазен. Докоснете, за да го видите"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"При изтриването на записа на екрана възникна грешка"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Извличането на разрешенията не бе успешно."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"При стартирането на записа на екрана възникна грешка"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До изгрев"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ще се включи в <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"До <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Намаляване на яркостта"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"КБП е деактивирана"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"КБП е активирана"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Отключете, за да използвате NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Това устройство принадлежи на организацията ви"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Това устройство принадлежи на <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Това устройство е предоставено от <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Плъзнете с пръст от иконата, за да използвате телефона"</string>
<string name="voice_hint" msgid="7476017460191291417">"Прекарайте пръст от иконата, за да получите гласова помощ"</string>
<string name="camera_hint" msgid="4519495795000658637">"Плъзнете с пръст от иконата, за да включите камерата"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Докоснете, за да заглушите звука. Възможно е звукът на услугите за достъпност да бъде заглушен."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Докоснете, за да зададете вибриране."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Докоснете, за да заглушите звука."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Докоснете, за да промените режима на звънене"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"спиране"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"пускане"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вибриране"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index ee639d6..c88b578 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"বাতিল করুন"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"শেয়ার করুন"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"স্ক্রিন রেকর্ডিং বাতিল করা হয়েছে"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"স্ক্রিন রেকর্ডিং সেভ করা হয়েছে, দেখতে ট্যাপ করুন"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"স্ক্রিন রেকডিং মুছে ফেলার সময় সমস্যা হয়েছে"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"অনুমতি পাওয়া যায়নি"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"স্ক্রিন রেকর্ডিং শুরু করার সময় সমস্যা হয়েছে"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"সূর্যোদয় পর্যন্ত"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>-এ চালু হবে"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> পর্যন্ত"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"উজ্জ্বলতা কমান"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC অক্ষম করা আছে"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC সক্ষম করা আছে"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ব্যবহার করতে আনলক করুন"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"এই ডিভাইসটি আপনার প্রতিষ্ঠানের"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"এই ডিভাইসটি <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>-এর"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"এই ডিভাইস <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> দিয়েছে"</string>
<string name="phone_hint" msgid="6682125338461375925">"ফোনের জন্য আইকন থেকে সোয়াইপ করুন"</string>
<string name="voice_hint" msgid="7476017460191291417">"ভয়েস সহায়তার জন্য আইকন থেকে সোয়াইপ করুন"</string>
<string name="camera_hint" msgid="4519495795000658637">"ক্যামেরার জন্য আইকন থেকে সোয়াইপ করুন"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। মিউট করতে আলতো চাপুন। অ্যাক্সেসযোগ্যতার পরিষেবাগুলিকে মিউট করা হতে পারে।"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। ভাইব্রেট করতে ট্যাপ করুন।"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। মিউট করতে ট্যাপ করুন।"</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"রিঙ্গার মোড পরিবর্তন করতে ট্যাপ করুন"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"মিউট করুন"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"আনমিউট করুন"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ভাইব্রেট করান"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 01a55d3..ed605d4 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Otkaži"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Dijeli"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Snimanje ekrana je otkazano"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Snimak ekrana je sačuvan. Dodirnite za prikaz."</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Greška prilikom brisanja snimka ekrana"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Dobijanje odobrenja nije uspjelo"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Greška pri pokretanju snimanja ekrana"</string>
@@ -414,8 +417,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do svitanja"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Uključuje se u <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Smanjenje osvjetljenja"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je onemogućen"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je omogućen"</string>
@@ -449,8 +451,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da koristite NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada vašoj organizaciji"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Ovaj uređaj pripada organizaciji <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Ovaj uređaj pruža organizacija <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Prevucite preko ikone da otvorite telefon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Prevucite preko ikone za glasovnu pomoć"</string>
<string name="camera_hint" msgid="4519495795000658637">"Prevucite od ikone da otvorite kameru"</string>
@@ -631,8 +632,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da isključite zvuk. Zvukovi usluga pristupačnosti mogu biti isključeni."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Dodirnite da postavite vibraciju."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Dodirnite da isključite zvuk."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Dodirnite da promijenite način rada zvuka zvona"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"isključite zvuk"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"uključite zvuk"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibriranje"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 5d8ccbc..95775e9 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel·la"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Comparteix"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"S\'ha cancel·lat la gravació de la pantalla"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"S\'ha desat la gravació de la pantalla; toca per mostrar"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"S\'ha produït un error en suprimir la gravació de la pantalla"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"No s\'han pogut obtenir els permisos"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"S\'ha produït un error en iniciar la gravació de pantalla"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Fins a l\'alba"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Activat a les <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Fins a les <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reducció de la brillantor"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"L\'NFC està desactivada"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"L\'NFC està activada"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueja per utilitzar l\'NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Aquest dispositiu pertany a la teva organització"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Aquest dispositiu pertany a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> proporciona aquest dispositiu"</string>
<string name="phone_hint" msgid="6682125338461375925">"Llisca des de la icona per obrir el telèfon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Llisca des de la icona per obrir l\'assistent de veu"</string>
<string name="camera_hint" msgid="4519495795000658637">"Llisca des de la icona per obrir la càmera"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca per silenciar el so. Pot ser que els serveis d\'accessibilitat se silenciïn."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toca per activar la vibració."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toca per silenciar."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Toca per canviar el mode de timbre"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"deixar de silenciar"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 024b836..8f86d42 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Zrušit"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Sdílet"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Nahrávání obrazovky bylo zrušeno"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Záznam obrazovky byl uložen, zobrazíte jej klepnutím"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Při mazání záznamu obrazovky došlo k chybě"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nepodařilo se načíst oprávnění"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Při spouštění nahrávání obrazovky došlo k chybě"</string>
@@ -416,8 +419,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do svítání"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Zapnout v <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Snížit jas"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je vypnuto"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je zapnuto"</string>
@@ -451,8 +453,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC vyžaduje odemknutou obrazovku"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Toto zařízení patří vaší organizaci"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Toto zařízení patří organizaci <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Toto zařízení poskytuje organizace <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Telefon otevřete přejetím prstem od ikony"</string>
<string name="voice_hint" msgid="7476017460191291417">"Hlasovou asistenci otevřete přejetím prstem od ikony"</string>
<string name="camera_hint" msgid="4519495795000658637">"Fotoaparát otevřete přejetím prstem od ikony"</string>
@@ -634,8 +635,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Klepnutím vypnete zvuk. Služby přístupnosti mohou být ztlumeny."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Klepnutím nastavíte vibrace."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Klepnutím vypnete zvuk."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Klepnutím změníte režim vyzvánění"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vypnout zvuk"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"zapnout zvuk"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrovat"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index b1a7a5a..aad5d25 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annuller"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Del"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Skærmoptagelsen er annulleret"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Skærmoptagelsen er gemt. Tryk for at se den."</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Der opstod en fejl ved sletning af skærmoptagelsen"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Det lykkedes ikke et hente tilladelserne"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Skærmoptagelsen kunne ikke startes"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Indtil solopgang"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Tænd kl. <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Indtil kl. <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reducer lysstyrken"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC er deaktiveret"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC er aktiveret"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås op for at bruge NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Denne enhed tilhører din organisation"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Denne enhed tilhører <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Denne enhed er leveret af <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Stryg fra telefonikonet"</string>
<string name="voice_hint" msgid="7476017460191291417">"Stryg fra mikrofonikonet"</string>
<string name="camera_hint" msgid="4519495795000658637">"Stryg fra kameraikonet"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tryk for at slå lyden fra. Lyden i tilgængelighedstjenester kan blive slået fra."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tryk for at aktivere vibration."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tryk for at slå lyden fra."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Tryk for at ændre ringetilstand"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"slå lyden fra"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"slå lyden til"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrer"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 88dd62d..3266954 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Abbrechen"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Teilen"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Bildschirmaufzeichnung abgebrochen"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Bildschirmaufzeichnung gespeichert, zum Ansehen tippen"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Fehler beim Löschen der Bildschirmaufzeichnung"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Berechtigungen nicht erhalten"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Fehler beim Start der Bildschirmaufzeichnung"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Bis Sonnenaufgang"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"An um <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Bis <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Helligkeit verringern"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ist deaktiviert"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ist aktiviert"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Zur Verwendung von NFC entsperren"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Dieses Gerät gehört deiner Organisation"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Dieses Gerät gehört <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Dieses Gerät wird von <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> zur Verfügung gestellt"</string>
<string name="phone_hint" msgid="6682125338461375925">"Zum Öffnen des Telefons vom Symbol wegwischen"</string>
<string name="voice_hint" msgid="7476017460191291417">"Zum Öffnen des Sprachassistenten vom Symbol wegwischen"</string>
<string name="camera_hint" msgid="4519495795000658637">"Zum Öffnen der Kamera vom Symbol wegwischen"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Zum Stummschalten tippen. Bedienungshilfen werden unter Umständen stummgeschaltet."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Zum Aktivieren der Vibration tippen."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Zum Stummschalten tippen."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Zum Ändern des Klingeltonmodus tippen"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"stummschalten"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"Stummschaltung aufheben"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrieren"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 2133025..7ba7988 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Ακύρωση"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Κοινοποίηση"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Η εγγραφή οθόνης ακυρώθηκε"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Η εγγραφή οθόνης αποθηκεύτηκε. Πατήστε για προβολή."</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Παρουσιάστηκε σφάλμα κατά τη διαγραφή της εγγραφής οθόνης"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Η λήψη αδειών απέτυχε"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Σφάλμα κατά την έναρξη της εγγραφής οθόνης"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Μέχρι την ανατολή"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ενεργοποίηση στις <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Έως <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Μείωση φωτεινότητας"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Το NFC είναι απενεργοποιημένο"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Το NFC είναι ενεργοποιημένο"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ξεκλείδωμα για χρήση του NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Αυτή η συσκευή ανήκει στον οργανισμό σας."</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Αυτή η συσκευή ανήκει στον οργανισμό <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Αυτή η συσκευή παρέχεται από τον οργανισμό <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Σύρετε προς τα έξω για τηλέφωνο"</string>
<string name="voice_hint" msgid="7476017460191291417">"Σύρετε προς τα έξω για voice assist"</string>
<string name="camera_hint" msgid="4519495795000658637">"Σύρετε προς τα έξω για κάμερα"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Πατήστε για σίγαση. Οι υπηρεσίες προσβασιμότητας ενδέχεται να τεθούν σε σίγαση."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Πατήστε για να ενεργοποιήσετε τη δόνηση."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Πατήστε για σίγαση."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Πατήστε για να αλλάξετε τη λειτουργία ειδοποίησης ήχου"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"σίγαση"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"κατάργηση σίγασης"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"δόνηση"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 0a0f8f7..5cff3c0 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording cancelled"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string>
@@ -446,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"This device is provided by <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Swipe from icon for phone"</string>
<string name="voice_hint" msgid="7476017460191291417">"Swipe from icon for voice assist"</string>
<string name="camera_hint" msgid="4519495795000658637">"Swipe from icon for camera"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 403fdee..0ee5166 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording cancelled"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string>
@@ -446,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"This device is provided by <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Swipe from icon for phone"</string>
<string name="voice_hint" msgid="7476017460191291417">"Swipe from icon for voice assist"</string>
<string name="camera_hint" msgid="4519495795000658637">"Swipe from icon for camera"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 0a0f8f7..5cff3c0 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording cancelled"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string>
@@ -446,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"This device is provided by <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Swipe from icon for phone"</string>
<string name="voice_hint" msgid="7476017460191291417">"Swipe from icon for voice assist"</string>
<string name="camera_hint" msgid="4519495795000658637">"Swipe from icon for camera"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 0a0f8f7..5cff3c0 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording cancelled"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string>
@@ -446,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"This device is provided by <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Swipe from icon for phone"</string>
<string name="voice_hint" msgid="7476017460191291417">"Swipe from icon for voice assist"</string>
<string name="camera_hint" msgid="4519495795000658637">"Swipe from icon for camera"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index a665fb1..a9e2016 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording canceled"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string>
@@ -446,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organization"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"This device belongs to <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"This device is provided by <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Swipe from icon for phone"</string>
<string name="voice_hint" msgid="7476017460191291417">"Swipe from icon for voice assist"</string>
<string name="camera_hint" msgid="4519495795000658637">"Swipe from icon for camera"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index c97194f..4157fca 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -58,7 +58,7 @@
<string name="always_use_device" msgid="210535878779644679">"Abrir siempre <xliff:g id="APPLICATION">%1$s</xliff:g> cuando se conecte <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
<string name="always_use_accessory" msgid="1977225429341838444">"Abrir siempre <xliff:g id="APPLICATION">%1$s</xliff:g> cuando se conecte <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="8274884945238642726">"¿Permitir depuración por USB?"</string>
- <string name="usb_debugging_message" msgid="5794616114463921773">"La huella digital de tu clave RSA es:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_message" msgid="5794616114463921773">"La huella dactilar de tu clave RSA es:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="4003121804294739548">"Permitir siempre desde esta computadora"</string>
<string name="usb_debugging_allow" msgid="1722643858015321328">"Permitir"</string>
<string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"No tienes permitida la depuración por USB"</string>
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Compartir"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Se canceló la grabación de pantalla"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Se guardó la grabación de pantalla; presiona para verla"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"No se pudo borrar la grabación de pantalla"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Error al obtener permisos"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Error al iniciar la grabación de pantalla"</string>
@@ -135,8 +138,8 @@
<string name="accessibility_phone_button" msgid="4256353121703100427">"Teléfono"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Asistente voz"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"Desbloquear"</string>
- <string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Esperando huella digital"</string>
- <string name="accessibility_unlock_without_fingerprint" msgid="1811563723195375298">"Desbloquear sin utilizar la huella digital"</string>
+ <string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"Esperando huella dactilar"</string>
+ <string name="accessibility_unlock_without_fingerprint" msgid="1811563723195375298">"Desbloquear sin utilizar la huella dactilar"</string>
<string name="accessibility_scanning_face" msgid="3093828357921541387">"Escaneando rostro"</string>
<string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Enviar"</string>
<string name="accessibility_manage_notification" msgid="582215815790143983">"Administrar notificaciones"</string>
@@ -175,8 +178,8 @@
<string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Hubo demasiados intentos incorrectos. Se borrará este usuario."</string>
<string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Hubo demasiados intentos incorrectos. Se borrarán este perfil de trabajo y sus datos."</string>
<string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Descartar"</string>
- <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toca el sensor de huellas digitales"</string>
- <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ícono de huella digital"</string>
+ <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toca el sensor de huellas dactilares"</string>
+ <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ícono de huella dactilar"</string>
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Autenticando tu rostro…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ícono de rostro"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Botón de zoom de compatibilidad"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hasta el amanecer"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"A la(s) <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Hasta la(s) <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reducir el brillo"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"La tecnología NFC está inhabilitada"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"La tecnología NFC está habilitada"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea el dispositivo para usar NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertenece a tu organización"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertenece a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> proporciona este dispositivo"</string>
<string name="phone_hint" msgid="6682125338461375925">"Desliza el dedo para desbloquear el teléfono."</string>
<string name="voice_hint" msgid="7476017460191291417">"Desliza el dedo desde el ícono para abrir asistente de voz."</string>
<string name="camera_hint" msgid="4519495795000658637">"Desliza el dedo para acceder a la cámara."</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Presiona para silenciar. Es posible que los servicios de accesibilidad estén silenciados."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Presiona para establecer el modo vibración."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Presiona para silenciar."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Presiona para cambiar el modo de timbre"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"dejar de silenciar"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 4c5ef0b..8d8f5b5 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Compartir"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Se ha cancelado la grabación de la pantalla"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Se ha guardado la grabación de la pantalla; toca para verla"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"No se ha podido eliminar la grabación de la pantalla"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"No se han podido obtener los permisos"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"No se ha podido empezar a grabar la pantalla"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hasta el amanecer"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"A las <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Hasta las <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reducir brillo"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"El NFC está desactivado"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"El NFC está activado"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea para usar el NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertenece a tu organización"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertenece a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Este dispositivo lo proporciona <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Desliza desde el icono para abrir el teléfono"</string>
<string name="voice_hint" msgid="7476017460191291417">"Desliza desde el icono para abrir asistente de voz"</string>
<string name="camera_hint" msgid="4519495795000658637">"Desliza desde el icono para abrir la cámara"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca para silenciar. Los servicios de accesibilidad pueden silenciarse."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toca para activar la vibración."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toca para silenciar."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Toca para cambiar el modo de timbre"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"dejar de silenciar"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 65c5930..06fcd05 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Tühista"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Jaga"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekraanikuva salvestamine on tühistatud"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Ekraanikuva salvestis on salvestatud, puudutage vaatamiseks"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Viga ekraanikuva salvestise kustutamisel"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Lubade hankimine ebaõnnestus"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Viga ekraanikuva salvestamise alustamisel"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Kuni päikesetõusuni"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Sisse kell <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Kuni <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Ereduse vähendamine"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC on keelatud"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC on lubatud"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC kasutamiseks avage."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"See seade kuulub teie organisatsioonile"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Selle seadme omanik on <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Selle seadme on andnud <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Telefoni kasutamiseks pühkige ikoonilt eemale"</string>
<string name="voice_hint" msgid="7476017460191291417">"Häälabi kasutamiseks pühkige ikoonilt eemale"</string>
<string name="camera_hint" msgid="4519495795000658637">"Kaamera kasutamiseks pühkige ikoonilt eemale"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Puudutage vaigistamiseks. Juurdepääsetavuse teenused võidakse vaigistada."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Puudutage vibreerimise määramiseks."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Puudutage vaigistamiseks."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Puudutage telefonihelina režiimi muutmiseks"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vaigistamine"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"vaigistuse tühistamine"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibreerimine"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 9cebde1..2eab6eb 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Utzi"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Partekatu"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Utzi zaio pantaila grabatzeari"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Gorde da pantailaren grabaketa; sakatu ikusteko"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Errore bat gertatu da pantailaren grabaketa ezabatzean"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Ezin izan dira lortu baimenak"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Errore bat gertatu da pantaila grabatzen hastean"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Egunsentira arte"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aktibatze-ordua: <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Desaktibatze-ordua: <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Murriztu distira"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Desgaituta dago NFC"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Gaituta dago NFC"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desblokea ezazu NFC erabiltzeko"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Gailu hau zure erakundearena da"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Gailu hau <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> erakundearena da"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> erakundeak eman du gailu hau"</string>
<string name="phone_hint" msgid="6682125338461375925">"Pasatu hatza ikonotik, telefonoa irekitzeko"</string>
<string name="voice_hint" msgid="7476017460191291417">"Pasatu hatza ikonotik, ahots-laguntza irekitzeko"</string>
<string name="camera_hint" msgid="4519495795000658637">"Pasatu hatza ikonotik, kamera irekitzeko"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Sakatu audioa desaktibatzeko. Baliteke erabilerraztasun-eginbideen audioa desaktibatzea."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Sakatu hau dardara ezartzeko."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Sakatu hau audioa desaktibatzeko."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Sakatu tonu-jotzailearen modua aldatzeko"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desaktibatu audioa"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"aktibatu audioa"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"dardara"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 04b14f1..b25f118 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"لغو"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"همرسانی"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ضبط صفحهنمایش لغو شد"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"ضبط صفحهنمایش ذخیره شد، برای مشاهده ضربه بزنید"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"خطا در حذف فایل ضبط صفحهنمایش"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"مجوزها دریافت نشدند"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"خطا هنگام شروع ضبط صفحهنمایش"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"تا طلوع آفتاب"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"ساعت <xliff:g id="TIME">%s</xliff:g> روشن میشود"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"تا<xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"کاهش روشنایی"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"ارتباط میدان نزدیک (NFC)"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"«ارتباط میدان نزدیک» (NFC) غیرفعال است"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"«ارتباط میدان نزدیک» (NFC) فعال است"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"برای استفاده از NFC، قفل را باز کنید"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"این دستگاه به سازمان شما تعلق دارد"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"این دستگاه به <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> تعلق دارد"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"این دستگاه را <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ارائه داده است"</string>
<string name="phone_hint" msgid="6682125338461375925">"انگشتتان را از نماد تلفن تند بکشید"</string>
<string name="voice_hint" msgid="7476017460191291417">"برای «دستیار صوتی»، تند بکشید"</string>
<string name="camera_hint" msgid="4519495795000658637">"انگشتتان را از نماد دوربین تند بکشید"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. برای صامت کردن ضربه بزنید. ممکن است سرویسهای دسترسپذیری صامت شود."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. برای تنظیم روی لرزش، ضربه بزنید."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. برای صامت کردن ضربه بزنید."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"برای تغییر حالت زنگ، ضربه بزنید"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"صامت کردن"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"باصدا کردن"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"لرزش"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index d08bfb5..c9043d1 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Peruuta"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Jaa"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Näytön tallennus peruutettu"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Näyttötallenne tallennettu, katso napauttamalla"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Virhe poistettaessa näyttötallennetta"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Käyttöoikeuksien hakeminen epäonnistui."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Virhe näytön tallennuksen aloituksessa"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Auringonnousuun"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Päälle klo <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> asti"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Vähennä kirkkautta"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC on poistettu käytöstä"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC on käytössä"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Avaa lukitus, jotta voit käyttää NFC:tä"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Organisaatiosi omistaa tämän laitteen"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> omistaa tämän laitteen"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> tarjoaa tämän laitteen"</string>
<string name="phone_hint" msgid="6682125338461375925">"Avaa puhelu pyyhkäisemällä."</string>
<string name="voice_hint" msgid="7476017460191291417">"Avaa ääniapuri pyyhkäisemällä kuvakkeesta."</string>
<string name="camera_hint" msgid="4519495795000658637">"Avaa kamera pyyhkäisemällä."</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Mykistä koskettamalla. Myös esteettömyyspalvelut saattavat mykistyä."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Siirry värinätilaan napauttamalla."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Mykistä napauttamalla."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Vaihda soittoäänen tilaa napauttamalla"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mykistä"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"poista mykistys"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"värinä"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 3d1ab93..8e6c39c 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annuler"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Partager"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"L\'enregistrement d\'écran a été annulé"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"L\'enregistrement d\'écran est terminé. Touchez ici pour l\'afficher."</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Une erreur s\'est produite lors de la suppression de l\'enregistrement d\'écran"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Impossible d\'obtenir les autorisations"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Une erreur s\'est produite lors du démarrage de l\'enregistrement d\'écran"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Jusqu\'à l\'aube"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Actif à <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Jusqu\'à <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Réduire la luminosité"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC désactivée"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC activée"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour utiliser la NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Cet appareil appartient à <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Cet appareil est fourni par <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Balayez à partir de l\'icône pour accéder au téléphone"</string>
<string name="voice_hint" msgid="7476017460191291417">"Balayez à partir de l\'icône pour accéder à l\'assist. vocale"</string>
<string name="camera_hint" msgid="4519495795000658637">"Balayez à partir de l\'icône pour accéder à l\'appareil photo"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Touchez pour couper le son. Il est possible de couper le son des services d\'accessibilité."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Touchez pour activer les vibrations."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Touchez pour couper le son."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Touchez pour modifier le mode de sonnerie"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"désactiver le son"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"réactiver le son"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibration"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index c6d0674..837a424 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annuler"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Partager"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Enregistrement de l\'écran annulé"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Enregistrement de l\'écran enregistré. Appuyez pour afficher"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Erreur lors de la suppression de l\'enregistrement de l\'écran"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Échec d\'obtention des autorisations"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Erreur lors du démarrage de l\'enregistrement de l\'écran"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Jusqu\'à l\'aube"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"À partir de <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Jusqu\'à <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Réduire la luminosité"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC désactivée"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"La technologie NFC est activée"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour pouvoir utiliser NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Cet appareil appartient à <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Cet appareil est fourni par <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Balayer pour téléphoner"</string>
<string name="voice_hint" msgid="7476017460191291417">"Balayer l\'écran depuis l\'icône pour l\'assistance vocale"</string>
<string name="camera_hint" msgid="4519495795000658637">"Balayer pour prendre une photo"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Appuyez pour ignorer. Vous pouvez ignorer les services d\'accessibilité."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Appuyez pour mettre en mode vibreur."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Appuyez pour ignorer."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Appuyez pour changer le mode de la sonnerie"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"couper le son"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"réactiver le son"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"activer le vibreur"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 08841a2..199dd54 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Compartir"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Cancelouse a gravación de pantalla"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Gardouse a gravación de pantalla; toca esta notificación para visualizala"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Produciuse un erro ao eliminar a gravación de pantalla"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Produciuse un erro ao obter os permisos"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Produciuse un erro ao iniciar a gravación da pantalla"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Ata o amencer"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Activarase ás: <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Utilizarase ata as: <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reducir brillo"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"A opción NFC está desactivada"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"A opción NFC está activada"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea o dispositivo para utilizar a NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence á túa organización"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertence a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> proporciona este dispositivo"</string>
<string name="phone_hint" msgid="6682125338461375925">"Pasa o dedo desde a icona para acceder ao teléfono"</string>
<string name="voice_hint" msgid="7476017460191291417">"Pasa o dedo desde a icona para acceder ao asistente de voz"</string>
<string name="camera_hint" msgid="4519495795000658637">"Pasa o dedo desde a icona para acceder á cámara"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toca para silenciar. Pódense silenciar os servizos de accesibilidade."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toca para establecer a vibración."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toca para silenciar."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Toca para cambiar o modo de timbre"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"activar o son"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 867bc2f..d19c341 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"રદ કરો"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"શેર કરો"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"સ્ક્રીન રેકોર્ડિંગ રદ કર્યું"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"સ્ક્રીન રેકોર્ડિંગ સાચવ્યું, જોવા માટે ટૅપ કરો"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"સ્ક્રીન રેકોર્ડિંગ ડિલીટ કરવામાં ભૂલ આવી"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"પરવાનગીઓ મેળવવામાં નિષ્ફળ રહ્યાં"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"સ્ક્રીનને રેકૉર્ડ કરવાનું શરૂ કરવામાં ભૂલ"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"સૂર્યોદય સુધી"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> વાગ્યે ચાલુ"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> વાગ્યા સુધી"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"બ્રાઇટનેસ ઘટાડો"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC અક્ષમ કરેલ છે"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC સક્ષમ કરેલ છે"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCનો ઉપયોગ કરવા માટે અનલૉક કરો"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"આ ડિવાઇસ તમારી સંસ્થાની માલિકીનું છે"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"આ ડિવાઇસ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>ની માલિકીનું છે"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"આ ડિવાઇસ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> દ્વારા પ્રદાન કરવામાં આવેલું છે"</string>
<string name="phone_hint" msgid="6682125338461375925">"ફોન માટે આયકનમાંથી સ્વાઇપ કરો"</string>
<string name="voice_hint" msgid="7476017460191291417">"વૉઇસ સહાય માટે આયકનમાંથી સ્વાઇપ કરો"</string>
<string name="camera_hint" msgid="4519495795000658637">"કૅમેરા માટે આયકનમાંથી સ્વાઇપ કરો"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. મ્યૂટ કરવા માટે ટૅપ કરો. ઍક્સેસિબિલિટી સેવાઓ મ્યૂટ કરવામાં આવી શકે છે."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. કંપન પર સેટ કરવા માટે ટૅપ કરો."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. મ્યૂટ કરવા માટે ટૅપ કરો."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"રિંગર મોડ બદલવા માટે ટૅપ કરો"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"મ્યૂટ કરો"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"અનમ્યૂટ કરો"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"વાઇબ્રેટ"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index a357ad2..764acad 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"रद्द करें"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"शेयर करें"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"स्क्रीन रिकॉर्डिंग रद्द कर दी गई"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"स्क्रीन रिकॉर्डिंग सेव की गई, देखने के लिए टैप करें"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"स्क्रीन रिकॉर्डिंग मिटाने में गड़बड़ी हुई"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"मंज़ूरी नहीं मिल सकी"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"स्क्रीन को रिकॉर्ड करने में गड़बड़ी आ रही है"</string>
@@ -414,8 +417,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"सुबह तक चालू रहेगी"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> पर चालू हाेगी"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> तक चालू रहेगी"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"स्क्रीन की चमक कम करें"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"एनएफ़सी"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC बंद है"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC चालू है"</string>
@@ -449,8 +451,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"एनएफ़सी इस्तेमाल करने के लिए स्क्रीन को अनलॉक करें"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"इस डिवाइस का मालिकाना हक आपके संगठन के पास है"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"इस डिवाइस का मालिकाना हक <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> के पास है"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"यह डिवाइस <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ने दिया है"</string>
<string name="phone_hint" msgid="6682125338461375925">"फ़ोन के लिए आइकॉन से स्वाइप करें"</string>
<string name="voice_hint" msgid="7476017460191291417">"\'आवाज़ से डिवाइस का इस्तेमाल\' आइकॉन से स्वाइप करें"</string>
<string name="camera_hint" msgid="4519495795000658637">"कैमरे के लिए आइकॉन से स्वाइप करें"</string>
@@ -630,8 +631,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. म्यूट करने के लिए टैप करें. सुलभता सेवाएं म्यूट हो सकती हैं."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. कंपन (वाइब्रेशन) पर सेट करने के लिए छूएं."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. म्यूट करने के लिए टैप करें."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"रिंगर मोड बदलने के लिए टैप करें"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"म्यूट करें"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"अनम्यूट करें"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"वाइब्रेशन की सुविधा चालू करें"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index d8064ab..55970a0 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Odustani"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Dijeli"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Snimanje zaslona otkazano"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Snimanje zaslona spremljeno je, dodirnite da biste ga pregledali"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Pogreška prilikom brisanja snimanja zaslona"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Dohvaćanje dopuštenja nije uspjelo"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Pogreška prilikom pokretanja snimanja zaslona"</string>
@@ -414,8 +417,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do izlaska sunca"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Uključuje se u <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Smanjenje svjetline"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je onemogućen"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je omogućen"</string>
@@ -449,8 +451,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da biste upotrijebili NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada vašoj organizaciji"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Ovaj uređaj pripada organizaciji <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Ovaj uređaj pruža organizacija <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Prijeđite prstom od ikone za telefon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Prijeđite prstom od ikone za glasovnu pomoć"</string>
<string name="camera_hint" msgid="4519495795000658637">"Prijeđite prstom od ikone za fotoaparat"</string>
@@ -631,8 +632,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dodirnite da biste isključili zvuk. Usluge pristupačnosti možda neće imati zvuk."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Dodirnite da biste postavili na vibraciju."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Dodirnite da biste isključili zvuk."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Dodirnite da biste promijenili način softvera zvona"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"isključivanje zvuka"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"uključivanje zvuka"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibriranje"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index a736f88..ee3f45d 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Mégse"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Megosztás"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"A képernyő rögzítése megszakítva"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Képernyőfelvétel mentve, koppintson a megtekintéshez"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Hiba történt a képernyőről készült felvétel törlésekor"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nincs engedély"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Hiba a képernyőrögzítés indításakor"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Napfelkeltéig"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Be: <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Eddig: <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Fényerő csökkentése"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Az NFC ki van kapcsolva"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Az NFC be van kapcsolva"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Az NFC használatához oldja fel a képernyőzárat"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ez az eszköz az Ön szervezetének tulajdonában van"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Ez az eszköz a(z) <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> tulajdonában van"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Ezt az eszközt a(z) <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> szervezet biztosítja"</string>
<string name="phone_hint" msgid="6682125338461375925">"A telefonhoz csúsztasson az ikonról"</string>
<string name="voice_hint" msgid="7476017460191291417">"A hangsegéd eléréséhez csúsztassa ujját az ikonról"</string>
<string name="camera_hint" msgid="4519495795000658637">"A fényképezőhöz csúsztasson az ikonról"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Koppintson a némításhoz. Előfordulhat, hogy a kisegítő lehetőségek szolgáltatásai le vannak némítva."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Koppintson a rezgés beállításához."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Koppintson a némításhoz."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Koppintson a csengés módjának módosításához"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"némítás"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"némítás feloldása"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"rezgés"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 40ddf54..84451eb 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Չեղարկել"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Կիսվել"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Էկրանի տեսագրումը չեղարկվեց"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Էկրանի տեսագրությունը պահվեց։ Հպեք՝ դիտելու համար:"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Չհաջողվեց ջնջել տեսագրությունը"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Չհաջողվեց ստանալ անհրաժեշտ թույլտվությունները"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Չհաջողվեց սկսել տեսագրումը"</string>
@@ -446,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ապակողպեք՝ NFC-ն օգտագործելու համար"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Այս սարքը պատկանում է ձեր կազմակերպությանը"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Այս սարքը պատկանում է «<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>» կազմակերպությանը"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Այս սարքը տրամադրվել է «<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>» կազմակերպության կողմից"</string>
<string name="phone_hint" msgid="6682125338461375925">"Սահահարվածեք հեռախոսի պատկերակից"</string>
<string name="voice_hint" msgid="7476017460191291417">"Սահահարվածեք ձայնային հուշման պատկերակից"</string>
<string name="camera_hint" msgid="4519495795000658637">"Սահահարվածեք խցիկի պատկերակից"</string>
@@ -985,7 +987,7 @@
<string name="privacy_type_camera" msgid="7974051382167078332">"տեսախցիկը"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"վայրը"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"խոսափողը"</string>
- <string name="sensor_privacy_mode" msgid="4462866919026513692">"Տվիչներն անջատած են"</string>
+ <string name="sensor_privacy_mode" msgid="4462866919026513692">"Տվիչներն անջատված են"</string>
<string name="device_services" msgid="1549944177856658705">"Սարքի ծառայություններ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Անանուն"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Տեղափոխել"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index e20dd51..f694e1d 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Batal"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Bagikan"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Rekaman layar dibatalkan"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Rekaman layar disimpan, ketuk untuk melihat"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error saat menghapus rekaman layar"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Gagal mendapatkan izin"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Terjadi error saat memulai perekaman layar"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Sampai pagi"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aktif pada <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Sampai <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Kurangi kecerahan"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC dinonaktifkan"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC diaktifkan"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Buka kunci untuk menggunakan NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Perangkat ini milik organisasi Anda"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Perangkat ini milik <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Perangkat ini disediakan oleh <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Geser dari ikon untuk telepon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Geser dari ikon untuk bantuan suara"</string>
<string name="camera_hint" msgid="4519495795000658637">"Geser dari ikon untuk kamera"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ketuk untuk membisukan. Layanan aksesibilitas mungkin dibisukan."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Ketuk untuk menyetel agar bergetar."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Ketuk untuk menonaktifkan."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Ketuk untuk mengubah mode pendering"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"Tanpa suara"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"aktifkan"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"getar"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 0c99420..08210ef 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Hætta við"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Deila"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Hætt við skjáupptöku"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Skjáupptaka vistuð, ýttu til að skoða"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Villa við að eyða skjáupptöku"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Ekki tókst að fá heimildir"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Villa við að hefja upptöku skjás"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Til sólarupprásar"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Virkt kl. <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Til <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Minnka birtu"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Slökkt á NFC"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Kveikt á NFC"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Taktu úr lás til að nota NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Þetta tæki tilheyrir fyrirtækinu þínu"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Þetta tæki tilheyrir <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Þetta tæki er frá <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Strjúktu frá tákninu fyrir síma"</string>
<string name="voice_hint" msgid="7476017460191291417">"Strjúktu frá tákninu fyrir raddaðstoð"</string>
<string name="camera_hint" msgid="4519495795000658637">"Strjúktu frá tákninu fyrir myndavél"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ýttu til að þagga. Hugsanlega verður slökkt á hljóði aðgengisþjónustu."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Ýttu til að stilla á titring."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Ýttu til að þagga."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Ýta til að skipta um hringjarastillingu"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"þagga"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"hætta að þagga"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"titringur"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 527a695..d47a454 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annulla"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Condividi"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Registrazione dello schermo annullata"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Registrazione dello schermo salvata. Tocca per visualizzarla."</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Errore durante l\'eliminazione della registrazione dello schermo"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Impossibile ottenere le autorizzazioni"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Errore durante l\'avvio della registrazione dello schermo"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Fino all\'alba"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Attivazione alle <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Fino alle <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Riduci la luminosità"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC non attiva"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC attiva"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Sblocca per usare NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Questo dispositivo appartiene alla tua organizzazione"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Questo dispositivo appartiene a <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Questo dispositivo è fornito da <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Scorri per accedere al telefono"</string>
<string name="voice_hint" msgid="7476017460191291417">"Scorri dall\'icona per accedere a Voice Assist"</string>
<string name="camera_hint" msgid="4519495795000658637">"Scorri dall\'icona per accedere alla fotocamera"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tocca per disattivare l\'audio. L\'audio dei servizi di accessibilità può essere disattivato."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tocca per attivare la vibrazione."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tocca per disattivare l\'audio."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Tocca per cambiare la modalità della suoneria"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"disattiva l\'audio"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"riattiva l\'audio"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrazione"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 9fc8b23..e937a5a 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ביטול"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"שיתוף"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"הקלטת המסך בוטלה"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"הקלטת המסך נשמרה, יש להקיש כדי להציג"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"שגיאה במחיקת הקלטת המסך"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"קבלת ההרשאות נכשלה"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"שגיאה בהפעלה של הקלטת המסך"</string>
@@ -416,8 +419,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"עד הזריחה"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"יתחיל בשעה <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"עד <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"הפחתה של עוצמת הבהירות"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC מושבת"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC מופעל"</string>
@@ -451,8 +453,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"יש לבטל את הנעילה כדי להשתמש ב-NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"המכשיר הזה שייך לארגון שלך"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"המכשיר הזה שייך לארגון <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"המכשיר הזה התקבל מ-<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"החלק מהסמל כדי להפעיל את הטלפון"</string>
<string name="voice_hint" msgid="7476017460191291417">"החלק מהסמל כדי להפעיל את המסייע הקולי"</string>
<string name="camera_hint" msgid="4519495795000658637">"החלק מהסמל כדי להפעיל את המצלמה"</string>
@@ -634,8 +635,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. הקש כדי להשתיק. ייתכן ששירותי הנגישות מושתקים."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. הקש כדי להעביר למצב רטט."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. הקש כדי להשתיק."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"יש להקיש כדי לשנות את מצב תוכנת הצלצול"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"השתקה"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ביטול ההשתקה"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"רטט"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 1b18b5c..802e160 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"キャンセル"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"共有"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"画面の録画をキャンセルしました"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"画面の録画を保存しました。タップで表示できます"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"画面の録画の削除中にエラーが発生しました"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"権限を取得できませんでした"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"画面の録画中にエラーが発生しました"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"日の出まで"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>にオン"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g>まで"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"明るさを下げる"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC は無効です"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC は有効です"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC を使用するには、ロックを解除してください"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"これは組織が所有するデバイスです"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"これは <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> が所有するデバイスです"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"このデバイスは <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> から提供されています"</string>
<string name="phone_hint" msgid="6682125338461375925">"右にスワイプして通話"</string>
<string name="voice_hint" msgid="7476017460191291417">"アイコンからスワイプして音声アシストを起動"</string>
<string name="camera_hint" msgid="4519495795000658637">"左にスワイプしてカメラを起動"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。タップしてミュートします。ユーザー補助機能サービスがミュートされる場合があります。"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s。タップしてバイブレーションに設定します。"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s。タップしてミュートします。"</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"タップすると、着信音のモードを変更できます"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ミュート"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ミュートを解除"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"バイブレーション"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index e2b9fac..53cf03e 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"გაუქმება"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"გაზიარება"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ეკრანის ჩაწერა გაუქმდა"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"ეკრანის ჩანაწერი შენახულია, შეეხეთ სანახავად"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ეკრანის ჩანაწერის წაშლისას წარმოიშვა შეცდომა"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ნებართვების მიღება ვერ მოხერხდა"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ეკრანის ჩაწერის დაწყებისას წარმოიქმნა შეცდომა"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"მზის ამოსვლამდე"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"ჩაირთოს <xliff:g id="TIME">%s</xliff:g>-ზე"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g>-მდე"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"სიკაშკაშის შემცირება"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC გათიშულია"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ჩართულია"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"განბლოკეთ NFC-ის გამოსაყენებლად"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ამ მოწყობილობას ფლობს თქვენი ორგანიზაცია"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"ამ მოწყობილობას ფლობს <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"ამ მოწყობილობის მომწოდებელია <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"ტელეფონისთვის გადაფურცლეთ ხატულადან"</string>
<string name="voice_hint" msgid="7476017460191291417">"ხმოვანი დახმარებისთვის გადაფურცლეთ ხატულადან"</string>
<string name="camera_hint" msgid="4519495795000658637">"კამერისთვის გადაფურცლეთ ხატულადან"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. შეეხეთ დასადუმებლად. შეიძლება დადუმდეს მარტივი წვდომის სერვისებიც."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. შეეხეთ ვიბრაციაზე დასაყენებლად."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. შეეხეთ დასადუმებლად."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"შეეხეთ მრეკავის რეჟიმის შესაცვლელად"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"დადუმება"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"დადუმების მოხსნა"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ვიბრაცია"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 1fbb8a5..6851942 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Бас тарту"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Бөлісу"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Экранды бейнеге жазудан бас тартылды"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Экран бейне жазбасы сақталды, көру үшін түртіңіз"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Экран бейне жазбасын жою кезінде қате кетті"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Рұқсаттар алынбады"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Экрандағы бейнені жазу кезінде қате шықты."</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Күн шыққанға дейін"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Қосылу уақыты: <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> дейін"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Жарықтығын азайту"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC өшірулі"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC қосулы"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC пайдалану үшін құлыпты ашыңыз."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Бұл құрылғы ұйымыңызға тиесілі."</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Бұл құрылғы <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ұйымына тиесілі."</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Бұл құрылғыны <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ұсынады."</string>
<string name="phone_hint" msgid="6682125338461375925">"Телефонды ашу үшін белгішеден әрі қарай сырғытыңыз"</string>
<string name="voice_hint" msgid="7476017460191291417">"Дауыс көмекшісін ашу үшін белгішеден әрі қарай сырғытыңыз"</string>
<string name="camera_hint" msgid="4519495795000658637">"Камераны ашу үшін белгішеден әрі қарай сырғытыңыз"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Дыбысын өшіру үшін түртіңіз. Арнайы мүмкіндік қызметтерінің дыбысы өшуі мүмкін."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Діріл режимін орнату үшін түртіңіз."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Дыбысын өшіру үшін түртіңіз."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Қоңырау режимін өзгерту үшін түртіңіз."</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"дыбысын өшіру"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"дыбысын қосу"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"дірілдету"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index e6f9668..d7faeec 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"បោះបង់"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"ចែករំលែក"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"បានបោះបង់ការថតសកម្មភាពអេក្រង់"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"បានរក្សាទុកការថតសកម្មភាពអេក្រង់។ សូមចុចដើម្បីមើល"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"មានបញ្ហាក្នុងការលុបការថតសកម្មភាពអេក្រង់"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"មិនអាចទទួលបានការអនុញ្ញាតទេ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"មានបញ្ហាក្នុងការចាប់ផ្ដើមថតអេក្រង់"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"រហូតដល់ពេលថ្ងៃរះ"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"បើកនៅម៉ោង <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"រហូតដល់ម៉ោង <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"បន្ថយពន្លឺ"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"បានបិទ NFC"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"បានបើក NFC"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"ដោះសោ ដើម្បីប្រើ NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ឧបករណ៍នេះគឺជាកម្មសិទ្ធិរបស់ស្ថាប័នអ្នក"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"ឧបករណ៍នេះគឺជាកម្មសិទ្ធិរបស់ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"ឧបករណ៍នេះត្រូវបានផ្ដល់ដោយ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"អូសចេញពីរូបតំណាងដើម្បីប្រើទូរស័ព្ទ"</string>
<string name="voice_hint" msgid="7476017460191291417">"អូសចេញពីរូបតំណាងដើម្បីប្រើជំនួយសំឡេង"</string>
<string name="camera_hint" msgid="4519495795000658637">"អូសចេញពីរូបតំណាងដើម្បីប្រើកាមេរ៉ា"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s។ ប៉ះដើម្បីបិទសំឡេង។ សេវាកម្មលទ្ធភាពប្រើប្រាស់អាចនឹងត្រូវបានបិទសំឡេង។"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s ។ ចុចដើម្បីកំណត់ឲ្យញ័រ។"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s ។ ចុចដើម្បីបិទសំឡេង។"</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"ចុចដើម្បីប្ដូរមុខងាររោទ៍"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"បិទសំឡេង"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"បើកសំឡេង"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ញ័រ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 15abcaa..851039f 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ರದ್ದುಮಾಡಿ"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"ಹಂಚಿಕೊಳ್ಳಿ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಅನ್ನು ರದ್ದುಮಾಡಲಾಗಿದೆ"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಅನ್ನು ಉಳಿಸಲಾಗಿದೆ, ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಅಳಿಸುವಾಗ ದೋಷ ಕಂಡುಬಂದಿದೆ"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ಅನುಮತಿಗಳನ್ನು ಪಡೆಯುವಲ್ಲಿ ವಿಫಲವಾಗಿದೆ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಪ್ರಾರಂಭಿಸುವಾಗ ದೋಷ ಕಂಡುಬಂದಿದೆ"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"ಸೂರ್ಯೋದಯದವರೆಗೆ"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> ಸಮಯದಲ್ಲಿ"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> ವರೆಗೂ"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"ಪ್ರಖರತೆಯನ್ನು ಕಡಿಮೆ ಮಾಡಿ"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ನಿಷ್ಕ್ರಿಯಗೊಂಡಿದೆ"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ಸಕ್ರಿಯಗೊಂಡಿದೆ"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ಬಳಸಲು ಅನ್ಲಾಕ್ ಮಾಡಿ"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ಈ ಸಾಧನವು ನಿಮ್ಮ ಸಂಸ್ಥೆಗೆ ಸೇರಿದೆ"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"ಈ ಸಾಧನವು <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ಗೆ ಸೇರಿದೆ"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"ಈ ಸಾಧನವನ್ನು <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ಒದಗಿಸಿದ್ದಾರೆ"</string>
<string name="phone_hint" msgid="6682125338461375925">"ಫೋನ್ಗಾಗಿ ಐಕಾನ್ನಿಂದ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
<string name="voice_hint" msgid="7476017460191291417">"ಧ್ವನಿ ಸಹಾಯಕ್ಕಾಗಿ ಐಕಾನ್ನಿಂದ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
<string name="camera_hint" msgid="4519495795000658637">"ಕ್ಯಾಮರಾಗಾಗಿ ಐಕಾನ್ನಿಂದ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ಮ್ಯೂಟ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಪ್ರವೇಶಿಸುವಿಕೆ ಸೇವೆಗಳನ್ನು ಮ್ಯೂಟ್ ಮಾಡಬಹುದು."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. ವೈಬ್ರೇಟ್ ಮಾಡಲು ಹೊಂದಿಸುವುದಕ್ಕಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. ಮ್ಯೂಟ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"ರಿಂಗರ್ ಮೋಡ್ ಬದಲಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ಮ್ಯೂಟ್ ಮಾಡಿ"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ಅನ್ಮ್ಯೂಟ್ ಮಾಡಿ"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ವೈಬ್ರೇಟ್"</string>
@@ -1043,8 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"ಸೇರಿಸಿ"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ಆ್ಯಪ್ ಸೂಚಿಸಿದೆ"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"ನಿಯಂತ್ರಣಗಳನ್ನು ನವೀಕರಿಸಲಾಗಿದೆ"</string>
- <!-- no translation found for controls_tile_locked (731547768182831938) -->
- <skip />
+ <string name="controls_tile_locked" msgid="731547768182831938">"ಸಾಧನ ಲಾಕ್ ಆಗಿದೆ"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ಪಿನ್ ಅಕ್ಷರಗಳು ಅಥವಾ ಸಂಕೇತಗಳನ್ನು ಒಳಗೊಂಡಿದೆ"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ಅನ್ನು ಪರಿಶೀಲಿಸಿ"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"ತಪ್ಪಾದ ಪಿನ್"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 78c2958..d4289925 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"취소"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"공유"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"화면 녹화가 취소되었습니다."</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"화면 녹화본이 저장되었습니다. 확인하려면 탭하세요."</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"화면 녹화는 삭제하는 중에 오류가 발생했습니다."</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"권한을 확보하지 못했습니다."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"화면 녹화 시작 중 오류 발생"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"일출까지"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>에 켜짐"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g>까지"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"밝기 낮추기"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC 사용 중지됨"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC 사용 설정됨"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"잠금 해제하여 NFC 사용"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"내 조직에 속한 기기입니다."</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>에 속한 기기입니다."</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"이 기기는 <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>에서 제공합니다"</string>
<string name="phone_hint" msgid="6682125338461375925">"전화 기능을 사용하려면 아이콘에서 스와이프하세요."</string>
<string name="voice_hint" msgid="7476017460191291417">"음성 지원을 사용하려면 아이콘에서 스와이프하세요."</string>
<string name="camera_hint" msgid="4519495795000658637">"카메라를 사용하려면 아이콘에서 스와이프하세요."</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. 탭하여 음소거로 설정하세요. 접근성 서비스가 음소거될 수 있습니다."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. 탭하여 진동으로 설정하세요."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. 탭하여 음소거로 설정하세요."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"탭하여 벨소리 장치 모드 변경"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"음소거"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"음소거 해제"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"진동"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 7a4d7d2..d726d55 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Жокко чыгаруу"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Бөлүшүү"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Экранды жаздыруу жокко чыгарылды"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Экранды жаздыруу сакталды, көрүү үчүн таптап коюңуз"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Экранды жаздырууну өчүрүүдө ката кетти"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Уруксаттар алынбай калды"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Экранды жаздырууну баштоодо ката кетти"</string>
@@ -414,8 +417,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Күн чыкканга чейин"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Саат <xliff:g id="TIME">%s</xliff:g> күйөт"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> чейин"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Экрандын жарыктыгын төмөндөтүү"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC өчүрүлгөн"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC иштетилген"</string>
@@ -449,8 +451,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC колдонуу үчүн түзмөктүн кулпусун ачыңыз"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Бул түзмөк уюмуңузга таандык"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Бул түзмөк төмөнкүгө таандык: <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Бул түзмөктү <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> камсыздады."</string>
<string name="phone_hint" msgid="6682125338461375925">"Сүрөтчөнү сүрүп телефонго өтүңүз"</string>
<string name="voice_hint" msgid="7476017460191291417">"Сүрөтчөнү сүрүп үн жардамчысына өтүңүз"</string>
<string name="camera_hint" msgid="4519495795000658637">"Сүрөтчөнү сүрүп камерага өтүңүз"</string>
@@ -630,8 +631,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Үнүн өчүрүү үчүн таптап коюңуз. Атайын мүмкүнчүлүктөр кызматынын үнүн өчүрүп койсо болот."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Дирилдөөгө коюу үчүн басыңыз."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Үнүн өчүрүү үчүн басыңыз."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Коңгуроо режимин өзгөртүү үчүн басыңыз"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"үнсүз"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"үнүн чыгаруу"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"дирилдөө"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 7070fa1..23df8bc 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ຍົກເລີກ"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"ແບ່ງປັນ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ຍົກເລີກການບັນທຶກໜ້າຈໍແລ້ວ"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"ຈັດເກັບການບັນທຶກໜ້າຈໍ, ແຕະເພື່ອເບິ່ງ"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ເກີດຄວາມຜິດພາດໃນການລຶບການບັນທຶກໜ້າຈໍ"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ໂຫຼດສິດອະນຸຍາດບໍ່ສຳເລັດ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ເກີດຄວາມຜິດພາດໃນການບັນທຶກໜ້າຈໍ"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"ຈົນກວ່າຕາເວັນຂຶ້ນ"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"ເປີດເວລາ <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"ຈົນຮອດ <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"ຫຼຸດຄວາມສະຫວ່າງລົງ"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"ປົດລັອກເພື່ອໃຊ້ NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ອຸປະກອນນີ້ເປັນຂອງອົງການທ່ານ"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"ອຸປະກອນນີ້ເປັນຂອງ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"ອຸປະກອນນີ້ແມ່ນສະໜອງໃຫ້ໂດຍ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"ປັດຈາກໄອຄອນສຳລັບໂທລະສັບ"</string>
<string name="voice_hint" msgid="7476017460191291417">"ປັດຈາກໄອຄອນສຳລັບການຊ່ວຍທາງສຽງ"</string>
<string name="camera_hint" msgid="4519495795000658637">"ປັດຈາກໄອຄອນສຳລັບກ້ອງຖ່າຍຮູບ"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ແຕະເພື່ອປິດສຽງ. ບໍລິການຊ່ວຍເຂົ້າເຖິງອາດຖືກປິດສຽງໄວ້."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. ແຕະເພື່ອຕັ້ງເປັນສັ່ນເຕືອນ."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. ແຕະເພື່ອປິດສຽງ."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"ແຕະເພື່ອປ່ຽນໂໝດຣິງເກີ"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ປິດສຽງ"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ເຊົາປິດສຽງ"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ສັ່ນເຕືອນ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index ff69e05..64b4d6d 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Atšaukti"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Bendrinti"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekrano įrašymas atšauktas"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Ekrano įrašas išsaugotas, palieskite ir peržiūrėkite"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Ištrinant ekrano įrašą įvyko klaida"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nepavyko gauti leidimų"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Pradedant ekrano vaizdo įrašymą iškilo problema"</string>
@@ -416,8 +419,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Iki saulėtekio"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Iki <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Šviesumo mažinimas"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"ALR"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"ALR išjungtas"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"ALR įjungtas"</string>
@@ -451,8 +453,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Norėdami naudoti NFC, atrakinkite"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Šis įrenginys priklauso jūsų organizacijai"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Šis įrenginys priklauso „<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>“"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Šį įrenginį teikia „<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>“"</string>
<string name="phone_hint" msgid="6682125338461375925">"Perbraukite iš telefono piktogramos"</string>
<string name="voice_hint" msgid="7476017460191291417">"Perbraukite iš „Voice Assist“ piktogramos"</string>
<string name="camera_hint" msgid="4519495795000658637">"Perbraukite iš fotoaparato piktogramos"</string>
@@ -634,8 +635,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Palieskite, kad nutildytumėte. Gali būti nutildytos pritaikymo neįgaliesiems paslaugos."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Palieskite, kad nustatytumėte vibravimą."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Palieskite, kad nutildytumėte."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Palieskite, kad pakeistumėte skambučio režimą"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"nutildyti"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"įjungti garsą"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibruoti"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 18816ad..225b9aa 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Atcelt"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Kopīgot"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekrāna ierakstīšana ir atcelta."</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Ekrāna ieraksts ir saglabāts. Pieskarieties, lai to skatītu."</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Dzēšot ekrāna ierakstu, radās kļūda."</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Neizdevās iegūt atļaujas."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Sākot ierakstīt ekrāna saturu, radās kļūda."</string>
@@ -414,8 +417,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Līdz saullēktam"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Plkst. <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Līdz plkst. <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Samazināt spilgtumu"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ir atspējoti"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ir iespējoti"</string>
@@ -449,8 +451,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Atbloķējiet ierīci, lai izmantotu NFC."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Šī ierīce pieder jūsu organizācijai."</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Šī ierīce pieder organizācijai <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>."</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Šo ierīci nodrošina <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Lai lietotu tālruni, velciet no ikonas"</string>
<string name="voice_hint" msgid="7476017460191291417">"Lai lietotu balss palīgu, velciet no ikonas"</string>
<string name="camera_hint" msgid="4519495795000658637">"Lai lietotu kameru, velciet no ikonas"</string>
@@ -631,8 +632,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Pieskarieties, lai izslēgtu skaņu. Var tikt izslēgti pieejamības pakalpojumu signāli."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Pieskarieties, lai iestatītu vibrozvanu."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Pieskarieties, lai izslēgtu skaņu."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Pieskarieties, lai mainītu zvanītāja režīmu."</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"izslēgt skaņu"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ieslēgt skaņu"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrēt"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 59fc2d4..c74786e 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Откажи"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Сподели"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Снимањето екран е откажано"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Снимката од екранот е зачувана, допрете за да ја видите"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Грешка при бришењето на снимката од екранот"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Не успеаја да се добијат дозволи"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Грешка при почетокот на снимањето на екранот"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До изгрејсонце"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Се вклучува во <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"До <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Намалување на осветленоста"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC е оневозможено"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC е овозможено"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Отклучете за да користите NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Уредов е во сопственост на организацијата"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Уредов е во сопственост на <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> го обезбедува уредов"</string>
<string name="phone_hint" msgid="6682125338461375925">"Повлечете од иконата за телефонот"</string>
<string name="voice_hint" msgid="7476017460191291417">"Повлечете од иконата за гласовна помош"</string>
<string name="camera_hint" msgid="4519495795000658637">"Повлечете од иконата за камерата"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Допрете за да исклучите звук. Можеби ќе се исклучи звукот на услугите за достапност."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Допрете за да се постави на вибрации."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Допрете за да се исклучи звукот."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Допрете за да го промените режимот на ѕвончето"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"исклучен звук"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"вклучен звук"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вибрации"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 44883d6d..b54c6b0 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"റദ്ദാക്കുക"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"പങ്കിടുക"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"സ്ക്രീൻ റെക്കോർഡിംഗ് റദ്ദാക്കി"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"സ്ക്രീൻ റെക്കോർഡിംഗ് സംരക്ഷിച്ചു, കാണാൻ ടാപ്പ് ചെയ്യുക"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"സ്ക്രീൻ റെക്കോർഡിംഗ് ഇല്ലാതാക്കുന്നതിൽ പിശക്"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"അനുമതികൾ ലഭിച്ചില്ല"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"സ്ക്രീൻ റെക്കോർഡിംഗ് ആരംഭിക്കുന്നതിൽ പിശക്"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"സൂര്യോദയം വരെ"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>-ന്"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> വരെ"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"തെളിച്ചം കുറയ്ക്കുക"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC പ്രവർത്തനരഹിതമാക്കി"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC പ്രവർത്തനക്ഷമമാക്കി"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ഉപയോഗിക്കാൻ അൺലോക്ക് ചെയ്യുക"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ഈ ഉപകരണം നിങ്ങളുടെ സ്ഥാപനത്തിന്റേതാണ്"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"ഈ ഉപകരണം <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> എന്ന സ്ഥാപനത്തിന്റേതാണ്"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> നൽകിയ ഉപകരണമാണിത്"</string>
<string name="phone_hint" msgid="6682125338461375925">"ഫോൺ ഐക്കണിൽ നിന്ന് സ്വൈപ്പുചെയ്യുക"</string>
<string name="voice_hint" msgid="7476017460191291417">"വോയ്സ് അസിസ്റ്റിനായുള്ള ഐക്കണിൽ നിന്ന് സ്വൈപ്പുചെയ്യുക"</string>
<string name="camera_hint" msgid="4519495795000658637">"ക്യാമറ ഐക്കണിൽ നിന്ന് സ്വൈപ്പുചെയ്യുക"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. മ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക. ഉപയോഗസഹായി സേവനങ്ങൾ മ്യൂട്ടുചെയ്യപ്പെട്ടേക്കാം."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s വൈബ്രേറ്റിലേക്ക് സജ്ജമാക്കുന്നതിന് ടാപ്പുചെയ്യുക."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s മ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"റിംഗർ മോഡ് മാറ്റാൻ ടാപ്പ് ചെയ്യുക"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"മ്യൂട്ട് ചെയ്യുക"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"അൺമ്യൂട്ട് ചെയ്യുക"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"വൈബ്രേറ്റ് ചെയ്യുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index efb2711..93d66f4 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Цуцлах"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Хуваалцах"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Дэлгэцийн бичлэгийг цуцалсан"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Дэлгэцийн бичлэгийг хадгалсан. Харахын тулд товшино уу"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Дэлгэцийн бичлэгийг устгахад алдаа гарлаа"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Зөвшөөрөл авч чадсангүй"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Дэлгэцийн бичлэгийг эхлүүлэхэд алдаа гарлаа"</string>
@@ -446,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC-г ашиглахын тулд түгжээг тайлна уу"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Энэ төхөөрөмж танай байгууллагад харьяалагддаг"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Энэ төхөөрөмж <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>-д харьяалагддаг"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Энэ төхөөрөмжийг <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>-с нийлүүлдэг"</string>
<string name="phone_hint" msgid="6682125338461375925">"Утсыг гаргахын тулд дүрс тэмдгээс шудрах"</string>
<string name="voice_hint" msgid="7476017460191291417">"Дуут туслахыг нээхийн тулд дүрс тэмдгээс шудрах"</string>
<string name="camera_hint" msgid="4519495795000658637">"Камер нээхийн тулд дүрс тэмдгийг шудрах"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index fcff3df..093a03b 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"रद्द करा"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"शेअर करा"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"स्क्रीन रेकॉर्डिंग रद्द केले"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"स्क्रीन रेकॉर्डिंग सेव्ह केली, पाहण्यासाठी टॅप करा"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"स्क्रीन रेकॉर्डिंग हटवताना एरर आली"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"परवानग्या मिळवता आल्या नाहीत"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"स्क्रीन रेकॉर्डिंग सुरू करताना एरर आली"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"सूर्योदयापर्यंत"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> वाजता सुरू होते"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> पर्यंत"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"ब्राइटनेस कमी करा"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC अक्षम केले आहे"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC सक्षम केले आहे"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC वापरण्यासाठी स्क्रीन अनलॉक करा"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"हे डिव्हाइस तुमच्या संस्थेचे आहे"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"हे डिव्हाइस <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> चे आहे"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"हे डिव्हाइस <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> द्वारे पुरवले गेले आहे"</string>
<string name="phone_hint" msgid="6682125338461375925">"फोनसाठी चिन्हावरून स्वाइप करा"</string>
<string name="voice_hint" msgid="7476017460191291417">"व्हॉइस सहाय्यासाठी चिन्हावरून स्वाइप करा"</string>
<string name="camera_hint" msgid="4519495795000658637">"कॅमेर्यासाठी चिन्हावरून स्वाइप करा"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. म्यूट करण्यासाठी टॅप करा. प्रवेशक्षमता सेवा म्यूट केल्या जाऊ शकतात."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. व्हायब्रेट सेट करण्यासाठी टॅप करा."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. म्यूट करण्यासाठी टॅप करा."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"रिंगर मोड बदलण्यासाठी टॅप करा"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"म्यूट करा"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"म्यूट काढून टाका"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"व्हायब्रेट करा"</string>
@@ -1043,8 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"जोडा"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ने सुचवले आहे"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"नियंत्रणे अपडेट केली आहेत"</string>
- <!-- no translation found for controls_tile_locked (731547768182831938) -->
- <skip />
+ <string name="controls_tile_locked" msgid="731547768182831938">"डिव्हाइस लॉक आहे"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"पिनमध्ये अक्षरे किंवा चिन्हे आहेत"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ची पडताळणी करा"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"चुकीचा पिन"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index e723ec6..ca5c6cf 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Batal"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Kongsi"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Rakaman skrin dibatalkan"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Rakaman skrin disimpan, ketik untuk melihat"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Ralat semasa memadamkan rakaman skrin"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Gagal mendapatkan kebenaran"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Ralat semasa memulakan rakaman skrin"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hingga matahari trbt"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Dihidupkan pada <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Hingga <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Kurangkan kecerahan"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC dilumpuhkan"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC didayakan"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Buka kunci untuk menggunakan NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Peranti ini milik organisasi anda"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Peranti ini milik <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Peranti ini disediakan oleh <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Leret dari ikon untuk telefon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Leret dari ikon untuk bantuan suara"</string>
<string name="camera_hint" msgid="4519495795000658637">"Leret dari ikon untuk kamera"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Ketik untuk meredam. Perkhidmatan kebolehaksesan mungkin diredamkan."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Ketik untuk menetapkan pada getar."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Ketik untuk meredam."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Ketik untuk menukar mod pendering"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"redam"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"nyahredam"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"getar"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index c57a94c..cd4d590 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"မလုပ်တော့"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"မျှဝေရန်"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ဖန်သားပြင် ရိုက်ကူးမှု ပယ်ဖျက်လိုက်ပါပြီ"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"ဖန်သားပြင် ရိုက်ကူးမှု သိမ်းထားသည်၊ ကြည့်ရန် တို့ပါ"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ဖန်သားပြင် ရိုက်ကူးမှု ဖျက်ရာတွင် အမှားအယွင်းရှိနေသည်"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ခွင့်ပြုချက် မရယူနိုင်ပါ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ဖန်သားပြင် ရိုက်ကူးမှု စတင်ရာတွင် အမှားအယွင်းရှိနေသည်"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"နေထွက်ချိန် အထိ"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> တွင် ဖွင့်မည်"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> အထိ"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"တောက်ပမှုကို လျှော့ခြင်း"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ကို ပိတ်ထားသည်"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ကို ဖွင့်ထားသည်"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ကို အသုံးပြုရန် လော့ခ်ဖွင့်ပါ"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ဤစက်ကို သင့်အဖွဲ့အစည်းက ပိုင်ဆိုင်သည်"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"ဤစက်ကို <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> က ပိုင်ဆိုင်သည်"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"ဤစက်ပစ္စည်းကို <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> က ပံ့ပိုးထားသည်"</string>
<string name="phone_hint" msgid="6682125338461375925">"ဖုန်းအတွက် သင်္ကေတပုံအား ပွတ်ဆွဲပါ"</string>
<string name="voice_hint" msgid="7476017460191291417">"အသံအကူအညီအတွက် သင်္ကေတပုံအား ပွတ်ဆွဲပါ"</string>
<string name="camera_hint" msgid="4519495795000658637">"ကင်မရာအတွက် သင်္ကေတပုံအား ပွတ်ဆွဲပါ"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s။ အသံပိတ်ရန် တို့ပါ။ အများသုံးစွဲနိုင်မှု ဝန်ဆောင်မှုများကို အသံပိတ်ထားနိုင်ပါသည်။"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s။ တုန်ခါခြင်းသို့ သတ်မှတ်ရန်တို့ပါ။"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s။ အသံတိတ်ရန် တို့ပါ။"</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"ဖုန်းခေါ်သံမုဒ်သို့ ပြောင်းရန် တို့ပါ"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"အသံတိတ်ရန်"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"အသံဖွင့်ရန်"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"တုန်ခါမှု"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 997147d..52c289d 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Avbryt"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Del"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Skjermopptak er avbrutt"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Skjermopptaket er lagret. Trykk for å se det"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Feil ved sletting av skjermopptaket"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Kunne ikke få tillatelser"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Feil ved start av skjermopptaket"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Til soloppgang"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Slås på klokken <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Til <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reduser lysstyrken"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC er slått av"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC er slått på"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås opp for å bruke NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Denne enheten tilhører organisasjonen din"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Denne enheten tilhører <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Denne enheten leveres av <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Sveip ikonet for å åpne telefon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Sveip fra ikonet for å åpne talehjelp"</string>
<string name="camera_hint" msgid="4519495795000658637">"Sveip ikonet for å åpne kamera"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Trykk for å slå av lyden. Lyden kan bli slått av for tilgjengelighetstjenestene."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Trykk for å angi vibrasjon."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Trykk for å slå av lyden."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Trykk for å endre ringemodus"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"kutt lyden"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"slå på lyden"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrer"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index e03ee5b..63a8423 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"रद्द गर्नुहोस्"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"सेयर गर्नुहोस्"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"स्क्रिन रेकर्ड गर्ने कार्य रद्द गरियो"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"स्क्रिन रेकर्डिङ सुरक्षित गरियो, हेर्न ट्याप गर्नुहोस्"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"स्क्रिनको रेकर्डिङ मेट्ने क्रममा त्रुटि"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"अनुमति प्राप्त गर्न सकिएन"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"स्क्रिन रेकर्ड गर्न थाल्ने क्रममा त्रुटि भयो"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"सूर्योदयसम्म"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> मा सक्रिय"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> सम्म"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"चमक घटाइयोस्"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC लाई असक्षम पारिएको छ"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC लाई सक्षम पारिएको छ"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC प्रयोग गर्न स्क्रिन अनलक गर्नुहोस्"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"यो यन्त्र तपाईंको सङ्गठनको स्वामित्वमा छ"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"यो यन्त्र <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> को स्वामित्वमा छ"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ले यो यन्त्र उपलब्ध गराएको हो"</string>
<string name="phone_hint" msgid="6682125338461375925">"फोनको लागि आइकनबाट स्वाइप गर्नुहोस्"</string>
<string name="voice_hint" msgid="7476017460191291417">"आवाज सहायताका लागि आइकनबाट स्वाइप गर्नुहोस्"</string>
<string name="camera_hint" msgid="4519495795000658637">"क्यामेराको लागि आइकनबाट स्वाइप गर्नुहोस्"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। म्यूट गर्नाका लागि ट्याप गर्नुहोस्। पहुँच सम्बन्धी सेवाहरू म्यूट हुन सक्छन्।"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। कम्पन मोडमा सेट गर्न ट्याप गर्नुहोस्।"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। म्यूट गर्न ट्याप गर्नुहोस्।"</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"रिङ्गर मोड बदल्न ट्याप गर्नुहोस्"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"म्युट गर्नुहोस्"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"अनम्युट गर्नुहोस्"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"कम्पन गर्नुहोस्"</string>
@@ -1043,8 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"थप्नुहोस्"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ले सिफारिस गरेको"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"नियन्त्रण सुविधाहरू अद्यावधिक गरिए"</string>
- <!-- no translation found for controls_tile_locked (731547768182831938) -->
- <skip />
+ <string name="controls_tile_locked" msgid="731547768182831938">"यन्त्र लक गरिएको छ"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN मा अक्षर वा चिन्हहरू समाविष्ट हुन्छन्"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> पुष्टि गर्नुहोस्"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"PIN मिलेन"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 8ffc3f4..9da7ad7 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annuleren"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Delen"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Schermopname geannuleerd"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Schermopname opgeslagen, tik om te bekijken"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Fout bij verwijderen van schermopname"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Kan rechten niet ophalen"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Fout bij starten van schermopname"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Tot zonsopgang"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aan om <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Tot <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Helderheid verlagen"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is uitgeschakeld"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is ingeschakeld"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ontgrendel het apparaat om NFC te gebruiken"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Dit apparaat is eigendom van je organisatie"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Dit apparaat is eigendom van <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Dit apparaat wordt geleverd door <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Swipen voor telefoon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Swipen vanaf icoon voor spraakassistent"</string>
<string name="camera_hint" msgid="4519495795000658637">"Vegen voor camera"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tik om te dempen. Het geluid van toegankelijkheidsservices kan hierdoor uitgaan."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tik om in te stellen op trillen."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tik om geluid uit te zetten."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Tik om de beltoonmodus te wijzigen"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"geluid uit"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"geluid aanzetten"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"trillen"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index f03c31d..c847d15 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ବାତିଲ୍ କରନ୍ତୁ"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"ସେୟାର୍ କରନ୍ତୁ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ସ୍କ୍ରିନ୍ ରେକର୍ଡିଂ ବାତିଲ୍ କରିଦିଆଯାଇଛି"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"ସ୍କ୍ରିନ୍ ରେକର୍ଡିଂ ସେଭ୍ ହୋଇଛି, ଦେଖିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ସ୍କ୍ରିନ୍ ରେକର୍ଡିଂ ଡିଲିଟ୍ କରିବାରେ ତ୍ରୁଟି"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ଅନୁମତି ପାଇବାରେ ଅସଫଳ ହେଲା।"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ସ୍କ୍ରିନ୍ ରେକର୍ଡିଂ ଆରମ୍ଭ କରିବାରେ ତ୍ରୁଟି"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"ସକାଳ ପର୍ଯ୍ୟନ୍ତ"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>ରେ ଚାଲୁ ହେବ"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> ପର୍ଯ୍ୟନ୍ତ"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"ଉଜ୍ଜ୍ୱଳତା କମ୍ କରନ୍ତୁ"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ଅକ୍ଷମ କରାଯାଇଛି"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ସକ୍ଷମ କରାଯାଇଛି"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ବ୍ୟବହାର କରିବାକୁ ଅନଲକ୍ କରନ୍ତୁ"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ଏହି ଡିଭାଇସଟି ଆପଣଙ୍କ ସଂସ୍ଥାର ଅଟେ"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"ଏହି ଡିଭାଇସଟି <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>ର ଅଟେ"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"ଏହି ଡିଭାଇସ୍ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ଦ୍ୱାରା ପ୍ରଦାନ କରାଯାଇଛି"</string>
<string name="phone_hint" msgid="6682125338461375925">"ଫୋନ୍ ପାଇଁ ଆଇକନରୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
<string name="voice_hint" msgid="7476017460191291417">"ଭଏସ୍ ସହାୟକ ପାଇଁ ଆଇକନରୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
<string name="camera_hint" msgid="4519495795000658637">"କ୍ୟାମେରା ପାଇଁ ଆଇକନରୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। ମ୍ୟୁଟ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ। ଆକ୍ସେସିବିଲିଟୀ ସର୍ଭିସ୍ ମ୍ୟୁଟ୍ କରାଯାଇପାରେ।"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। ଭାଇବ୍ରେଟରେ ସେଟ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। ମ୍ୟୁଟ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"ରିଙ୍ଗର୍ ମୋଡ୍ ବଦଳାଇବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ମ୍ୟୁଟ୍"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ଅନ୍-ମ୍ୟୁଟ୍ କରନ୍ତୁ"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ଭାଇବ୍ରେଟ୍"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 459b163..53a71a6 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ਰੱਦ ਕਰੋ"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"ਸਾਂਝਾ ਕਰੋ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ਸਕ੍ਰੀਨ ਦੀ ਰਿਕਾਰਡਿੰਗ ਰੱਦ ਕੀਤੀ ਗਈ"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਰੱਖਿਅਤ ਕੀਤੀ ਗਈ, ਦੇਖਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਨੂੰ ਮਿਟਾਉਣ ਦੌਰਾਨ ਗੜਬੜ ਹੋਈ"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ਇਜਾਜ਼ਤਾਂ ਪ੍ਰਾਪਤ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਵੇਲੇ ਗੜਬੜ ਹੋਈ"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"ਸੂਰਜ ਚੜ੍ਹਨ ਤੱਕ"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> ਵਜੇ ਚਾਲੂ"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> ਵਜੇ ਤੱਕ"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"ਚਮਕ ਘਟਾਓ"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ਨੂੰ ਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ਵਰਤਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ਇਹ ਡੀਵਾਈਸ ਤੁਹਾਡੀ ਸੰਸਥਾ ਨਾਲ ਸੰਬੰਧਿਤ ਹੈ"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"ਇਹ ਡੀਵਾਈਸ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ਨਾਲ ਸੰਬੰਧਿਤ ਹੈ"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"ਇਹ ਡੀਵਾਈਸ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ਵੱਲੋਂ ਮੁਹੱਈਆ ਕੀਤਾ ਗਿਆ ਹੈ"</string>
<string name="phone_hint" msgid="6682125338461375925">"ਫ਼ੋਨ ਲਈ ਪ੍ਰਤੀਕ ਤੋਂ ਸਵਾਈਪ ਕਰੋ"</string>
<string name="voice_hint" msgid="7476017460191291417">"ਅਵਾਜ਼ੀ ਸਹਾਇਕ ਲਈ ਪ੍ਰਤੀਕ ਤੋਂ ਸਵਾਈਪ ਕਰੋ"</string>
<string name="camera_hint" msgid="4519495795000658637">"ਕੈਮਰੇ ਲਈ ਪ੍ਰਤੀਕ ਤੋਂ ਸਵਾਈਪ ਕਰੋ"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s। ਮਿਊਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ। ਪਹੁੰਚਯੋਗਤਾ ਸੇਵਾਵਾਂ ਮਿਊਟ ਹੋ ਸਕਦੀਆਂ ਹਨ।"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s। ਥਰਥਰਾਹਟ \'ਤੇ ਸੈੱਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s। ਮਿਊਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"ਰਿੰਗਰ ਮੋਡ ਨੂੰ ਬਦਲਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ਮਿਊਟ ਕਰੋ"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ਅਣਮਿਊਟ ਕਰੋ"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ਥਰਥਰਾਹਟ"</string>
@@ -1043,8 +1043,7 @@
<string name="controls_dialog_ok" msgid="2770230012857881822">"ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"<xliff:g id="APP">%s</xliff:g> ਵੱਲੋਂ ਸੁਝਾਇਆ ਗਿਆ"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"ਕੰਟਰੋਲ ਅੱਪਡੇਟ ਕੀਤੇ ਗਏ"</string>
- <!-- no translation found for controls_tile_locked (731547768182831938) -->
- <skip />
+ <string name="controls_tile_locked" msgid="731547768182831938">"ਡੀਵਾਈਸ ਲਾਕ ਹੈ"</string>
<string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"ਪਿੰਨ ਵਿੱਚ ਅੱਖਰ ਜਾਂ ਚਿੰਨ੍ਹ ਸ਼ਾਮਲ ਹਨ"</string>
<string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ"</string>
<string name="controls_pin_wrong" msgid="6162694056042164211">"ਗਲਤ ਪਿੰਨ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index e16b5ec..f8c275d 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Anuluj"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Udostępnij"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Anulowano nagrywanie zawartości ekranu"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Zapisano nagranie zawartości ekranu – kliknij, by je obejrzeć"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Błąd podczas usuwania nagrania zawartości ekranu"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nie udało się uzyskać uprawnień"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Błąd podczas rozpoczynania rejestracji zawartości ekranu"</string>
@@ -416,8 +419,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do wschodu słońca"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Włącz o <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Zmniejsz jasność"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"Komunikacja NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Komunikacja NFC jest wyłączona"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Komunikacja NFC jest włączona"</string>
@@ -451,8 +453,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Odblokuj, by użyć komunikacji NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"To urządzenie należy do Twojej organizacji"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Właściciel tego urządzenia: <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"To urządzenie dostarcza organizacja <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Aby włączyć telefon, przesuń palcem od ikony"</string>
<string name="voice_hint" msgid="7476017460191291417">"Aby uzyskać pomoc głosową, przesuń palcem od ikony"</string>
<string name="camera_hint" msgid="4519495795000658637">"Przesuń palcem od ikony, by włączyć aparat"</string>
@@ -634,8 +635,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Kliknij, by wyciszyć. Ułatwienia dostępu mogą być wyciszone."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Kliknij, by włączyć wibracje."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Kliknij, by wyciszyć."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Kliknij, aby zmienić tryb dzwonka"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"wycisz"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"wyłącz wyciszenie"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"włącz wibracje"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index efe0f06..ab53aa0 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Compartilhar"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Gravação de tela cancelada"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Gravação de tela salva, toque para ver"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Erro ao excluir a gravação de tela"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Não foi possível acessar as permissões"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Erro ao iniciar a gravação de tela"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Até o nascer do sol"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ativar: <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Até: <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reduzir brilho"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"A NFC está desativada"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"A NFC está ativada"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueie para usar a NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua organização"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertence à organização <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Este dispositivo é fornecido pela <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Deslize a partir do ícone do telefone"</string>
<string name="voice_hint" msgid="7476017460191291417">"Deslize a partir do ícone de assistência de voz"</string>
<string name="camera_hint" msgid="4519495795000658637">"Deslize a partir do ícone da câmera"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para silenciar. É possível que os serviços de acessibilidade sejam silenciados."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toque para configurar para vibrar."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toque para silenciar."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Toque para mudar o modo da campainha"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desativar o som"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ativar o som"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 3a82feb..884b210 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Partilhar"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Gravação de ecrã cancelada."</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Gravação de ecrã guardada. Toque para ver."</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Erro ao eliminar a gravação de ecrã."</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Falha ao obter as autorizações."</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Ocorreu um erro ao iniciar a gravação do ecrã."</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Até ao amanhecer"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ativado à(s) <xliff:g id="TIME">%s</xliff:g>."</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Até à(s) <xliff:g id="TIME">%s</xliff:g>."</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reduzir o brilho"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"O NFC está desativado"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"O NFC está ativado"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquear para utilizar o NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua entidade."</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertence à entidade <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>."</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Este dispositivo foi fornecido por <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>."</string>
<string name="phone_hint" msgid="6682125338461375925">"Deslize rapid. a partir do ícone para aceder ao telemóvel"</string>
<string name="voice_hint" msgid="7476017460191291417">"Deslize rapid. a partir do ícone para aceder ao assist. voz"</string>
<string name="camera_hint" msgid="4519495795000658637">"Deslize rapidamente a partir do ícone para aceder à câmara"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para desativar o som. Os serviços de acessibilidade podem ser silenciados."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toque para ativar a vibração."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toque para desativar o som."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Toque para alterar o modo de campainha"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desativar som"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"reativar som"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index efe0f06..ab53aa0 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Compartilhar"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Gravação de tela cancelada"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Gravação de tela salva, toque para ver"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Erro ao excluir a gravação de tela"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Não foi possível acessar as permissões"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Erro ao iniciar a gravação de tela"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Até o nascer do sol"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ativar: <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Até: <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reduzir brilho"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"A NFC está desativada"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"A NFC está ativada"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueie para usar a NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua organização"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Este dispositivo pertence à organização <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Este dispositivo é fornecido pela <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Deslize a partir do ícone do telefone"</string>
<string name="voice_hint" msgid="7476017460191291417">"Deslize a partir do ícone de assistência de voz"</string>
<string name="camera_hint" msgid="4519495795000658637">"Deslize a partir do ícone da câmera"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Toque para silenciar. É possível que os serviços de acessibilidade sejam silenciados."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Toque para configurar para vibrar."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Toque para silenciar."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Toque para mudar o modo da campainha"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desativar o som"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ativar o som"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 18093b4..6a928da 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Anulați"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Trimiteți"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Înregistrarea ecranului a fost anulată"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Înregistrarea ecranului a fost salvată. Atingeți pentru vizualizare"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Eroare la ștergerea înregistrării ecranului"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nu s-au obținut permisiunile"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Eroare la începerea înregistrării ecranului"</string>
@@ -414,8 +417,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Până la răsărit"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Activată la <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Până la <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Reduceți luminozitatea"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Serviciul NFC este dezactivat"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Serviciul NFC este activat"</string>
@@ -449,8 +451,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Deblocați pentru a folosi NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Dispozitivul aparține organizației dvs."</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Acest dispozitiv aparține organizației <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Acest dispozitiv este oferit de <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Glisați dinspre telefon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Glisați dinspre pictogramă pentru asistentul vocal"</string>
<string name="camera_hint" msgid="4519495795000658637">"Glisați pentru a fotografia"</string>
@@ -631,8 +632,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Atingeți pentru a dezactiva sunetul. Sunetul se poate dezactiva pentru serviciile de accesibilitate."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Atingeți pentru a seta pe vibrații."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Atingeți pentru a dezactiva sunetul."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Atingeți pentru a schimba modul soneriei"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"dezactivați sunetul"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"activați sunetul"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrații"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index a9f7c02..f064e4f 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Отмена"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Поделиться"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Запись видео с экрана отменена"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Запись видео с экрана сохранена. Чтобы открыть ее, нажмите на уведомление."</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Не удалось удалить запись видео с экрана"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Не удалось получить необходимые разрешения"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Не удалось начать запись видео с экрана."</string>
@@ -416,8 +419,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До рассвета"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Включить в <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"До <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Уменьшение яркости"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"Модуль NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Модуль NFC отключен"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Модуль NFC включен"</string>
@@ -451,8 +453,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Чтобы использовать NFC, разблокируйте устройство."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Это устройство принадлежит вашей организации"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Этим устройством владеет организация \"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>\""</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Устройство предоставлено компанией <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Телефон: проведите от значка"</string>
<string name="voice_hint" msgid="7476017460191291417">"Аудиоподсказки: проведите от значка"</string>
<string name="camera_hint" msgid="4519495795000658637">"Камера: проведите от значка"</string>
@@ -634,8 +635,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Нажмите, чтобы выключить звук. Специальные возможности могут прекратить работу."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Нажмите, чтобы включить вибрацию."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Нажмите, чтобы выключить звук."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Нажмите, чтобы изменить режим звонка."</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"отключить звук"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"включить звук"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"включить вибрацию"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 5134e04..5a1f599 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"අවලංගු කරන්න"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"බෙදා ගන්න"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"තිර පටිගත කිරීම අවලංගු කරන ලදී"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"තිර පටිගත කිරීම සුරකින ලදී, බැලීමට තට්ටු කරන්න"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"තිර පටිගත කිරීම මැකීමේ දෝෂයකි"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"අවසර ලබා ගැනීමට අසමත් විය"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"තිර පටිගත කිරීම ආරම්භ කිරීමේ දෝෂයකි"</string>
@@ -446,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC භාවිත කිරීමට අගුලු හරින්න"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"මෙම උපාංගය ඔබේ සංවිධානයට අයිතිය"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"මෙම උපාංගය <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> සංවිධානයට අයිතිය"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"මෙම උපාංගය <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> මගින් සැපයේ."</string>
<string name="phone_hint" msgid="6682125338461375925">"දුරකථනය සඳහා නිරූපකය වෙතින් ස්වයිප් කරන්න"</string>
<string name="voice_hint" msgid="7476017460191291417">"හඬ සහාය සඳහා නිරූපකය වෙතින් ස්වයිප් කරන්න"</string>
<string name="camera_hint" msgid="4519495795000658637">"කැමරාව සඳහා නිරූපකය වෙතින් ස්වයිප් කරන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index d514b66..eba75e3 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Zrušiť"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Zdieľať"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Záznam obrazovky bol zrušený"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Záznam obrazovky bol uložený, zobrazíte ho klepnutím"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Pri odstraňovaní záznamu obrazovky sa vyskytla chyba"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Nepodarilo sa získať povolenia"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Pri spustení nahrávania obrazovky sa vyskytla chyba"</string>
@@ -416,8 +419,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do východu slnka"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Zapne sa o <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Zníženie jasu"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je deaktivované"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je aktivované"</string>
@@ -451,8 +453,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ak chcete použiť NFC, odomknite"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Toto zariadenie patrí vašej organizácii"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Toto zariadení patrí organizácii <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Toto zariadenie poskytla organizácia <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Telefón otvoríte prejdením prstom od ikony"</string>
<string name="voice_hint" msgid="7476017460191291417">"Hlasového asistenta otvoríte prejdením prstom od ikony"</string>
<string name="camera_hint" msgid="4519495795000658637">"Fotoaparát otvoríte prejdením prstom od ikony"</string>
@@ -634,8 +635,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Klepnutím vypnite zvuk. Služby dostupnosti je možné stlmiť."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Klepnutím nastavíte vibrovanie."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Klepnutím vypnete zvuk."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Režim zvonenia zmeníte klepnutím"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vypnite zvuk"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"zapnite zvuk"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"zapnite vibrovanie"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index b7b2dd0..7bf496a 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Prekliči"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Deli"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Snemanje zaslona je preklicano"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Videoposnetek zaslona je shranjen, dotaknite se za ogled"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Napaka pri brisanju videoposnetka zaslona"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Dovoljenj ni bilo mogoče pridobiti"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Napaka pri začenjanju snemanja zaslona"</string>
@@ -416,8 +419,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do sončnega vzhoda"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Vklop ob <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Do <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Zmanjšanje svetlosti"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Tehnologija NFC je onemogočena"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Tehnologija NFC je omogočena"</string>
@@ -451,8 +453,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Odklenite napravo, če želite uporabljati NFC."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ta naprava pripada vaši organizaciji"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Ta naprava pripada organizaciji <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"To napravo zagotavlja <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>."</string>
<string name="phone_hint" msgid="6682125338461375925">"Povlecite z ikone za telefon"</string>
<string name="voice_hint" msgid="7476017460191291417">"Povlecite z ikone za glasovnega pomočnika"</string>
<string name="camera_hint" msgid="4519495795000658637">"Povlecite z ikone za fotoaparat"</string>
@@ -634,8 +635,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Dotaknite se, če želite izklopiti zvok. V storitvah za ljudi s posebnimi potrebami bo morda izklopljen zvok."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Dotaknite se, če želite nastaviti vibriranje."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Dotaknite se, če želite izklopiti zvok."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Dotaknite se, če želite spremeniti način zvonjenja."</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"izklop zvoka"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"vklop zvoka"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibriranje"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 9f4c1e1..ac22fea 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Anulo"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Ndaj"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Regjistrimi i ekranit u anulua"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Regjistrimi i ekranit u ruajt, trokit për ta parë"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Gabim gjatë fshirjes së regjistrimit të ekranit"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Marrja e lejeve dështoi"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Gabim gjatë nisjes së regjistrimit të ekranit"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Deri në lindje të diellit"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aktiv në <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Deri në <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Redukto ndriçimin"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC është çaktivizuar"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC është aktivizuar"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Shkyçe për të përdorur NFC-në"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Kjo pajisje i përket organizatës sate"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Kjo pajisje i përket <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Kjo pajisje ofrohet nga <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Rrëshqit për të hapur telefonin"</string>
<string name="voice_hint" msgid="7476017460191291417">"Rrëshqit për të hapur ndihmën zanore"</string>
<string name="camera_hint" msgid="4519495795000658637">"Rrëshqit për të hapur kamerën"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Trokit për të çaktivizuar. Shërbimet e qasshmërisë mund të çaktivizohen."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Trokit për ta vendosur në dridhje."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Trokit për ta çaktivizuar."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Trokit për të ndryshuar modalitetin e ziles"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"çaktivizo audion"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"aktivizo audion"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"lësho dridhje"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 5c2fbac..bcfcf30 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Откажи"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Дели"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Снимање екрана је отказано"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Снимак екрана је сачуван, додирните да бисте прегледали"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Дошло је до проблема при брисању снимка екрана"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Преузимање дозвола није успело"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Грешка при покретању снимања екрана"</string>
@@ -414,8 +417,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До изласка сунца"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Укључује се у <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"До <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Смањите осветљеност"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC је онемогућен"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC је омогућен"</string>
@@ -449,8 +451,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Откључајте да бисте користили NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Овај уређај припада организацији"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Овај уређај припада организацији <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Овај уређај пружа <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Превуците од иконе за телефон"</string>
<string name="voice_hint" msgid="7476017460191291417">"Превуците од иконе за гласовну помоћ"</string>
<string name="camera_hint" msgid="4519495795000658637">"Превуците од иконе за камеру"</string>
@@ -631,8 +632,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Додирните да бисте искључили звук. Звук услуга приступачности ће можда бити искључен."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Додирните да бисте подесили на вибрацију."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Додирните да бисте искључили звук."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Додирните да бисте променили режим звона"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"искључите звук"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"укључите звук"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вибрација"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 5ca41ed..f1f9f20 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Avbryt"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Dela"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Skärminspelningen har avbrutits"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Skärminspelningen har sparats, tryck här om du vill titta på den"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Det gick inte att radera skärminspelningen"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Behörighet saknas"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Det gick inte att starta skärminspelningen"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Till soluppgången"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aktivera kl. <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Till <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Minska ljusstyrkan"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC är inaktiverat"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC är aktiverat"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås upp om du vill använda NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Den här enheten tillhör organisationen"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Den här enheten tillhör <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Den här enheten tillhandahålls av <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Svep från ikonen och öppna telefonen"</string>
<string name="voice_hint" msgid="7476017460191291417">"Svep från ikonen och öppna röstassistenten"</string>
<string name="camera_hint" msgid="4519495795000658637">"Svep från ikonen och öppna kameran"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Tryck här om du vill stänga av ljudet. Tillgänglighetstjänsterna kanske inaktiveras."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Tryck här om du vill aktivera vibrationsläget."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Tryck här om du vill stänga av ljudet."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Tryck för att ändra ringsignalens läge"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"stänga av ljudet"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"slå på ljudet"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibration"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 768e10c..5a4088e 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Ghairi"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Shiriki"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Imeghairi mchakato wa kurekodi skrini"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Imehifadhi rekodi ya skrini, gusa ili uangalie"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Hitilafu imetokea wakati wa kufuta rekodi ya skrini"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Imeshindwa kupata ruhusa"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Hitilafu imetokea wakati wa kuanza kurekodi skrini"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hadi macheo"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Itawashwa saa <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Hadi saa <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Punguza ung\'aavu"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC imezimwa"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC imewashwa"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Fungua ili utumie NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Kifaa hiki kinamilikiwa na shirika lako"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Kifaa hiki kinamilikiwa na <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Kifaa hiki kinatolewa na <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Telezesha kidole kutoka kwa aikoni ili ufikie simu"</string>
<string name="voice_hint" msgid="7476017460191291417">"Telezesha kidole kutoka aikoni ili upate mapendekezo ya sauti"</string>
<string name="camera_hint" msgid="4519495795000658637">"Telezesha kidole kutoka aikoni ili ufikie kamera"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Gusa ili ukomeshe. Huenda ikakomesha huduma za zana za walio na matatizo ya kuona au kusikia."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Gusa ili uweke mtetemo."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Gusa ili usitishe."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Gusa ili ubadilishe hali ya programu inayotoa milio ya simu"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"zima sauti"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"washa sauti"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"tetema"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 2ea5a6a..5750119 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ரத்துசெய்"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"பகிர்"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"திரை ரெக்கார்டிங் ரத்துசெய்யப்பட்டது"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"திரை ரெக்கார்டிங் சேமிக்கப்பட்டது, பார்க்கத் தட்டவும்"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"திரை ரெக்கார்டிங்கை நீக்குவதில் பிழை"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"அனுமதிகளைப் பெற இயலவில்லை"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"ஸ்கிரீன் ரெக்கார்டிங்கைத் தொடங்குவதில் பிழை"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"காலை வரை"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g>க்கு ஆன் செய்"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> வரை"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"ஒளிர்வைக் குறைத்தல்"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC முடக்கப்பட்டது"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC இயக்கப்பட்டது"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCயைப் பயன்படுத்த அன்லாக் செய்யவும்"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"இந்த சாதனம் உங்கள் நிறுவனத்துக்கு சொந்தமானது"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"இந்த சாதனம் <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> நிறுவனத்துக்கு சொந்தமானது"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"இந்தச் சாதனம் <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> நிறுவனத்தால் வழங்கப்பட்டது"</string>
<string name="phone_hint" msgid="6682125338461375925">"ஃபோனிற்கு ஐகானிலிருந்து ஸ்வைப் செய்யவும்"</string>
<string name="voice_hint" msgid="7476017460191291417">"குரல் உதவிக்கு ஐகானிலிருந்து ஸ்வைப் செய்யவும்"</string>
<string name="camera_hint" msgid="4519495795000658637">"கேமராவிற்கு ஐகானிலிருந்து ஸ்வைப் செய்யவும்"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. ஒலியடக்க, தட்டவும். அணுகல்தன்மை சேவைகள் ஒலியடக்கப்படக்கூடும்."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. அதிர்விற்கு அமைக்க, தட்டவும்."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. ஒலியடக்க, தட்டவும்."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"ரிங்கர் பயன்முறையை மாற்ற தட்டவும்"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ஒலியடக்கும்"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ஒலி இயக்கும்"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"அதிர்வுறும்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 03af2a0..f39fa69 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"రద్దు చేయి"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"షేర్ చేయి"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"స్క్రీన్ రికార్డ్ రద్దు చేయబడింది"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"స్క్రీన్ రికార్డింగ్ సేవ్ చేయబడింది, చూడటం కోసం నొక్కండి"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"స్క్రీన్ రికార్డింగ్ని తొలగిస్తున్నప్పుడు ఎర్రర్ ఏర్పడింది"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"అనుమతులను పొందడం విఫలమైంది"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"స్క్రీన్ రికార్డింగ్ ప్రారంభించడంలో ఎర్రర్ ఏర్పడింది"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"సూర్యోదయం వరకు"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> కు ఆన్ అవుతుంది"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> వరకు"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"ప్రకాశాన్ని తగ్గించండి"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC నిలిపివేయబడింది"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ప్రారంభించబడింది"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFCని ఉపయోగించడానికి అన్లాక్ చేయండి"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"ఈ పరికరం మీ సంస్థకు చెందినది"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"ఈ పరికరం <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>కు చెందినది"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"ఈ పరికరం <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ద్వారా అందించబడింది"</string>
<string name="phone_hint" msgid="6682125338461375925">"ఫోన్ కోసం చిహ్నాన్ని స్వైప్ చేయండి"</string>
<string name="voice_hint" msgid="7476017460191291417">"వాయిస్ అసిస్టెంట్ చిహ్నం నుండి స్వైప్"</string>
<string name="camera_hint" msgid="4519495795000658637">"కెమెరా కోసం చిహ్నాన్ని స్వైప్ చేయండి"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. మ్యూట్ చేయడానికి నొక్కండి. యాక్సెస్ సామర్థ్య సేవలు మ్యూట్ చేయబడవచ్చు."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. వైబ్రేట్ అయ్యేలా సెట్ చేయడం కోసం నొక్కండి."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. మ్యూట్ చేయడానికి నొక్కండి."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"రింగర్ మోడ్ను మార్చడానికి ట్యాప్ చేయండి"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"మ్యూట్ చేయి"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"అన్మ్యూట్ చేయి"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"వైబ్రేట్"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 5e37ed8..a726dda 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"ยกเลิก"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"แชร์"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"ยกเลิกการบันทึกหน้าจอแล้ว"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"บันทึกการบันทึกหน้าจอแล้ว แตะเพื่อดู"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"เกิดข้อผิดพลาดในการลบการบันทึกหน้าจอ"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"ขอสิทธิ์ไม่สำเร็จ"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"เกิดข้อผิดพลาดขณะเริ่มบันทึกหน้าจอ"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"จนพระอาทิตย์ขึ้น"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"เปิดเวลา <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"จนถึง <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"ลดความสว่าง"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ถูกปิดใช้งาน"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"เปิดใช้งาน NFC แล้ว"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"ปลดล็อกเพื่อใช้ NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"องค์กรของคุณเป็นเจ้าของอุปกรณ์นี้"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g> เป็นเจ้าของอุปกรณ์นี้"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"อุปกรณ์นี้ให้บริการโดย <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"เลื่อนไอคอนโทรศัพท์"</string>
<string name="voice_hint" msgid="7476017460191291417">"เลื่อนไอคอนตัวช่วยเสียง"</string>
<string name="camera_hint" msgid="4519495795000658637">"เลื่อนไอคอนกล้อง"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s แตะเพื่อปิดเสียง อาจมีการปิดเสียงบริการการเข้าถึง"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s แตะเพื่อตั้งค่าให้สั่น"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s แตะเพื่อปิดเสียง"</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"แตะเพื่อเปลี่ยนโหมดเสียงเรียกเข้า"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ปิดเสียง"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"เปิดเสียง"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"สั่น"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 18313e4..92d5a66 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Kanselahin"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Ibahagi"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Kinansela ang pag-record ng screen"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Na-save ang pag-record ng screen, i-tap para tingnan"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Error sa pag-delete sa pag-record ng screen"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Hindi nakuha ang mga pahintulot"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Nagkaroon ng error sa pagsisimula ng pag-record ng screen"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hanggang sunrise"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ma-o-on nang <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Hanggang <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Bawasan ang liwanag"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Naka-disable ang NFC"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Naka-enable ang NFC"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"I-unlock para magamit ang NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Pagmamay-ari ng iyong organisasyon ang device na ito"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Pagmamay-ari ng <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ang device na ito"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Nagmula sa <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> ang device na ito"</string>
<string name="phone_hint" msgid="6682125338461375925">"Mag-swipe mula sa icon para sa telepono"</string>
<string name="voice_hint" msgid="7476017460191291417">"Mag-swipe mula sa icon para sa voice assist"</string>
<string name="camera_hint" msgid="4519495795000658637">"Mag-swipe mula sa icon para sa camera"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. I-tap upang i-mute. Maaaring i-mute ang mga serbisyo sa Accessibility."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. I-tap upang itakda na mag-vibrate."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. I-tap upang i-mute."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"I-tap para baguhin ang ringer mode"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"i-mute"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"i-unmute"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"i-vibrate"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 6b3015c..c708b5a 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"İptal"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Paylaş"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekran kaydı iptal edildi"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Ekran kaydı tamamlandı, görüntülemek için dokunun"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Ekran kaydı silinirken hata oluştu"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"İzinler alınamadı"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Ekran kaydı başlatılırken hata oluştu"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Sabaha kadar"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Açılacağı saat: <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Şu saate kadar: <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Parlaklığı azalt"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC devre dışı"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC etkin"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC\'yi kullanmak için kilidi açın"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Bu cihaz, kuruluşunuza ait"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Bu cihaz <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> adlı kuruluşa ait"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Bu cihaz, <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> tarafından sağlanmaktadır"</string>
<string name="phone_hint" msgid="6682125338461375925">"Telefon için, simgeden hızlıca kaydırın"</string>
<string name="voice_hint" msgid="7476017460191291417">"Sesli yardım için, simgeden hızlıca kaydırın"</string>
<string name="camera_hint" msgid="4519495795000658637">"Kamera için, simgeden hızlıca kaydırın"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Sesi kapatmak için dokunun. Erişilebilirlik hizmetlerinin sesi kapatılabilir."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Titreşime ayarlamak için dokunun."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Sesi kapatmak için dokunun."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Telefon zili modunu değiştirmek için dokunun"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"sesi kapat"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"sesi aç"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"titreşim"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 12b4830..e51122b 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Скасувати"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Поділитися"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Запис екрана скасовано"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Запис екрана збережено. Натисніть, щоб переглянути"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Не вдалося видалити запис екрана"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Не вдалось отримати дозволи"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Не вдалося почати запис екрана"</string>
@@ -416,8 +419,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До сходу сонця"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Вмикається о <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"До <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Зменшення яскравості"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC вимкнено"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ввімкнено"</string>
@@ -451,8 +453,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Розблокуйте екран, щоб скористатись NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Цей пристрій належить вашій організації"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Цей пристрій належить організації \"<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>\""</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Цей пристрій надала організація <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Телефон: проведіть пальцем від значка"</string>
<string name="voice_hint" msgid="7476017460191291417">"Голосові підказки: проведіть пальцем від значка"</string>
<string name="camera_hint" msgid="4519495795000658637">"Камера: проведіть пальцем від значка"</string>
@@ -634,8 +635,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Торкніться, щоб вимкнути звук. Спеціальні можливості може бути вимкнено."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Торкніться, щоб налаштувати вібросигнал."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Торкніться, щоб вимкнути звук."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Торкніться, щоб змінити режим дзвінка"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"вимкнути звук"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"увімкнути звук"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"увімкнути вібросигнал"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 3668f7e..d2e37e7 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"منسوخ کریں"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"اشتراک کریں"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"اسکرین ریکارڈنگ منسوخ ہو گئی"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"اسکرین ریکارڈنگ محفوظ ہو گئی، دیکھنے کیلئے تھپتھپائیں"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"اسکرین ریکارڈنگ کو حذف کرنے میں خرابی"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"اجازتیں حاصل کرنے میں ناکامی"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"اسکرین ریکارڈنگ شروع کرنے میں خرابی"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"طلوع آفتاب تک"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"آن ہوگی بوقت <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> تک"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"چمک کم کریں"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC غیر فعال ہے"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC فعال ہے"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC استعمال کرنے کیلئے غیر مقفل کریں"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"یہ آلہ آپ کی تنظیم کا ہے"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"یہ آلہ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> کا ہے"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"یہ آلہ <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> نے فراہم کیا ہے"</string>
<string name="phone_hint" msgid="6682125338461375925">"فون کیلئے آئیکن سے سوائپ کریں"</string>
<string name="voice_hint" msgid="7476017460191291417">"صوتی معاون کیلئے آئیکن سے سوائپ کریں"</string>
<string name="camera_hint" msgid="4519495795000658637">"کیمرہ کیلئے آئیکن سے سوائپ کریں"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s۔ خاموش کرنے کیلئے تھپتھپائیں۔ ایکسیسبیلٹی سروسز شاید خاموش ہوں۔"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s۔ ارتعاش پر سیٹ کرنے کیلئے تھپتھپائیں۔"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s۔ خاموش کرنے کیلئے تھپتھپائیں۔"</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"رنگر وضع تبدیل کرنے کیلئے تھپتھپائیں"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"خاموش کریں"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"غیر خاموش کریں"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"وائبریٹ"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 0732c7f..4615f4a 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Bekor qilish"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Ulashish"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekrandan yozib olish bekor qilindi"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Ekrandan yozib olingan video saqlandi. Uni ochish uchun bildirishnomani bosing."</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Ekrandan yozib olingan vi olib tashlanmadi"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Zarur ruxsatlar olinmadi"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Ekranni yozib olish boshlanmadi"</string>
@@ -446,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ishlatish uchun qurilma qulfini oching"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Bu qurilma tashkilotingizga tegishli"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Bu qurilma <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> tashkilotiga tegishli"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Bu qurilma <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> tomonidan berilgan."</string>
<string name="phone_hint" msgid="6682125338461375925">"Telefonni ochish uchun suring"</string>
<string name="voice_hint" msgid="7476017460191291417">"Ovozli yordam: belgidan boshlab suring"</string>
<string name="camera_hint" msgid="4519495795000658637">"Kamerani ochish uchun suring"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index cc89303..ee97bc5 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Hủy"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Chia sẻ"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Đã hủy bản ghi màn hình"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Đã lưu bản ghi màn hình, nhấn để xem"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Lỗi khi xóa bản ghi màn hình"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Không được cấp đủ quyền"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Lỗi khi bắt đầu ghi màn hình"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Cho đến khi trời sáng"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Bật vào lúc <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Cho đến <xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Giảm độ sáng"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC đã được tắt"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC đã được bật"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Mở khóa để sử dụng NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Thiết bị này thuộc về tổ chức của bạn"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Thiết bị này thuộc về <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Thiết bị này do <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> cung cấp"</string>
<string name="phone_hint" msgid="6682125338461375925">"Vuốt từ biểu tượng để mở điện thoại"</string>
<string name="voice_hint" msgid="7476017460191291417">"Vuốt từ biểu tượng để mở trợ lý thoại"</string>
<string name="camera_hint" msgid="4519495795000658637">"Vuốt từ biểu tượng để mở máy ảnh"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Nhấn để tắt tiếng. Bạn có thể tắt tiếng dịch vụ trợ năng."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Nhấn để đặt chế độ rung."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Nhấn để tắt tiếng."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Nhấn để thay đổi chế độ chuông"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"tắt tiếng"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"bật tiếng"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"rung"</string>
@@ -844,7 +844,7 @@
<string name="right_nav_bar_button_type" msgid="4472566498647364715">"Loại nút bổ sung bên phải"</string>
<string name="nav_bar_default" msgid="8386559913240761526">"(mặc định)"</string>
<string-array name="nav_bar_buttons">
- <item msgid="2681220472659720036">"Khay nhớ tạm"</item>
+ <item msgid="2681220472659720036">"Bảng nhớ tạm"</item>
<item msgid="4795049793625565683">"Mã phím"</item>
<item msgid="80697951177515644">"Xác nhận xoay, trình chuyển đổi bàn phím"</item>
<item msgid="7626977989589303588">"Không có"</item>
@@ -859,7 +859,7 @@
<string name="save" msgid="3392754183673848006">"Lưu"</string>
<string name="reset" msgid="8715144064608810383">"Đặt lại"</string>
<string name="adjust_button_width" msgid="8313444823666482197">"Điều chỉnh chiều rộng nút"</string>
- <string name="clipboard" msgid="8517342737534284617">"Khay nhớ tạm"</string>
+ <string name="clipboard" msgid="8517342737534284617">"Bảng nhớ tạm"</string>
<string name="accessibility_key" msgid="3471162841552818281">"Nút điều hướng tùy chỉnh"</string>
<string name="left_keycode" msgid="8211040899126637342">"Mã phím bên trái"</string>
<string name="right_keycode" msgid="2480715509844798438">"Mã phím bên phải"</string>
@@ -1080,7 +1080,7 @@
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Không thể kết nối. Hãy thử lại."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Ghép nối thiết bị mới"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Số bản dựng"</string>
- <string name="build_number_copy_toast" msgid="877720921605503046">"Đã sao chép số bản dựng vào khay nhớ tạm."</string>
+ <string name="build_number_copy_toast" msgid="877720921605503046">"Đã sao chép số bản dựng vào bảng nhớ tạm."</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Đã xảy ra vấn đề khi đọc dung lượng pin của bạn"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Nhấn để biết thêm thông tin"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 92f9e67..bee359d 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"取消"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"分享"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"已取消录制屏幕"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"屏幕录制内容已保存,点按即可查看"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"删除屏幕录制内容时出错"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"无法获取权限"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"启动屏幕录制时出错"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"在日出时关闭"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"在<xliff:g id="TIME">%s</xliff:g> 开启"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"直到<xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"调低亮度"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC 已停用"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC 已启用"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"需要解锁才能使用 NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"此设备归贵单位所有"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"此设备归<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>所有"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"这是<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>提供的设备"</string>
<string name="phone_hint" msgid="6682125338461375925">"滑动图标即可拨打电话"</string>
<string name="voice_hint" msgid="7476017460191291417">"滑动图标即可打开语音助理"</string>
<string name="camera_hint" msgid="4519495795000658637">"滑动图标即可打开相机"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。点按即可设为静音,但可能会同时将无障碍服务设为静音。"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s。点按即可设为振动。"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s。点按即可设为静音。"</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"点按即可更改振铃器模式"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"静音"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"取消静音"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"振动"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index d2a232b..7b4f663 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"取消"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"分享"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"已取消錄影畫面"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"已儲存錄影畫面,輕按即可查看"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"刪除錄影畫面時發生錯誤"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"無法獲得權限"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"開始錄影畫面時發生錯誤"</string>
@@ -446,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"解鎖方可使用 NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"此裝置屬於您的機構"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"此裝置屬於「<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>」"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"此為「<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>」提供的裝置"</string>
<string name="phone_hint" msgid="6682125338461375925">"從圖示滑動即可使用手機功能"</string>
<string name="voice_hint" msgid="7476017460191291417">"從圖示滑動即可使用語音助手"</string>
<string name="camera_hint" msgid="4519495795000658637">"從圖示滑動即可使用相機功能"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 396484a..1dddeba 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"取消"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"分享"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"已取消錄製螢幕畫面"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"已儲存螢幕畫面錄製內容,輕觸即可查看"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"刪除螢幕畫面錄製內容時發生錯誤"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"無法取得權限"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"開始錄製螢幕畫面時發生錯誤"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"於日出時關閉"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"開啟時間:<xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"關閉時間:<xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"調低亮度"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC 已停用"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC 已啟用"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"如要使用 NFC,請先解鎖"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"這部裝置的擁有者為貴機構"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"這部裝置的擁有者為「<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>」"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"此為「<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>」提供的裝置"</string>
<string name="phone_hint" msgid="6682125338461375925">"滑動手機圖示即可啟用"</string>
<string name="voice_hint" msgid="7476017460191291417">"滑動語音小幫手圖示即可啟用"</string>
<string name="camera_hint" msgid="4519495795000658637">"滑動相機圖示即可啟用"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s。輕觸即可設為靜音,但系統可能會將無障礙服務一併設為靜音。"</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s。輕觸即可設為震動。"</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s。輕觸即可設為靜音。"</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"輕觸即可變更鈴聲模式"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"靜音"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"取消靜音"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"震動"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index d4e05d0..c6f0ef9 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -116,7 +116,10 @@
<string name="screenrecord_cancel_label" msgid="7850926573274483294">"Khansela"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"Yabelana"</string>
<string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ukurekhoda isikrini kukhanseliwe"</string>
- <string name="screenrecord_save_message" msgid="490522052388998226">"Ukurekhoda isikrini kulondoloziwe, thepha ukuze ubuke"</string>
+ <!-- no translation found for screenrecord_save_title (1886652605520893850) -->
+ <skip />
+ <!-- no translation found for screenrecord_save_text (3008973099800840163) -->
+ <skip />
<string name="screenrecord_delete_error" msgid="2870506119743013588">"Iphutha lokususa ukurekhoda isikrini"</string>
<string name="screenrecord_permission_error" msgid="7856841237023137686">"Yehlulekile ukuthola izimvume"</string>
<string name="screenrecord_start_error" msgid="2200660692479682368">"Iphutha lokuqala ukurekhoda isikrini"</string>
@@ -412,8 +415,7 @@
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Kuze kube sekuphumeni kwelanga"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Kuvulwe ngo-<xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Kuze kube ngu-<xliff:g id="TIME">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_reduce_bright_colors_label (7537352080559075175) -->
- <skip />
+ <string name="quick_settings_reduce_bright_colors_label" msgid="7537352080559075175">"Nciphisa ukukhanya"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"I-NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"I-NFC ikhutshaziwe"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"I-NFC inikwe amandla"</string>
@@ -447,8 +449,7 @@
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Vula ukuze usebenzise i-NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Le divayisi eyenhlangano yakho"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Le divayisi ngeye-<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <!-- no translation found for do_financed_disclosure_with_name (6723004643314467864) -->
- <skip />
+ <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Le divayisi ihlinzekwa yi-<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
<string name="phone_hint" msgid="6682125338461375925">"Swayiphela ifoni kusukela kusithonjana"</string>
<string name="voice_hint" msgid="7476017460191291417">"Swayiphela isilekeleli sezwi kusukela kusithonjana"</string>
<string name="camera_hint" msgid="4519495795000658637">"Swayiphela ikhamela kusukela kusithonjana"</string>
@@ -628,8 +629,7 @@
<string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Thepha ukuze uthulise. Amasevisi okufinyelela angathuliswa."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="2742330052979397471">"%1$s. Thepha ukuze usethele ekudlidlizeni."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="5743548478357238156">"%1$s. Thepha ukuze uthulise."</string>
- <!-- no translation found for volume_ringer_change (3574969197796055532) -->
- <skip />
+ <string name="volume_ringer_change" msgid="3574969197796055532">"Thepha ukuze ushintshe imodi yokukhala"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"thulisa"</string>
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"susa ukuthula"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"dlidliza"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 3bc1c80..c36f7cd 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -171,10 +171,10 @@
<color name="zen_introduction">#ffffffff</color>
- <color name="smart_reply_button_text">@color/GM2_grey_700</color>
+ <color name="smart_reply_button_text">@*android:color/notification_primary_text_color_light</color>
<color name="smart_reply_button_text_dark_bg">@*android:color/notification_primary_text_color_dark</color>
<color name="smart_reply_button_background">#ffffffff</color>
- <color name="smart_reply_button_stroke">#ffdadce0</color>
+ <color name="smart_reply_button_stroke">@*android:color/accent_device_default</color>
<!-- Biometric dialog colors -->
<color name="biometric_dialog_dim_color">#80000000</color> <!-- 50% black -->
@@ -183,7 +183,9 @@
<color name="biometric_dialog_error">#ffd93025</color> <!-- red 600 -->
<!-- UDFPS colors -->
- <color name="udfps_enroll_icon">#000000</color> <!-- 100% black -->
+ <color name="udfps_enroll_icon">#000000</color> <!-- 100% black -->
+ <color name="udfps_moving_target_fill">#cc4285f4</color> <!-- 80% blue -->
+ <color name="udfps_moving_target_stroke">#ff669DF6</color> <!-- 100% blue -->
<!-- Logout button -->
<color name="logout_button_bg_color">#ccffffff</color>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 5f8df5a..b5ded01 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -294,8 +294,10 @@
<string name="screenrecord_share_label">Share</string>
<!-- A toast message shown after successfully canceling a screen recording [CHAR LIMIT=NONE] -->
<string name="screenrecord_cancel_success">Screen recording canceled</string>
- <!-- Notification text shown after saving a screen recording to prompt the user to view it [CHAR LIMIT=100] -->
- <string name="screenrecord_save_message">Screen recording saved, tap to view</string>
+ <!-- Notification text shown after saving a screen recording [CHAR LIMIT=100] -->
+ <string name="screenrecord_save_title">Screen recording saved</string>
+ <!-- Subtext for a notification shown after saving a screen recording to prompt the user to view it [CHAR_LIMIT=100] -->
+ <string name="screenrecord_save_text">Tap to view</string>
<!-- A toast message shown when there is an error deleting a screen recording [CHAR LIMIT=NONE] -->
<string name="screenrecord_delete_error">Error deleting screen recording</string>
<!-- A toast message shown when the screen recording cannot be started due to insufficient permissions [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 2d202fb..ec26b8d 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -608,6 +608,11 @@
<item name="android:windowCloseOnTouchOutside">true</item>
</style>
+ <!-- Privacy dialog -->
+ <style name="PrivacyDialog" parent="ScreenRecord">
+ <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
+ </style>
+
<!-- USB Contaminant dialog -->
<style name ="USBContaminant" />
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
index e5ced3e..54242be 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl
@@ -21,5 +21,5 @@
*/
oneway interface ISplitScreenListener {
void onStagePositionChanged(int stage, int position);
- void onTaskStageChanged(int taskId, int stage);
-}
\ No newline at end of file
+ void onTaskStageChanged(int taskId, int stage, boolean visible);
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IStartingWindowListener.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IStartingWindowListener.aidl
new file mode 100644
index 0000000..eb3e60c
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IStartingWindowListener.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 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.systemui.shared.recents;
+
+/**
+ * Listener interface that Launcher attaches to SystemUI to get
+ * callbacks when need a new starting window.
+ */
+interface IStartingWindowListener {
+ /**
+ * Notifies when Shell going to create a new starting window.
+ * @param taskId The task Id
+ * @param supportedType The starting window type
+ */
+ oneway void onTaskLaunching(int taskId, int supportedType);
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 5c943f6..49e86f5 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -19,6 +19,7 @@
import android.app.PendingIntent;
import android.app.PictureInPictureParams;
import android.content.ComponentName;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Insets;
@@ -29,12 +30,13 @@
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.recents.ISplitScreenListener;
+import com.android.systemui.shared.recents.IStartingWindowListener;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.RemoteTransitionCompat;
/**
* Temporary callbacks into SystemUI.
- * Next id = 30
+ * Next id = 44
*/
interface ISystemUiProxy {
@@ -251,5 +253,11 @@
void startShortcut(in String packageName, in String shortcutId, in int stage, in int position,
in Bundle options, in UserHandle user) = 40;
void startIntent(
- in PendingIntent intent, in int stage, in int position, in Bundle options) = 41;
+ in PendingIntent intent, in Intent fillInIntent, in int stage, in int position,
+ in Bundle options) = 41;
+ void removeFromSideStage(in int taskId) = 42;
+ /**
+ * Sets listener to get task launching callbacks.
+ */
+ void setStartingWindowListener(IStartingWindowListener listener) = 43;
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
index e6477f1..400bf15 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
@@ -113,17 +113,6 @@
// TODO(bc-unlock): Build wrapped object for non-apps target.
final RemoteAnimationTargetCompat[] nonAppsCompat =
new RemoteAnimationTargetCompat[0];
- final Runnable animationFinishedCallback = new Runnable() {
- @Override
- public void run() {
- try {
- finishCallback.onTransitionFinished(null /* wct */);
- } catch (RemoteException e) {
- Log.e("ActivityOptionsCompat", "Failed to call app controlled animation"
- + " finished callback", e);
- }
- }
- };
// TODO(b/177438007): Move this set-up logic into launcher's animation impl.
boolean isReturnToHome = false;
@@ -143,8 +132,8 @@
final TransitionInfo.Change change = info.getChanges().get(i);
final SurfaceControl leash = change.getLeash();
final int mode = info.getChanges().get(i).getMode();
- // Only deal with roots
- if (change.getParent() != null) continue;
+ // Only deal with independent layers
+ if (!TransitionInfo.isIndependent(change, info)) continue;
if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
t.setLayer(leash, info.getChanges().size() * 3 - i);
}
@@ -156,6 +145,18 @@
}
}
t.apply();
+
+ final Runnable animationFinishedCallback = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ finishCallback.onTransitionFinished(null /* wct */);
+ } catch (RemoteException e) {
+ Log.e("ActivityOptionsCompat", "Failed to call app controlled animation"
+ + " finished callback", e);
+ }
+ }
+ };
// TODO(bc-unlcok): Pass correct transit type.
remoteAnimationAdapter.onAnimationStart(
TRANSIT_OLD_NONE,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 2373d75..83c2d1e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -405,14 +405,19 @@
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
+ /**
+ * Set the amount (ratio) that the device has transitioned to doze.
+ *
+ * @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake.
+ */
public void setDarkAmount(float darkAmount) {
- boolean isAwake = darkAmount != 0;
- boolean wasAwake = mDarkAmount != 0;
- if (isAwake == wasAwake) {
+ boolean isDozing = darkAmount != 0;
+ boolean wasDozing = mDarkAmount != 0;
+ if (isDozing == wasDozing) {
return;
}
mDarkAmount = darkAmount;
- setLayoutAnimationListener(isAwake ? null : mKeepAwakeListener);
+ setLayoutAnimationListener(isDozing ? null : mKeepAwakeListener);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java
index a029003..a51b6fd1 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimation.java
@@ -17,6 +17,7 @@
package com.android.systemui.biometrics;
import android.content.Context;
+import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.view.View;
@@ -46,12 +47,17 @@
}
public void onSensorRectUpdated(@NonNull RectF sensorRect) {
- int margin = (int) (sensorRect.bottom - sensorRect.top) / 5;
- mFingerprintDrawable.setBounds(
- (int) sensorRect.left + margin,
+ final int margin = (int) sensorRect.height() / 8;
+
+ final Rect bounds = new Rect((int) sensorRect.left + margin,
(int) sensorRect.top + margin,
(int) sensorRect.right - margin,
(int) sensorRect.bottom - margin);
+ updateFingerprintIconBounds(bounds);
+ }
+
+ protected void updateFingerprintIconBounds(@NonNull Rect bounds) {
+ mFingerprintDrawable.setBounds(bounds);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java
index 28b5719..015a598 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java
@@ -22,13 +22,14 @@
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
+import android.graphics.PointF;
+import android.graphics.Rect;
import android.graphics.RectF;
-import android.util.Log;
+import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.settingslib.Utils;
import com.android.systemui.R;
/**
@@ -40,9 +41,13 @@
private static final float SHADOW_RADIUS = 5.f;
private static final float PROGRESS_BAR_RADIUS = 140.f;
- @Nullable private RectF mSensorRect;
+ @NonNull private final Drawable mMovingTargetFpIcon;
@NonNull private final Paint mSensorPaint;
- private final int mNotificationShadeColor;
+ @NonNull private final Paint mBlueFill;
+ @NonNull private final Paint mBlueStroke;;
+
+ @Nullable private RectF mSensorRect;
+ @Nullable private UdfpsEnrollHelper mEnrollHelper;
UdfpsAnimationEnroll(@NonNull Context context) {
super(context);
@@ -53,8 +58,24 @@
mSensorPaint.setShadowLayer(SHADOW_RADIUS, 0, 0, Color.BLACK);
mSensorPaint.setStyle(Paint.Style.FILL);
- mNotificationShadeColor = Utils.getColorAttr(context,
- android.R.attr.colorBackgroundFloating).getDefaultColor();
+ mBlueFill = new Paint(0 /* flags */);
+ mBlueFill.setAntiAlias(true);
+ mBlueFill.setColor(context.getColor(R.color.udfps_moving_target_fill));
+ mBlueFill.setStyle(Paint.Style.FILL);
+
+ mBlueStroke = new Paint(0 /* flags */);
+ mBlueStroke.setAntiAlias(true);
+ mBlueStroke.setColor(context.getColor(R.color.udfps_moving_target_stroke));
+ mBlueStroke.setStyle(Paint.Style.STROKE);
+ mBlueStroke.setStrokeWidth(12);
+
+ mMovingTargetFpIcon = context.getResources().getDrawable(R.drawable.ic_fingerprint, null);
+ mMovingTargetFpIcon.setTint(Color.WHITE);
+ mMovingTargetFpIcon.mutate();
+ }
+
+ void setEnrollHelper(@NonNull UdfpsEnrollHelper helper) {
+ mEnrollHelper = helper;
}
@Override
@@ -74,6 +95,12 @@
}
@Override
+ protected void updateFingerprintIconBounds(@NonNull Rect bounds) {
+ super.updateFingerprintIconBounds(bounds);
+ mMovingTargetFpIcon.setBounds(bounds);
+ }
+
+ @Override
public void draw(@NonNull Canvas canvas) {
if (isIlluminationShowing()) {
return;
@@ -87,6 +114,24 @@
}
}
mFingerprintDrawable.draw(canvas);
+
+ // Draw moving target
+ if (mEnrollHelper.isCenterEnrollmentComplete()) {
+ mFingerprintDrawable.setAlpha(64);
+
+ canvas.save();
+ final PointF point = mEnrollHelper.getNextGuidedEnrollmentPoint();
+ canvas.translate(point.x, point.y);
+ if (mSensorRect != null) {
+ canvas.drawOval(mSensorRect, mBlueFill);
+ canvas.drawOval(mSensorRect, mBlueStroke);
+ }
+
+ mMovingTargetFpIcon.draw(canvas);
+ canvas.restore();
+ } else {
+ mFingerprintDrawable.setAlpha(255);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
index f4dd181..43ecf67 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.PointF;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.widget.FrameLayout;
@@ -62,7 +63,10 @@
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- getUdfpsAnimation().onDestroy();
+
+ if (getUdfpsAnimation() != null) {
+ getUdfpsAnimation().onDestroy();
+ }
}
private int expansionToAlpha(float expansion) {
@@ -78,11 +82,19 @@
}
void onIlluminationStarting() {
+ if (getUdfpsAnimation() == null) {
+ return;
+ }
+
getUdfpsAnimation().setIlluminationShowing(true);
postInvalidate();
}
void onIlluminationStopped() {
+ if (getUdfpsAnimation() == null) {
+ return;
+ }
+
getUdfpsAnimation().setIlluminationShowing(false);
postInvalidate();
}
@@ -131,4 +143,14 @@
}
return getUdfpsAnimation().getPaddingY();
}
+
+ /**
+ * @return the amount of translation needed if the view currently requires the user to touch
+ * somewhere other than the exact center of the sensor. For example, this can happen
+ * during guided enrollment.
+ */
+ @NonNull
+ PointF getTouchTranslation() {
+ return new PointF(0, 0);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewBp.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewBp.java
new file mode 100644
index 0000000..515b442
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewBp.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 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.systemui.biometrics;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import androidx.annotation.Nullable;
+
+/**
+ * Class that coordinates non-HBM animations during BiometricPrompt.
+ *
+ * Note that {@link AuthBiometricUdfpsView} also shows UDFPS animations. At some point we should
+ * de-dupe this if necessary. This will probably happen once the top-level TODO in UdfpsController
+ * is completed (inflate operation-specific views, instead of inflating generic udfps_view and
+ * adding operation-specific animations to it).
+ */
+public class UdfpsAnimationViewBp extends UdfpsAnimationView {
+ public UdfpsAnimationViewBp(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Nullable
+ @Override
+ protected UdfpsAnimation getUdfpsAnimation() {
+ return null;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewEnroll.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewEnroll.java
index 19e77493..543df33 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewEnroll.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewEnroll.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
@@ -33,7 +34,7 @@
private static final String TAG = "UdfpsAnimationViewEnroll";
- @NonNull private UdfpsAnimation mUdfpsAnimation;
+ @NonNull private UdfpsAnimationEnroll mUdfpsAnimation;
@NonNull private UdfpsProgressBar mProgressBar;
@Nullable private UdfpsEnrollHelper mEnrollHelper;
@@ -50,6 +51,7 @@
public void setEnrollHelper(@NonNull UdfpsEnrollHelper helper) {
mEnrollHelper = helper;
+ mUdfpsAnimation.setEnrollHelper(helper);
}
@Override
@@ -81,4 +83,14 @@
mProgressBar.setProgress(interpolatedProgress, true);
}
+
+ @NonNull
+ @Override
+ PointF getTouchTranslation() {
+ if (!mEnrollHelper.isCenterEnrollmentComplete()) {
+ return new PointF(0, 0);
+ } else {
+ return mEnrollHelper.getNextGuidedEnrollmentPoint();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index e1d7eb3..3296cb8 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -28,11 +28,13 @@
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IUdfpsOverlayController;
+import android.os.SystemClock;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.Surface;
+import android.view.VelocityTracker;
import android.view.WindowManager;
import androidx.annotation.NonNull;
@@ -66,6 +68,9 @@
private static final String TAG = "UdfpsController";
private static final long AOD_INTERRUPT_TIMEOUT_MILLIS = 1000;
+ // Minimum required delay between consecutive touch logs in milliseconds.
+ private static final long MIN_TOUCH_LOG_INTERVAL = 50;
+
private final Context mContext;
private final FingerprintManager mFingerprintManager;
@NonNull private final LayoutInflater mInflater;
@@ -78,6 +83,13 @@
@VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
private final WindowManager.LayoutParams mCoreLayoutParams;
+ // Tracks the velocity of a touch to help filter out the touches that move too fast.
+ @Nullable private VelocityTracker mVelocityTracker;
+ // The ID of the pointer for which ACTION_DOWN has occurred. -1 means no pointer is active.
+ private int mActivePointerId;
+ // The timestamp of the most recent touch log.
+ private long mTouchLogTime;
+
@Nullable private UdfpsView mView;
// Indicates whether the overlay has been requested.
private boolean mIsOverlayRequested;
@@ -97,7 +109,7 @@
public void showUdfpsOverlay(int sensorId, int reason) {
if (reason == IUdfpsOverlayController.REASON_ENROLL_FIND_SENSOR
|| reason == IUdfpsOverlayController.REASON_ENROLL_ENROLLING) {
- mEnrollHelper = new UdfpsEnrollHelper(reason);
+ mEnrollHelper = new UdfpsEnrollHelper(mContext, reason);
} else {
mEnrollHelper = null;
}
@@ -136,46 +148,98 @@
}
}
- @VisibleForTesting
- final StatusBar.ExpansionChangedListener mStatusBarExpansionListener =
+ @VisibleForTesting final StatusBar.ExpansionChangedListener mStatusBarExpansionListener =
(expansion, expanded) -> mView.onExpansionChanged(expansion, expanded);
- @VisibleForTesting
- final StatusBarStateController.StateListener mStatusBarStateListener =
+ @VisibleForTesting final StatusBarStateController.StateListener mStatusBarStateListener =
new StatusBarStateController.StateListener() {
@Override
public void onStateChanged(int newState) {
- mView.onStateChanged(newState);
+ mView.onStateChanged(newState);
}
- };
+ };
+
+ private static float computePointerSpeed(@NonNull VelocityTracker tracker, int pointerId) {
+ final float vx = tracker.getXVelocity(pointerId);
+ final float vy = tracker.getYVelocity(pointerId);
+ return (float) Math.sqrt(Math.pow(vx, 2.0) + Math.pow(vy, 2.0));
+ }
@SuppressLint("ClickableViewAccessibility")
- private final UdfpsView.OnTouchListener mOnTouchListener = (v, event) -> {
- UdfpsView view = (UdfpsView) v;
- final boolean isFingerDown = view.isIlluminationRequested();
- switch (event.getAction()) {
+ private final UdfpsView.OnTouchListener mOnTouchListener = (view, event) -> {
+ UdfpsView udfpsView = (UdfpsView) view;
+ final boolean isFingerDown = udfpsView.isIlluminationRequested();
+ boolean handled = false;
+ switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_MOVE:
- final boolean isValidTouch = view.isValidTouch(event.getX(), event.getY(),
- event.getPressure());
- if (!isFingerDown && isValidTouch) {
- onFingerDown((int) event.getX(), (int) event.getY(), event.getTouchMinor(),
- event.getTouchMajor());
- } else if (isFingerDown && !isValidTouch) {
- onFingerUp();
+ // To simplify the lifecycle of the velocity tracker, make sure it's never null
+ // after ACTION_DOWN, and always null after ACTION_CANCEL or ACTION_UP.
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ } else {
+ // ACTION_UP or ACTION_CANCEL is not guaranteed to be called before a new
+ // ACTION_DOWN, in that case we should just reuse the old instance.
+ mVelocityTracker.clear();
}
- return true;
+ // TODO: move isWithinSensorArea to UdfpsController.
+ if (udfpsView.isWithinSensorArea(event.getX(), event.getY())) {
+ // The pointer that causes ACTION_DOWN is always at index 0.
+ // We need to persist its ID to track it during ACTION_MOVE that could include
+ // data for many other pointers because of multi-touch support.
+ mActivePointerId = event.getPointerId(0);
+ mVelocityTracker.addMovement(event);
+ handled = true;
+ }
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ final int idx = event.findPointerIndex(mActivePointerId);
+ if (idx == event.getActionIndex()) {
+ final float x = event.getX(idx);
+ final float y = event.getY(idx);
+ if (udfpsView.isWithinSensorArea(x, y)) {
+ mVelocityTracker.addMovement(event);
+ // Compute pointer velocity in pixels per second.
+ mVelocityTracker.computeCurrentVelocity(1000);
+ // Compute pointer speed from X and Y velocities.
+ final float v = computePointerSpeed(mVelocityTracker, mActivePointerId);
+ final float minor = event.getTouchMinor(idx);
+ final float major = event.getTouchMajor(idx);
+ final String touchInfo = String.format("minor: %.1f, major: %.1f, v: %.1f",
+ minor, major, v);
+ final long sinceLastLog = SystemClock.elapsedRealtime() - mTouchLogTime;
+ if (!isFingerDown) {
+ onFingerDown((int) x, (int) y, minor, major);
+ Log.v(TAG, "onTouch | finger down: " + touchInfo);
+ mTouchLogTime = SystemClock.elapsedRealtime();
+ handled = true;
+ } else if (sinceLastLog >= MIN_TOUCH_LOG_INTERVAL) {
+ Log.v(TAG, "onTouch | finger move: " + touchInfo);
+ mTouchLogTime = SystemClock.elapsedRealtime();
+ }
+ } else if (isFingerDown) {
+ Log.v(TAG, "onTouch | finger outside");
+ onFingerUp();
+ }
+ }
+ break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
if (isFingerDown) {
+ Log.v(TAG, "onTouch | finger up");
onFingerUp();
}
- return true;
+ break;
default:
- return false;
+ // Do nothing.
}
+ return handled;
};
@Inject
@@ -231,6 +295,9 @@
@Override
public void dozeTimeTick() {
+ if (mView == null) {
+ return;
+ }
mView.dozeTimeTick();
}
@@ -358,23 +425,29 @@
switch (reason) {
case IUdfpsOverlayController.REASON_ENROLL_FIND_SENSOR:
case IUdfpsOverlayController.REASON_ENROLL_ENROLLING: {
- final UdfpsAnimationViewEnroll animation = (UdfpsAnimationViewEnroll)
+ final UdfpsAnimationViewEnroll view = (UdfpsAnimationViewEnroll)
inflater.inflate(R.layout.udfps_animation_view_enroll, null, false);
- animation.setEnrollHelper(mEnrollHelper);
- return animation;
+ view.setEnrollHelper(mEnrollHelper);
+ return view;
+ }
+
+ case IUdfpsOverlayController.REASON_AUTH_BP: {
+ final UdfpsAnimationViewBp view = (UdfpsAnimationViewBp)
+ inflater.inflate(R.layout.udfps_animation_view_bp, null, false);
+ return view;
}
case IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD: {
- final UdfpsAnimationViewKeyguard animation = (UdfpsAnimationViewKeyguard)
+ final UdfpsAnimationViewKeyguard view = (UdfpsAnimationViewKeyguard)
inflater.inflate(R.layout.udfps_animation_view_keyguard, null, false);
- animation.setStatusBarStateController(mStatusBarStateController);
- return animation;
+ view.setStatusBarStateController(mStatusBarStateController);
+ return view;
}
case IUdfpsOverlayController.REASON_AUTH_FPM_OTHER: {
- final UdfpsAnimationViewFpmOther animation = (UdfpsAnimationViewFpmOther)
+ final UdfpsAnimationViewFpmOther view = (UdfpsAnimationViewFpmOther)
inflater.inflate(R.layout.udfps_animation_view_fpm_other, null, false);
- return animation;
+ return view;
}
default:
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
index 942fa7a..14eca1b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
@@ -18,7 +18,13 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.PointF;
import android.hardware.fingerprint.IUdfpsOverlayController;
+import android.util.TypedValue;
+
+import java.util.ArrayList;
+import java.util.List;
/**
* Helps keep track of enrollment state and animates the progress bar accordingly.
@@ -26,20 +32,48 @@
public class UdfpsEnrollHelper {
private static final String TAG = "UdfpsEnrollHelper";
+ // Enroll with two center touches before going to guided enrollment
+ private static final int NUM_CENTER_TOUCHES = 2;
+
interface Listener {
void onEnrollmentProgress(int remaining, int totalSteps);
}
// IUdfpsOverlayController reason
private final int mEnrollReason;
+ private final List<PointF> mGuidedEnrollmentPoints;
private int mTotalSteps = -1;
- private int mCurrentProgress = 0;
+ private int mRemainingSteps = -1;
+
+ // Note that this is actually not equal to "mTotalSteps - mRemainingSteps", because the
+ // interface makes no promises about monotonically increasing by one each time.
+ private int mLocationsEnrolled = 0;
@Nullable Listener mListener;
- public UdfpsEnrollHelper(int reason) {
+ public UdfpsEnrollHelper(@NonNull Context context, int reason) {
mEnrollReason = reason;
+ mGuidedEnrollmentPoints = new ArrayList<>();
+
+ // Number of pixels per mm
+ float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1,
+ context.getResources().getDisplayMetrics());
+
+ mGuidedEnrollmentPoints.add(new PointF( 2.00f * px, 0.00f * px));
+ mGuidedEnrollmentPoints.add(new PointF( 0.87f * px, -2.70f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-1.80f * px, -1.31f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-1.80f * px, 1.31f * px));
+ mGuidedEnrollmentPoints.add(new PointF( 0.88f * px, 2.70f * px));
+ mGuidedEnrollmentPoints.add(new PointF( 3.94f * px, -1.06f * px));
+ mGuidedEnrollmentPoints.add(new PointF( 2.90f * px, -4.14f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-0.52f * px, -5.95f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-3.33f * px, -3.33f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-3.99f * px, -0.35f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-3.62f * px, 2.54f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-1.49f * px, 5.57f * px));
+ mGuidedEnrollmentPoints.add(new PointF( 2.29f * px, 4.92f * px));
+ mGuidedEnrollmentPoints.add(new PointF( 3.82f * px, 1.78f * px));
}
boolean shouldShowProgressBar() {
@@ -51,6 +85,12 @@
mTotalSteps = remaining;
}
+ if (remaining != mRemainingSteps) {
+ mLocationsEnrolled++;
+ }
+
+ mRemainingSteps = remaining;
+
if (mListener != null) {
mListener.onEnrollmentProgress(remaining, mTotalSteps);
}
@@ -67,8 +107,21 @@
// bar can be updated. If enrollment has not started yet, the progress bar will be empty
// anyway.
if (mTotalSteps != -1) {
- final int remainingSteps = mTotalSteps - mCurrentProgress;
- mListener.onEnrollmentProgress(remainingSteps, mTotalSteps);
+ mListener.onEnrollmentProgress(mRemainingSteps, mTotalSteps);
}
}
+
+ boolean isCenterEnrollmentComplete() {
+ if (mTotalSteps == -1 || mRemainingSteps == -1) {
+ return false;
+ }
+ final int stepsEnrolled = mTotalSteps - mRemainingSteps;
+ return stepsEnrolled >= NUM_CENTER_TOUCHES;
+ }
+
+ @NonNull
+ PointF getNextGuidedEnrollmentPoint() {
+ final int index = mLocationsEnrolled - NUM_CENTER_TOUCHES;
+ return mGuidedEnrollmentPoints.get(index % mGuidedEnrollmentPoints.size());
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
index cd849e6..a52bddc 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
@@ -27,11 +27,13 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
+import android.graphics.PointF;
import android.graphics.RectF;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
@@ -91,6 +93,12 @@
mIlluminationRequested = false;
}
+ // Don't propagate any touch events to the child views.
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ return true;
+ }
+
@Override
protected void onFinishInflate() {
mHbmSurfaceView = findViewById(R.id.hbm_view);
@@ -178,10 +186,11 @@
postInvalidate();
}
- boolean isValidTouch(float x, float y, float pressure) {
+ boolean isWithinSensorArea(float x, float y) {
// The X and Y coordinates of the sensor's center.
- final float cx = mSensorRect.centerX();
- final float cy = mSensorRect.centerY();
+ final PointF translation = mAnimationView.getTouchTranslation();
+ final float cx = mSensorRect.centerX() + translation.x;
+ final float cy = mSensorRect.centerY() + translation.y;
// Radii along the X and Y axes.
final float rx = (mSensorRect.right - mSensorRect.left) / 2.0f;
final float ry = (mSensorRect.bottom - mSensorRect.top) / 2.0f;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 04c4e97..1c5715c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -25,6 +25,7 @@
import android.app.IWallpaperManager;
import android.app.KeyguardManager;
import android.app.NotificationManager;
+import android.app.StatsManager;
import android.app.WallpaperManager;
import android.app.admin.DevicePolicyManager;
import android.app.role.RoleManager;
@@ -321,6 +322,12 @@
@Provides
@Singleton
+ static StatsManager provideStatsManager(Context context) {
+ return context.getSystemService(StatsManager.class);
+ }
+
+ @Provides
+ @Singleton
@Nullable
static TelecomManager provideTelecomManager(Context context) {
return context.getSystemService(TelecomManager.class);
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
index bd3f5a6..7fb7d8b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
@@ -20,9 +20,13 @@
import android.content.Context
import android.content.Intent
import android.text.TextUtils
+import android.util.Log
import com.android.settingslib.media.MediaOutputConstants
import javax.inject.Inject
+private const val TAG = "MediaOutputDlgReceiver"
+private val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
+
/**
* BroadcastReceiver for handling media output intent
*/
@@ -32,8 +36,13 @@
override fun onReceive(context: Context, intent: Intent) {
if (TextUtils.equals(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG,
intent.action)) {
- mediaOutputDialogFactory.create(
- intent.getStringExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME), false)
+ val packageName: String? =
+ intent.getStringExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME)
+ if (!TextUtils.isEmpty(packageName)) {
+ mediaOutputDialogFactory.create(packageName!!, false)
+ } else if (DEBUG) {
+ Log.e(TAG, "Unable to launch media output dialog. Package name is empty.")
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 70b7b04..4491cc1 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -180,7 +180,7 @@
}
} else {
for (int i = 0; i < mNavigationBars.size(); i++) {
- mNavigationBars.get(i).onConfigurationChanged(newConfig);
+ mNavigationBars.valueAt(i).onConfigurationChanged(newConfig);
}
}
}
@@ -193,7 +193,7 @@
if (navBar == null) {
continue;
}
- NavigationBarView view = (NavigationBarView) mNavigationBars.get(i).getView();
+ NavigationBarView view = (NavigationBarView) navBar.getView();
if (view != null) {
view.updateStates();
}
@@ -399,7 +399,7 @@
if (i > 0) {
pw.println();
}
- mNavigationBars.get(i).dump(pw);
+ mNavigationBars.valueAt(i).dump(pw);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
index 2ea8657..a69ec27 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
@@ -23,7 +23,6 @@
import android.app.INotificationManager;
import android.app.people.IPeopleManager;
import android.app.people.PeopleSpaceTile;
-import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
@@ -34,12 +33,10 @@
import android.util.Log;
import android.view.ViewGroup;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.UiEventLoggerImpl;
import com.android.systemui.R;
+import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
@@ -54,15 +51,14 @@
private ViewGroup mPeopleSpaceLayout;
private IPeopleManager mPeopleManager;
+ private PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
private INotificationManager mNotificationManager;
private PackageManager mPackageManager;
private LauncherApps mLauncherApps;
private Context mContext;
- private AppWidgetManager mAppWidgetManager;
private NotificationEntryManager mNotificationEntryManager;
private int mAppWidgetId;
private boolean mShowSingleConversation;
- private UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
@Inject
public PeopleSpaceActivity(NotificationEntryManager notificationEntryManager) {
@@ -81,8 +77,8 @@
mPackageManager = getPackageManager();
mPeopleManager = IPeopleManager.Stub.asInterface(
ServiceManager.getService(Context.PEOPLE_SERVICE));
+ mPeopleSpaceWidgetManager = new PeopleSpaceWidgetManager(mContext);
mLauncherApps = mContext.getSystemService(LauncherApps.class);
- mAppWidgetManager = AppWidgetManager.getInstance(mContext);
setTileViewsWithPriorityConversations();
mAppWidgetId = getIntent().getIntExtra(EXTRA_APPWIDGET_ID,
INVALID_APPWIDGET_ID);
@@ -142,29 +138,13 @@
+ mAppWidgetId);
}
}
-
- PeopleSpaceUtils.setStorageForTile(mContext, tile, mAppWidgetId);
- int[] widgetIds = new int[mAppWidgetId];
- // TODO: Populate new widget with existing conversation notification, if there is any.
- PeopleSpaceUtils.updateSingleConversationWidgets(mContext, widgetIds, mAppWidgetManager,
- mPeopleManager);
- if (mLauncherApps != null) {
- try {
- if (DEBUG) Log.d(TAG, "Caching shortcut for PeopleTile: " + tile.getId());
- mLauncherApps.cacheShortcuts(tile.getPackageName(),
- Collections.singletonList(tile.getId()),
- tile.getUserHandle(), LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS);
- } catch (Exception e) {
- Log.w(TAG, "Exception caching shortcut:" + e);
- }
- }
+ mPeopleSpaceWidgetManager.addNewWidget(tile, mAppWidgetId);
finishActivity();
}
/** Finish activity with a successful widget configuration result. */
private void finishActivity() {
if (DEBUG) Log.d(TAG, "Widget added!");
- mUiEventLogger.log(PeopleSpaceUtils.PeopleSpaceWidgetEvent.PEOPLE_SPACE_WIDGET_ADDED);
setActivityResult(RESULT_OK);
finish();
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
index 41080af..f9a16c1 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
@@ -220,7 +220,7 @@
}
@Nullable
- private static PeopleSpaceTile getPeopleSpaceTile(IPeopleManager peopleManager,
+ public static PeopleSpaceTile getPeopleSpaceTile(IPeopleManager peopleManager,
AppWidgetManager appWidgetManager,
Context context, int appWidgetId) {
try {
@@ -230,7 +230,7 @@
String pkg = widgetSp.getString(PACKAGE_NAME, EMPTY_STRING);
int userId = widgetSp.getInt(USER_ID, INVALID_USER_ID);
String shortcutId = widgetSp.getString(SHORTCUT_ID, EMPTY_STRING);
- if (pkg.isEmpty() || shortcutId.isEmpty() || userId == INVALID_WIDGET_ID) {
+ if (!validKey(shortcutId, pkg, userId)) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
shortcutId = sp.getString(String.valueOf(appWidgetId), null);
if (shortcutId == null) {
@@ -268,6 +268,17 @@
}
}
+ /** Returns stored widgets for the conversation specified. */
+ public static Set<String> getStoredWidgetIds(SharedPreferences sp, String shortcutId,
+ String packageName, int userId) {
+ if (shortcutId == null || packageName == null) {
+ return new HashSet<>();
+ }
+ String key = PeopleSpaceUtils.getKey(shortcutId, packageName, userId);
+ return new HashSet<>(sp.getStringSet(key, new HashSet<>()));
+ }
+
+
/** Best-effort attempts to migrate existing users to the new storage format. */
// TODO: Remove after sufficient time. Temporary migration storage for existing users.
private static void migrateExistingUsersToNewStorage(Context context, String shortcutId,
@@ -286,7 +297,11 @@
if (DEBUG) Log.d(TAG, "Migrate storage for " + entry.get().getUserName());
setStorageForTile(context, entry.get(), appWidgetId);
} else {
- Log.e(TAG, "Could not migrate user");
+ Log.e(TAG, "Could not migrate user. Delete old storage");
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
+ SharedPreferences.Editor editor = sp.edit();
+ editor.remove(String.valueOf(appWidgetId));
+ editor.apply();
}
} catch (Exception e) {
Log.e(TAG, "Could not query conversations");
@@ -320,17 +335,10 @@
}
/** Removes stored data when tile is deleted. */
- public static void removeStorageForTile(Context context, int widgetId) {
- SharedPreferences widgetSp = context.getSharedPreferences(String.valueOf(widgetId),
- Context.MODE_PRIVATE);
- String packageName = widgetSp.getString(PACKAGE_NAME, null);
- String shortcutId = widgetSp.getString(SHORTCUT_ID, null);
- int userId = widgetSp.getInt(USER_ID, -1);
-
+ public static void removeStorageForTile(Context context, String key, int widgetId) {
// Delete widgetId mapping to key.
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = sp.edit();
- String key = PeopleSpaceUtils.getKey(shortcutId, packageName, userId);
Set<String> storedWidgetIds = new HashSet<>(sp.getStringSet(key, new HashSet<>()));
storedWidgetIds.remove(String.valueOf(widgetId));
editor.putStringSet(key, storedWidgetIds);
@@ -338,6 +346,8 @@
editor.apply();
// Delete all data specifically mapped to widgetId.
+ SharedPreferences widgetSp = context.getSharedPreferences(String.valueOf(widgetId),
+ Context.MODE_PRIVATE);
SharedPreferences.Editor widgetEditor = widgetSp.edit();
widgetEditor.remove(PACKAGE_NAME);
widgetEditor.remove(USER_ID);
@@ -345,21 +355,6 @@
widgetEditor.apply();
}
- /**
- * Returns whether the data mapped to app widget specified by {@code appWidgetId} matches the
- * requested update data.
- */
- public static boolean isCorrectAppWidget(Context context, int appWidgetId, String shortcutId,
- String packageName, int userId) {
- SharedPreferences sp = context.getSharedPreferences(String.valueOf(appWidgetId),
- Context.MODE_PRIVATE);
- String storedPackage = sp.getString(PACKAGE_NAME, EMPTY_STRING);
- int storedUserId = sp.getInt(USER_ID, INVALID_USER_ID);
- String storedShortcutId = sp.getString(SHORTCUT_ID, EMPTY_STRING);
- return storedPackage.equals(packageName) && storedShortcutId.equals(shortcutId)
- && storedUserId == userId;
- }
-
static List<PeopleSpaceTile> augmentTilesFromVisibleNotifications(Context context,
List<PeopleSpaceTile> tiles, NotificationEntryManager notificationEntryManager) {
if (notificationEntryManager == null) {
@@ -396,39 +391,8 @@
return augmentTileFromNotification(context, tile, visibleNotifications.get(key).getSbn());
}
- /**
- * If incoming notification changed tile, store the changes in the tile options.
- */
- public static void updateWidgetWithNotificationChanged(IPeopleManager peopleManager,
- Context context,
- StatusBarNotification sbn,
- NotificationAction notificationAction, AppWidgetManager appWidgetManager,
- int appWidgetId) {
- PeopleSpaceTile storedTile = getPeopleSpaceTile(peopleManager, appWidgetManager, context,
- appWidgetId);
- if (storedTile == null) {
- if (DEBUG) Log.d(TAG, "Could not find stored tile to add notification to");
- return;
- }
- if (notificationAction == PeopleSpaceUtils.NotificationAction.POSTED) {
- if (DEBUG) Log.i(TAG, "Adding notification to storage, appWidgetId: " + appWidgetId);
- storedTile = augmentTileFromNotification(context, storedTile, sbn);
- } else {
- if (DEBUG) {
- Log.i(TAG, "Removing notification from storage, appWidgetId: " + appWidgetId);
- }
- storedTile = storedTile
- .toBuilder()
- .setNotificationKey(null)
- .setNotificationContent(null)
- .setNotificationDataUri(null)
- .setNotificationCategory(null)
- .build();
- }
- updateAppWidgetOptionsAndView(appWidgetManager, context, appWidgetId, storedTile);
- }
-
- static PeopleSpaceTile augmentTileFromNotification(Context context, PeopleSpaceTile tile,
+ /** Augments {@code tile} with the notification content from {@code sbn}. */
+ public static PeopleSpaceTile augmentTileFromNotification(Context context, PeopleSpaceTile tile,
StatusBarNotification sbn) {
Notification notification = sbn.getNotification();
if (notification == null) {
@@ -992,7 +956,7 @@
}
/** Update app widget options and the current view. */
- private static void updateAppWidgetOptionsAndView(AppWidgetManager appWidgetManager,
+ public static void updateAppWidgetOptionsAndView(AppWidgetManager appWidgetManager,
Context context, int appWidgetId, PeopleSpaceTile tile) {
updateAppWidgetOptions(appWidgetManager, appWidgetId, tile);
RemoteViews views = createRemoteViews(context, tile, appWidgetId);
@@ -1065,10 +1029,19 @@
* <li>"a/b/0" + "/" + 0 + "/" + "packageName"</li>
* </ul>
*/
+ @Nullable
public static String getKey(String shortcutId, String packageName, int userId) {
+ if (!validKey(shortcutId, packageName, userId)) {
+ return null;
+ }
return shortcutId + "/" + userId + "/" + packageName;
}
+ /** Returns whether the key is valid. */
+ public static boolean validKey(String shortcutId, String packageName, int userId) {
+ return !TextUtils.isEmpty(shortcutId) && !TextUtils.isEmpty(packageName) && userId >= 0;
+ }
+
/** Returns the userId associated with a {@link PeopleSpaceTile} */
public static int getUserId(PeopleSpaceTile tile) {
return tile.getUserHandle().getIdentifier();
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
index 9e5c786..22ee9e8 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
@@ -16,12 +16,28 @@
package com.android.systemui.people.widget;
+import static com.android.systemui.people.PeopleSpaceUtils.INVALID_USER_ID;
+import static com.android.systemui.people.PeopleSpaceUtils.PACKAGE_NAME;
+import static com.android.systemui.people.PeopleSpaceUtils.SHORTCUT_ID;
+import static com.android.systemui.people.PeopleSpaceUtils.USER_ID;
+import static com.android.systemui.people.PeopleSpaceUtils.augmentTileFromNotification;
+import static com.android.systemui.people.PeopleSpaceUtils.getPeopleSpaceTile;
+import static com.android.systemui.people.PeopleSpaceUtils.getStoredWidgetIds;
+import static com.android.systemui.people.PeopleSpaceUtils.updateAppWidgetOptionsAndView;
+
import android.app.NotificationChannel;
+import android.app.Person;
+import android.app.people.ConversationChannel;
import android.app.people.IPeopleManager;
+import android.app.people.PeopleManager;
+import android.app.people.PeopleSpaceTile;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.SharedPreferences;
+import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
+import android.net.Uri;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.preference.PreferenceManager;
@@ -30,14 +46,18 @@
import android.service.notification.StatusBarNotification;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.appwidget.IAppWidgetService;
-import com.android.systemui.R;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.UiEventLoggerImpl;
import com.android.systemui.people.PeopleSpaceUtils;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
@@ -49,52 +69,49 @@
private static final String TAG = "PeopleSpaceWidgetMgr";
private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
+ private final Object mLock = new Object();
private final Context mContext;
- private IAppWidgetService mAppWidgetService;
+ private LauncherApps mLauncherApps;
private AppWidgetManager mAppWidgetManager;
- private IPeopleManager mPeopleManager;
+ private IPeopleManager mIPeopleManager;
+ private SharedPreferences mSharedPrefs;
+ private PeopleManager mPeopleManager;
+ public UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
+ @GuardedBy("mLock")
+ public static Map<String, PeopleSpaceWidgetProvider.TileConversationListener> mListeners =
+ new HashMap<>();
@Inject
- public PeopleSpaceWidgetManager(Context context, IAppWidgetService appWidgetService) {
+ public PeopleSpaceWidgetManager(Context context) {
if (DEBUG) Log.d(TAG, "constructor");
mContext = context;
- mAppWidgetService = appWidgetService;
mAppWidgetManager = AppWidgetManager.getInstance(context);
- mPeopleManager = IPeopleManager.Stub.asInterface(
+ mIPeopleManager = IPeopleManager.Stub.asInterface(
ServiceManager.getService(Context.PEOPLE_SERVICE));
- }
-
- /**
- * Constructor used for testing.
- */
- @VisibleForTesting
- protected PeopleSpaceWidgetManager(Context context) {
- if (DEBUG) Log.d(TAG, "constructor");
- mContext = context;
- mAppWidgetService = IAppWidgetService.Stub.asInterface(
- ServiceManager.getService(Context.APPWIDGET_SERVICE));
+ mLauncherApps = context.getSystemService(LauncherApps.class);
+ mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
+ mPeopleManager = mContext.getSystemService(PeopleManager.class);
}
/**
* AppWidgetManager setter used for testing.
*/
@VisibleForTesting
- protected void setAppWidgetManager(IAppWidgetService appWidgetService,
- AppWidgetManager appWidgetManager, IPeopleManager peopleManager) {
- mAppWidgetService = appWidgetService;
+ protected void setAppWidgetManager(
+ AppWidgetManager appWidgetManager, IPeopleManager iPeopleManager,
+ PeopleManager peopleManager, LauncherApps launcherApps) {
mAppWidgetManager = appWidgetManager;
+ mIPeopleManager = iPeopleManager;
mPeopleManager = peopleManager;
+ mLauncherApps = launcherApps;
}
/**
* Updates People Space widgets.
*/
- public void updateWidgets() {
+ public void updateWidgets(int[] widgetIds) {
try {
if (DEBUG) Log.d(TAG, "updateWidgets called");
- int[] widgetIds = mAppWidgetService.getAppWidgetIds(
- new ComponentName(mContext, PeopleSpaceWidgetProvider.class)
- );
if (widgetIds.length == 0) {
if (DEBUG) Log.d(TAG, "no widgets to update");
return;
@@ -103,14 +120,11 @@
if (DEBUG) Log.d(TAG, "updating " + widgetIds.length + " widgets");
boolean showSingleConversation = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
-
if (showSingleConversation) {
- PeopleSpaceUtils.updateSingleConversationWidgets(mContext, widgetIds,
- mAppWidgetManager, mPeopleManager);
- } else {
- mAppWidgetService
- .notifyAppWidgetViewDataChanged(mContext.getOpPackageName(), widgetIds,
- R.id.widget_list_view);
+ synchronized (mLock) {
+ PeopleSpaceUtils.updateSingleConversationWidgets(mContext, widgetIds,
+ mAppWidgetManager, mIPeopleManager);
+ }
}
} catch (Exception e) {
Log.e(TAG, "Exception: " + e);
@@ -121,9 +135,9 @@
* Check if any existing People tiles match the incoming notification change, and store the
* change in the tile if so.
*/
- public void updateWidgetWithNotificationChanged(StatusBarNotification sbn,
+ public void updateWidgetsWithNotificationChanged(StatusBarNotification sbn,
PeopleSpaceUtils.NotificationAction notificationAction) {
- if (DEBUG) Log.d(TAG, "updateWidgetWithNotificationChanged called");
+ if (DEBUG) Log.d(TAG, "updateWidgetsWithNotificationChanged called");
boolean showSingleConversation = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
if (!showSingleConversation) {
@@ -135,26 +149,22 @@
if (DEBUG) Log.d(TAG, "Sbn shortcut id is null");
return;
}
- int[] widgetIds = mAppWidgetService.getAppWidgetIds(
+ int[] widgetIds = mAppWidgetManager.getAppWidgetIds(
new ComponentName(mContext, PeopleSpaceWidgetProvider.class)
);
if (widgetIds.length == 0) {
Log.d(TAG, "No app widget ids returned");
return;
}
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
- int userId = UserHandle.getUserHandleForUid(sbn.getUid()).getIdentifier();
- String key = PeopleSpaceUtils.getKey(sbnShortcutId, sbn.getPackageName(), userId);
- Set<String> storedWidgetIds = new HashSet<>(sp.getStringSet(key, new HashSet<>()));
- if (storedWidgetIds.isEmpty()) {
- Log.d(TAG, "No stored widget ids");
- return;
- }
- for (String widgetIdString : storedWidgetIds) {
- int widgetId = Integer.parseInt(widgetIdString);
- if (DEBUG) Log.d(TAG, "Storing notification change, key:" + sbn.getKey());
- PeopleSpaceUtils.updateWidgetWithNotificationChanged(mPeopleManager, mContext,
- sbn, notificationAction, mAppWidgetManager, widgetId);
+ synchronized (mLock) {
+ Set<String> storedWidgetIds = getStoredWidgetIds(mSharedPrefs, sbnShortcutId,
+ sbn.getPackageName(),
+ UserHandle.getUserHandleForUid(sbn.getUid()).getIdentifier());
+ for (String widgetIdString : storedWidgetIds) {
+ int widgetId = Integer.parseInt(widgetIdString);
+ if (DEBUG) Log.d(TAG, "Storing notification change, key:" + sbn.getKey());
+ updateStorageAndViewWithNotificationData(sbn, notificationAction, widgetId);
+ }
}
} catch (Exception e) {
Log.e(TAG, "Exception: " + e);
@@ -162,6 +172,91 @@
}
/**
+ * Update the tiles associated with the incoming conversation update.
+ */
+ public void updateWidgetsWithConversationChanged(ConversationChannel conversation) {
+ ShortcutInfo info = conversation.getShortcutInfo();
+ synchronized (mLock) {
+ Set<String> storedWidgetIds = getStoredWidgetIds(mSharedPrefs, info.getId(),
+ info.getPackage(),
+ info.getUserId());
+ for (String widgetIdString : storedWidgetIds) {
+ if (DEBUG) {
+ Log.d(TAG,
+ "Conversation update for widget " + widgetIdString + " , "
+ + info.getLabel());
+ }
+ updateStorageAndViewWithConversationData(conversation,
+ Integer.valueOf(widgetIdString));
+ }
+ }
+ }
+
+ /**
+ * Update {@code appWidgetId} with the new data provided by {@code conversation}.
+ */
+ private void updateStorageAndViewWithConversationData(ConversationChannel conversation,
+ int appWidgetId) {
+ PeopleSpaceTile storedTile = getPeopleSpaceTile(mIPeopleManager, mAppWidgetManager,
+ mContext,
+ appWidgetId);
+ if (storedTile == null) {
+ if (DEBUG) Log.d(TAG, "Could not find stored tile to add conversation to");
+ return;
+ }
+ ShortcutInfo info = conversation.getShortcutInfo();
+ Uri uri = null;
+ if (info.getPersons() != null && info.getPersons().length > 0) {
+ Person person = info.getPersons()[0];
+ uri = person.getUri() == null ? null : Uri.parse(person.getUri());
+ }
+ storedTile = storedTile.toBuilder()
+ .setUserName(info.getLabel())
+ .setUserIcon(
+ PeopleSpaceTile.convertDrawableToIcon(mLauncherApps.getShortcutIconDrawable(
+ info, 0))
+ )
+ .setContactUri(uri)
+ .setStatuses(conversation.getStatuses())
+ .setLastInteractionTimestamp(conversation.getLastEventTimestamp())
+ .setIsImportantConversation(conversation.getParentNotificationChannel() != null
+ && conversation.getParentNotificationChannel().isImportantConversation())
+ .build();
+ updateAppWidgetOptionsAndView(mAppWidgetManager, mContext, appWidgetId, storedTile);
+ }
+
+ /**
+ * Update {@code appWidgetId} with the new data provided by {@code sbn}.
+ */
+ private void updateStorageAndViewWithNotificationData(
+ StatusBarNotification sbn,
+ PeopleSpaceUtils.NotificationAction notificationAction,
+ int appWidgetId) {
+ PeopleSpaceTile storedTile = getPeopleSpaceTile(mIPeopleManager, mAppWidgetManager,
+ mContext,
+ appWidgetId);
+ if (storedTile == null) {
+ if (DEBUG) Log.d(TAG, "Could not find stored tile to add notification to");
+ return;
+ }
+ if (notificationAction == PeopleSpaceUtils.NotificationAction.POSTED) {
+ if (DEBUG) Log.i(TAG, "Adding notification to storage, appWidgetId: " + appWidgetId);
+ storedTile = augmentTileFromNotification(mContext, storedTile, sbn);
+ } else {
+ if (DEBUG) {
+ Log.i(TAG, "Removing notification from storage, appWidgetId: " + appWidgetId);
+ }
+ storedTile = storedTile
+ .toBuilder()
+ .setNotificationKey(null)
+ .setNotificationContent(null)
+ .setNotificationDataUri(null)
+ .build();
+ }
+ updateAppWidgetOptionsAndView(mAppWidgetManager, mContext, appWidgetId, storedTile);
+ }
+
+ /**
* Attaches the manager to the pipeline, making it ready to receive events. Should only be
* called once.
*/
@@ -174,8 +269,7 @@
@Override
public void onNotificationPosted(
StatusBarNotification sbn, NotificationListenerService.RankingMap rankingMap) {
- if (DEBUG) Log.d(TAG, "onNotificationPosted");
- updateWidgetWithNotificationChanged(sbn, PeopleSpaceUtils.NotificationAction.POSTED);
+ updateWidgetsWithNotificationChanged(sbn, PeopleSpaceUtils.NotificationAction.POSTED);
}
@Override
@@ -183,8 +277,7 @@
StatusBarNotification sbn,
NotificationListenerService.RankingMap rankingMap
) {
- if (DEBUG) Log.d(TAG, "onNotificationRemoved");
- updateWidgetWithNotificationChanged(sbn, PeopleSpaceUtils.NotificationAction.REMOVED);
+ updateWidgetsWithNotificationChanged(sbn, PeopleSpaceUtils.NotificationAction.REMOVED);
}
@Override
@@ -192,8 +285,7 @@
StatusBarNotification sbn,
NotificationListenerService.RankingMap rankingMap,
int reason) {
- if (DEBUG) Log.d(TAG, "onNotificationRemoved with reason " + reason);
- updateWidgetWithNotificationChanged(sbn, PeopleSpaceUtils.NotificationAction.REMOVED);
+ updateWidgetsWithNotificationChanged(sbn, PeopleSpaceUtils.NotificationAction.REMOVED);
}
@Override
@@ -204,7 +296,6 @@
@Override
public void onNotificationsInitialized() {
if (DEBUG) Log.d(TAG, "onNotificationsInitialized");
- updateWidgets();
}
@Override
@@ -213,11 +304,131 @@
UserHandle user,
NotificationChannel channel,
int modificationType) {
- if (DEBUG) Log.d(TAG, "onNotificationChannelModified");
if (channel.isConversation()) {
- updateWidgets();
+ updateWidgets(mAppWidgetManager.getAppWidgetIds(
+ new ComponentName(mContext, PeopleSpaceWidgetProvider.class)
+ ));
}
}
};
-}
\ No newline at end of file
+ /** Adds {@code tile} mapped to {@code appWidgetId}. */
+ public void addNewWidget(PeopleSpaceTile tile, int appWidgetId) {
+ mUiEventLogger.log(PeopleSpaceUtils.PeopleSpaceWidgetEvent.PEOPLE_SPACE_WIDGET_ADDED);
+ synchronized (mLock) {
+ if (DEBUG) Log.d(TAG, "Add storage for : " + tile.getUserName());
+ PeopleSpaceUtils.setStorageForTile(mContext, tile, appWidgetId);
+ }
+ try {
+ if (DEBUG) Log.d(TAG, "Caching shortcut for PeopleTile: " + tile.getId());
+ mLauncherApps.cacheShortcuts(tile.getPackageName(),
+ Collections.singletonList(tile.getId()),
+ tile.getUserHandle(), LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS);
+ } catch (Exception e) {
+ Log.w(TAG, "Exception caching shortcut:" + e);
+ }
+ PeopleSpaceWidgetProvider provider = new PeopleSpaceWidgetProvider();
+ provider.onUpdate(mContext, mAppWidgetManager, new int[]{appWidgetId});
+ }
+
+ /** Registers a conversation listener for {@code appWidgetId} if not already registered. */
+ public void registerConversationListenerIfNeeded(int widgetId,
+ PeopleSpaceWidgetProvider.TileConversationListener newListener) {
+ // Retrieve storage needed for registration.
+ String packageName;
+ String shortcutId;
+ int userId;
+ String key;
+ synchronized (mLock) {
+ SharedPreferences widgetSp = mContext.getSharedPreferences(String.valueOf(widgetId),
+ Context.MODE_PRIVATE);
+ packageName = widgetSp.getString(PACKAGE_NAME, null);
+ shortcutId = widgetSp.getString(SHORTCUT_ID, null);
+ userId = widgetSp.getInt(USER_ID, INVALID_USER_ID);
+ key = PeopleSpaceUtils.getKey(shortcutId, packageName, userId);
+ if (key == null) {
+ if (DEBUG) Log.e(TAG, "Could not register " + widgetId);
+ return;
+ }
+ }
+ synchronized (mListeners) {
+ if (mListeners.containsKey(key)) {
+ if (DEBUG) Log.d(TAG, "Already registered listener");
+ return;
+ }
+ if (DEBUG) Log.d(TAG, "Register listener for " + widgetId + " with " + key);
+ mListeners.put(key, newListener);
+ }
+ mPeopleManager.registerConversationListener(packageName,
+ userId,
+ shortcutId, newListener,
+ mContext.getMainExecutor());
+ }
+
+ /** Deletes all storage, listeners, and caching for {@code appWidgetIds}. */
+ public void deleteWidgets(int[] appWidgetIds) {
+ for (int widgetId : appWidgetIds) {
+ if (DEBUG) Log.d(TAG, "Widget removed: " + widgetId);
+ mUiEventLogger.log(PeopleSpaceUtils.PeopleSpaceWidgetEvent.PEOPLE_SPACE_WIDGET_DELETED);
+ // Retrieve storage needed for widget deletion.
+ String packageName;
+ String shortcutId;
+ int userId;
+ String key;
+ Set<String> storedWidgetIdsForKey;
+ synchronized (mLock) {
+ SharedPreferences widgetSp = mContext.getSharedPreferences(String.valueOf(widgetId),
+ Context.MODE_PRIVATE);
+ packageName = widgetSp.getString(PACKAGE_NAME, null);
+ shortcutId = widgetSp.getString(SHORTCUT_ID, null);
+ userId = widgetSp.getInt(USER_ID, INVALID_USER_ID);
+ key = PeopleSpaceUtils.getKey(shortcutId, packageName, userId);
+ if (key == null) {
+ if (DEBUG) Log.e(TAG, "Could not delete " + widgetId);
+ return;
+ }
+ storedWidgetIdsForKey = new HashSet<>(
+ mSharedPrefs.getStringSet(key, new HashSet<>()));
+ }
+ synchronized (mLock) {
+ PeopleSpaceUtils.removeStorageForTile(mContext, key, widgetId);
+ }
+ // If another tile with the conversation is still stored, we need to keep the listener.
+ if (DEBUG) Log.d(TAG, "Stored widget IDs: " + storedWidgetIdsForKey.toString());
+ if (storedWidgetIdsForKey.contains(String.valueOf(widgetId))
+ && storedWidgetIdsForKey.size() == 1) {
+ if (DEBUG) Log.d(TAG, "Remove caching and listener");
+ unregisterConversationListener(key, widgetId);
+ uncacheConversationShortcut(shortcutId, packageName, userId);
+ }
+ }
+ }
+
+ /** Unregisters the conversation listener for {@code appWidgetId}. */
+ private void unregisterConversationListener(String key, int appWidgetId) {
+ PeopleSpaceWidgetProvider.TileConversationListener registeredListener;
+ synchronized (mListeners) {
+ registeredListener = mListeners.get(key);
+ if (registeredListener == null) {
+ if (DEBUG) Log.d(TAG, "Cannot find listener to unregister");
+ return;
+ }
+ if (DEBUG) Log.d(TAG, "Unregister listener for " + appWidgetId + " with " + key);
+ mListeners.remove(key);
+ }
+ mPeopleManager.unregisterConversationListener(registeredListener);
+ }
+
+ /** Uncaches the conversation shortcut. */
+ private void uncacheConversationShortcut(String shortcutId, String packageName, int userId) {
+ try {
+ if (DEBUG) Log.d(TAG, "Uncaching shortcut for PeopleTile: " + shortcutId);
+ mLauncherApps.uncacheShortcuts(packageName,
+ Collections.singletonList(shortcutId),
+ UserHandle.of(userId),
+ LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS);
+ } catch (Exception e) {
+ Log.d(TAG, "Exception uncaching shortcut:" + e);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java
index 90baf56..c0c1847 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java
@@ -16,31 +16,17 @@
package com.android.systemui.people.widget;
-import static com.android.systemui.people.PeopleSpaceUtils.PACKAGE_NAME;
-import static com.android.systemui.people.PeopleSpaceUtils.SHORTCUT_ID;
-import static com.android.systemui.people.PeopleSpaceUtils.USER_ID;
-
-import android.app.PendingIntent;
-import android.app.people.IPeopleManager;
+import android.annotation.NonNull;
+import android.app.people.ConversationChannel;
+import android.app.people.PeopleManager;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.LauncherApps;
-import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.provider.Settings;
import android.util.Log;
-import android.widget.RemoteViews;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.UiEventLoggerImpl;
-import com.android.systemui.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.people.PeopleSpaceUtils;
-import java.util.Collections;
-
/** People Space Widget Provider class. */
public class PeopleSpaceWidgetProvider extends AppWidgetProvider {
private static final String TAG = "PeopleSpaceWidgetPvd";
@@ -50,7 +36,26 @@
public static final String EXTRA_PACKAGE_NAME = "extra_package_name";
public static final String EXTRA_USER_HANDLE = "extra_user_handle";
- public UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
+ public PeopleSpaceWidgetManager peopleSpaceWidgetManager;
+
+ /** Listener for the shortcut data changes. */
+ public class TileConversationListener implements PeopleManager.ConversationListener {
+
+ @Override
+ public void onConversationUpdate(@NonNull ConversationChannel conversation) {
+ if (DEBUG) {
+ Log.d(TAG,
+ "Received updated conversation: "
+ + conversation.getShortcutInfo().getLabel());
+ }
+ if (peopleSpaceWidgetManager == null) {
+ // This shouldn't happen since onUpdate is called at reboot.
+ Log.e(TAG, "Skipping conversation update: WidgetManager uninitialized");
+ return;
+ }
+ peopleSpaceWidgetManager.updateWidgetsWithConversationChanged(conversation);
+ }
+ }
/** Called when widget updates. */
@Override
@@ -58,70 +63,32 @@
super.onUpdate(context, appWidgetManager, appWidgetIds);
if (DEBUG) Log.d(TAG, "onUpdate called");
- boolean showSingleConversation = Settings.Global.getInt(context.getContentResolver(),
- Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
- if (showSingleConversation) {
- PeopleSpaceUtils.updateSingleConversationWidgets(context, appWidgetIds,
- appWidgetManager, IPeopleManager.Stub.asInterface(
- ServiceManager.getService(Context.PEOPLE_SERVICE)));
- return;
- }
- // Perform this loop procedure for each App Widget that belongs to this provider
+ ensurePeopleSpaceWidgetManagerInitialized(context);
+ peopleSpaceWidgetManager.updateWidgets(appWidgetIds);
for (int appWidgetId : appWidgetIds) {
- RemoteViews views =
- new RemoteViews(context.getPackageName(), R.layout.people_space_widget);
+ PeopleSpaceWidgetProvider.TileConversationListener
+ newListener = new PeopleSpaceWidgetProvider.TileConversationListener();
+ peopleSpaceWidgetManager.registerConversationListenerIfNeeded(appWidgetId,
+ newListener);
+ }
+ return;
+ }
- Intent intent = new Intent(context, PeopleSpaceWidgetService.class);
- intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
- views.setRemoteAdapter(R.id.widget_list_view, intent);
-
- Intent activityIntent = new Intent(context, LaunchConversationActivity.class);
- activityIntent.addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_CLEAR_TASK
- | Intent.FLAG_ACTIVITY_NO_HISTORY
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- PendingIntent pendingIntent = PendingIntent.getActivity(
- context,
- appWidgetId,
- activityIntent,
- PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
- views.setPendingIntentTemplate(R.id.widget_list_view, pendingIntent);
-
- // Tell the AppWidgetManager to perform an update on the current app widget
- appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_list_view);
- appWidgetManager.updateAppWidget(appWidgetId, views);
+ private void ensurePeopleSpaceWidgetManagerInitialized(Context context) {
+ if (peopleSpaceWidgetManager == null) {
+ peopleSpaceWidgetManager = new PeopleSpaceWidgetManager(context);
}
}
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
- LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
+ ensurePeopleSpaceWidgetManagerInitialized(context);
+ peopleSpaceWidgetManager.deleteWidgets(appWidgetIds);
+ }
- for (int widgetId : appWidgetIds) {
- if (DEBUG) Log.d(TAG, "Widget removed");
- mUiEventLogger.log(PeopleSpaceUtils.PeopleSpaceWidgetEvent.PEOPLE_SPACE_WIDGET_DELETED);
- if (launcherApps != null) {
- SharedPreferences widgetSp = context.getSharedPreferences(String.valueOf(widgetId),
- Context.MODE_PRIVATE);
- String packageName = widgetSp.getString(PACKAGE_NAME, null);
- String shortcutId = widgetSp.getString(SHORTCUT_ID, null);
- int userId = widgetSp.getInt(USER_ID, -1);
-
- if (packageName != null && shortcutId != null && userId != -1) {
- try {
- if (DEBUG) Log.d(TAG, "Uncaching shortcut for PeopleTile: " + shortcutId);
- launcherApps.uncacheShortcuts(packageName,
- Collections.singletonList(shortcutId),
- UserHandle.of(userId),
- LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS);
- } catch (Exception e) {
- Log.d(TAG, "Exception uncaching shortcut:" + e);
- }
- }
- }
- PeopleSpaceUtils.removeStorageForTile(context, widgetId);
- }
+ @VisibleForTesting
+ public void setPeopleSpaceWidgetManager(PeopleSpaceWidgetManager manager) {
+ peopleSpaceWidgetManager = manager;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
index 7679d48..8ec9b68 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
@@ -47,7 +47,7 @@
context: Context,
private val list: List<PrivacyElement>,
activityStarter: (String, Int) -> Unit
-) : SystemUIDialog(context, R.style.ScreenRecord) {
+) : SystemUIDialog(context, R.style.PrivacyDialog) {
private val dismissListeners = mutableListOf<WeakReference<OnDialogDismissed>>()
private val dismissed = AtomicBoolean(false)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
index 38e2ba4..33ca7d6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
@@ -259,23 +259,30 @@
mIcon.setIcon(state, allowAnimations);
setContentDescription(state.contentDescription);
final StringBuilder stateDescription = new StringBuilder();
+ String text = "";
switch (state.state) {
case Tile.STATE_UNAVAILABLE:
- stateDescription.append(mContext.getString(R.string.tile_unavailable));
+ text = mContext.getString(R.string.tile_unavailable);
break;
case Tile.STATE_INACTIVE:
if (state instanceof QSTile.BooleanState) {
- stateDescription.append(mContext.getString(R.string.switch_bar_off));
+ text = mContext.getString(R.string.switch_bar_off);
}
break;
case Tile.STATE_ACTIVE:
if (state instanceof QSTile.BooleanState) {
- stateDescription.append(mContext.getString(R.string.switch_bar_on));
+ text = mContext.getString(R.string.switch_bar_on);
}
break;
default:
break;
}
+ if (!TextUtils.isEmpty(text)) {
+ stateDescription.append(text);
+ if (TextUtils.isEmpty(state.secondaryLabel)) {
+ state.secondaryLabel = text;
+ }
+ }
if (!TextUtils.isEmpty(state.stateDescription)) {
stateDescription.append(", ");
stateDescription.append(state.stateDescription);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 5b2a7e7..a87bfd8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -85,6 +85,7 @@
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.recents.ISplitScreenListener;
+import com.android.systemui.shared.recents.IStartingWindowListener;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -101,6 +102,7 @@
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.splitscreen.SplitScreen;
+import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.transition.RemoteTransitions;
import java.io.FileDescriptor;
@@ -150,6 +152,7 @@
private final Optional<OneHanded> mOneHandedOptional;
private final CommandQueue mCommandQueue;
private final RemoteTransitions mShellTransitions;
+ private final Optional<StartingSurface> mStartingSurface;
private Region mActiveNavBarRegion;
@@ -167,6 +170,7 @@
private boolean mSupportsRoundedCornersOnWindows;
private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
private final ArraySet<IRemoteTransition> mRemoteTransitions = new ArraySet<>();
+ private IStartingWindowListener mIStartingWindowListener;
@VisibleForTesting
public ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
@@ -440,6 +444,21 @@
}
@Override
+ public void setStartingWindowListener(IStartingWindowListener listener) {
+ if (!verifyCaller("setStartingWindowListener")) {
+ return;
+ }
+ mIStartingWindowListener = listener;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mStartingSurface.ifPresent(s ->
+ s.setStartingWindowListener(mStartingWindowListener));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
public void onQuickSwitchToNewTask(@Surface.Rotation int rotation) {
if (!verifyCaller("onQuickSwitchToNewTask")) {
return;
@@ -662,14 +681,29 @@
}
@Override
- public void startIntent(PendingIntent intent, int stage, int position, Bundle options) {
+ public void startIntent(PendingIntent intent, Intent fillInIntent,
+ int stage, int position, Bundle options) {
if (!verifyCaller("startIntent")) {
return;
}
final long token = Binder.clearCallingIdentity();
try {
mSplitScreenOptional.ifPresent(s ->
- s.startIntent(intent, stage, position, options));
+ s.startIntent(intent, mContext, fillInIntent, stage, position, options));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void removeFromSideStage(int taskId) {
+ if (!verifyCaller("removeFromSideStage")) {
+ return;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mSplitScreenOptional.ifPresent(
+ s -> s.removeFromSideStage(taskId));
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -770,6 +804,9 @@
private final Consumer<Boolean> mPinnedStackAnimationCallback =
this::notifyPinnedStackAnimationStarted;
+ private final BiConsumer<Integer, Integer> mStartingWindowListener =
+ this::notifyTaskLaunching;
+
// This is the death handler for the binder from the launcher service
private final IBinder.DeathRecipient mOverviewServiceDeathRcpt
= this::cleanupAfterDeath;
@@ -789,10 +826,10 @@
}
@Override
- public void onTaskStageChanged(int taskId, int stage) {
+ public void onTaskStageChanged(int taskId, int stage, boolean visible) {
try {
if (mISplitScreenListener != null) {
- mISplitScreenListener.onTaskStageChanged(taskId, stage);
+ mISplitScreenListener.onTaskStageChanged(taskId, stage, visible);
}
} catch (RemoteException e) {
Log.e(TAG_OPS, "onTaskStageChanged", e);
@@ -812,7 +849,8 @@
Optional<Lazy<StatusBar>> statusBarOptionalLazy,
Optional<OneHanded> oneHandedOptional,
BroadcastDispatcher broadcastDispatcher,
- RemoteTransitions shellTransitions) {
+ RemoteTransitions shellTransitions,
+ Optional<StartingSurface> startingSurface) {
super(broadcastDispatcher);
mContext = context;
mPipOptional = pipOptional;
@@ -872,6 +910,7 @@
// Connect to the service
updateEnabledState();
startConnectionToCurrentUser();
+ mStartingSurface = startingSurface;
}
@Override
@@ -938,6 +977,18 @@
}
}
+ private void notifyTaskLaunching(int taskId, int supportedType) {
+ if (mIStartingWindowListener == null) {
+ return;
+ }
+
+ try {
+ mIStartingWindowListener.onTaskLaunching(taskId, supportedType);
+ } catch (RemoteException e) {
+ Log.e(TAG_OPS, "Failed to call notifyTaskLaunching()", e);
+ }
+ }
+
private void onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded,
boolean bouncerShowing) {
mSysUiState.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 1975821..bd46ffe 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -351,7 +351,8 @@
Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_screenrecord)
- .setContentTitle(getResources().getString(R.string.screenrecord_save_message))
+ .setContentTitle(getResources().getString(R.string.screenrecord_save_title))
+ .setContentText(getResources().getString(R.string.screenrecord_save_text))
.setContentIntent(PendingIntent.getActivity(
this,
REQUEST_CODE,
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
index 6cdf6ab..58a54f6 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java
@@ -82,7 +82,7 @@
dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE);
if (intent != null) {
final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
- mContext, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED, null, UserHandle.CURRENT);
+ mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE, null, UserHandle.CURRENT);
b.setContentIntent(pendingIntent);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index d2ddd21..5e8245f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -527,7 +527,7 @@
handleCustomTransformHeight(view, expandingAnimated, iconState);
float fullTransitionAmount;
- float transitionAmount;
+ float iconTransitionAmount;
float contentTransformationAmount;
float shelfStart = getTranslationY();
boolean fullyInOrOut = true;
@@ -549,18 +549,19 @@
fullTransitionAmount = 1.0f - interpolatedAmount;
if (isLastChild) {
- // If it's the last child we should use all of the notification to transform
- // instead of just to the icon, since that can be quite low.
- transitionAmount = (shelfStart - viewStart) / transformDistance;
+ // Reduce icon transform distance to completely fade in shelf icon
+ // by the time the notification icon fades out, and vice versa
+ iconTransitionAmount = (shelfStart - viewStart)
+ / (iconTransformStart - viewStart);
} else {
- transitionAmount = (shelfStart - iconTransformStart) / transformDistance;
+ iconTransitionAmount = (shelfStart - iconTransformStart) / transformDistance;
}
- transitionAmount = MathUtils.constrain(transitionAmount, 0.0f, 1.0f);
- transitionAmount = 1.0f - transitionAmount;
+ iconTransitionAmount = MathUtils.constrain(iconTransitionAmount, 0.0f, 1.0f);
+ iconTransitionAmount = 1.0f - iconTransitionAmount;
fullyInOrOut = false;
} else {
fullTransitionAmount = 1.0f;
- transitionAmount = 1.0f;
+ iconTransitionAmount = 1.0f;
}
// Transforming the content
@@ -569,7 +570,7 @@
contentTransformationAmount = 1.0f - contentTransformationAmount;
} else {
fullTransitionAmount = 0.0f;
- transitionAmount = 0.0f;
+ iconTransitionAmount = 0.0f;
contentTransformationAmount = 0.0f;
}
if (iconState != null && fullyInOrOut && !expandingAnimated && iconState.isLastExpandIcon) {
@@ -585,7 +586,7 @@
view.setContentTransformationAmount(contentTransformationAmount, isLastChild);
// Update the positioning of the icon
- updateIconPositioning(view, transitionAmount, fullTransitionAmount,
+ updateIconPositioning(view, iconTransitionAmount, fullTransitionAmount,
transformDistance, scrolling, scrollingFast, expandingAnimated, isLastChild);
return fullTransitionAmount;
@@ -679,8 +680,7 @@
|| iconState.useLinearTransitionAmount) {
transitionAmount = iconTransitionAmount;
} else {
- // We take the clamped position instead
- transitionAmount = clampedAmount;
+ transitionAmount = iconTransitionAmount;
iconState.needsCannedAnimation = iconState.clampedAppearAmount != clampedAmount
&& !mNoAnimationsInThisFrame;
}
@@ -689,8 +689,7 @@
? fullTransitionAmount
: transitionAmount;
iconState.clampedAppearAmount = clampedAmount;
- setIconTransformationAmount(view, transitionAmount, iconTransformDistance,
- clampedAmount != transitionAmount, isLastChild);
+ setIconTransformationAmount(view, transitionAmount, isLastChild);
}
private boolean isTargetClipped(ExpandableView view) {
@@ -708,7 +707,7 @@
}
private void setIconTransformationAmount(ExpandableView view,
- float transitionAmount, float iconTransformDistance, boolean usingLinearInterpolation,
+ float transitionAmount,
boolean isLastChild) {
if (!(view instanceof ExpandableNotificationRow)) {
return;
@@ -720,42 +719,13 @@
View rowIcon = row.getShelfTransformationTarget();
// Let's resolve the relative positions of the icons
- float notificationIconSize = 0.0f;
- int iconTopPadding;
int iconStartPadding;
if (rowIcon != null) {
- iconTopPadding = row.getRelativeTopPadding(rowIcon);
iconStartPadding = row.getRelativeStartPadding(rowIcon);
- notificationIconSize = rowIcon.getHeight();
} else {
- iconTopPadding = mIconAppearTopPadding;
iconStartPadding = 0;
}
-
- float shelfIconSize = mAmbientState.isFullyHidden() ? mHiddenShelfIconSize : mIconSize;
- shelfIconSize = shelfIconSize * icon.getIconScale();
-
- // Get the icon correctly positioned in Y
- float notificationIconPositionY = row.getTranslationY() + row.getContentTranslation();
- float targetYPosition = 0;
boolean stayingInShelf = row.isInShelf() && !row.isTransformingIntoShelf();
- if (usingLinearInterpolation && !stayingInShelf) {
- // If we interpolate from the notification position, this might lead to a slightly
- // odd interpolation, since the notification position changes as well.
- // Let's instead interpolate directly to the top left of the notification
- targetYPosition = NotificationUtils.interpolate(
- Math.min(notificationIconPositionY + mIconAppearTopPadding
- - getTranslationY(), 0),
- 0,
- transitionAmount);
- }
- notificationIconPositionY += iconTopPadding;
- float shelfIconPositionY = getTranslationY() + icon.getTop();
- shelfIconPositionY += (icon.getHeight() - shelfIconSize) / 2.0f;
- float iconYTranslation = NotificationUtils.interpolate(
- notificationIconPositionY - shelfIconPositionY,
- targetYPosition,
- transitionAmount);
// Get the icon correctly positioned in X
// Even in RTL it's the left, since we're inverting the location in post
@@ -767,28 +737,19 @@
transitionAmount);
// Let's handle the case that there's no Icon
- float alpha = 1.0f;
boolean noIcon = !row.isShowingIcon();
if (noIcon) {
// The view currently doesn't have an icon, lets transform it in!
- alpha = transitionAmount;
- notificationIconSize = shelfIconSize / 2.0f;
iconXTranslation = mShelfIcons.getActualPaddingStart();
}
- // The notification size is different from the size in the shelf / statusbar
- float newSize = NotificationUtils.interpolate(notificationIconSize, shelfIconSize,
- transitionAmount);
if (iconState != null) {
- iconState.scaleX = newSize / shelfIconSize;
- iconState.scaleY = iconState.scaleX;
iconState.hidden = transitionAmount == 0.0f && !iconState.isAnimating(icon);
boolean isAppearing = row.isDrawingAppearAnimation() && !row.isInShelf();
if (isAppearing) {
iconState.hidden = true;
iconState.iconAppearAmount = 0.0f;
}
- iconState.alpha = alpha;
- iconState.yTranslation = iconYTranslation;
+ iconState.alpha = transitionAmount;
iconState.xTranslation = iconXTranslation;
if (stayingInShelf) {
iconState.iconAppearAmount = 1.0f;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
index d1ab7ea..004cf99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
@@ -180,9 +180,6 @@
}
if (changed) {
notificationGroupManager.updateIsolation(entry)
- // ensure that the conversation icon isn't hidden
- // (ex: if it was showing in the shelf)
- entry.row?.updateIconVisibilities()
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 8a22b9f..dbd8580 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -176,7 +176,6 @@
private int mBucket = BUCKET_ALERTING;
@Nullable private Long mPendingAnimationDuration;
private boolean mIsMarkedForUserTriggeredMovement;
- private boolean mShelfIconVisible;
private boolean mIsAlerting;
public boolean mRemoteEditImeVisible;
@@ -417,7 +416,6 @@
//TODO: This will go away when we have a way to bind an entry to a row
public void setRow(ExpandableNotificationRow row) {
this.row = row;
- updateShelfIconVisibility();
}
public ExpandableNotificationRowController getRowController() {
@@ -938,19 +936,6 @@
return mIsMarkedForUserTriggeredMovement;
}
- /** Whether or not the icon for this notification is visible in the shelf. */
- public void setShelfIconVisible(boolean shelfIconVisible) {
- if (row == null) return;
- mShelfIconVisible = shelfIconVisible;
- updateShelfIconVisibility();
- }
-
- private void updateShelfIconVisibility() {
- if (row != null) {
- row.setShelfIconVisible(mShelfIconVisible);
- }
- }
-
/**
* Mark this entry for movement triggered by a user action (ex: changing the priorirty of a
* conversation). This can then be used for custom animations.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
index ba45f9a..5375ac3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
@@ -95,11 +95,6 @@
// Construct the shelf icon view.
val shelfIcon = iconBuilder.createIconView(entry)
shelfIcon.scaleType = ImageView.ScaleType.CENTER_INSIDE
-
- // TODO: This doesn't belong here
- shelfIcon.setOnVisibilityChangedListener { newVisibility: Int ->
- entry.setShelfIconVisible(newVisibility == View.VISIBLE)
- }
shelfIcon.visibility = View.INVISIBLE
// Construct the aod icon view.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 1251b58..0f23b77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -331,7 +331,6 @@
private boolean mHeadsupDisappearRunning;
private View mChildAfterViewWhenDismissed;
private View mGroupParentWhenDismissed;
- private boolean mShelfIconVisible;
private boolean mAboveShelf;
private OnUserInteractionCallback mOnUserInteractionCallback;
private NotificationGutsManager mNotificationGutsManager;
@@ -568,7 +567,6 @@
// The public layouts expand button is always visible
mPublicLayout.updateExpandButtons(true);
updateLimits();
- updateIconVisibilities();
updateShelfIconColor();
updateRippleAllowed();
if (mUpdateBackgroundOnUpdate) {
@@ -883,7 +881,6 @@
setDistanceToTopRoundness(NO_ROUNDNESS);
mNotificationParent.updateBackgroundForGroupState();
}
- updateIconVisibilities();
updateBackgroundClipping();
}
@@ -1481,21 +1478,6 @@
return getShelfTransformationTarget() != null;
}
- /**
- * Set the icons to be visible of this notification.
- */
- public void setShelfIconVisible(boolean iconVisible) {
- if (iconVisible != mShelfIconVisible) {
- mShelfIconVisible = iconVisible;
- updateIconVisibilities();
- }
- }
-
- @Override
- protected void onBelowSpeedBumpChanged() {
- updateIconVisibilities();
- }
-
@Override
protected void updateContentTransformation() {
if (mExpandAnimationRunning) {
@@ -1522,18 +1504,6 @@
}
}
- /** Refreshes the visibility of notification icons */
- public void updateIconVisibilities() {
- // The shelf icon is never hidden for children in groups
- boolean visible = !isChildInGroup() && mShelfIconVisible;
- for (NotificationContentView l : mLayouts) {
- l.setShelfIconVisible(visible);
- }
- if (mChildrenContainer != null) {
- mChildrenContainer.setShelfIconVisible(visible);
- }
- }
-
public void setIsLowPriority(boolean isLowPriority) {
mIsLowPriority = isLowPriority;
mPrivateLayout.setIsLowPriority(isLowPriority);
@@ -2052,8 +2022,7 @@
mNotificationLaunchHeight,
zProgress);
setTranslationZ(translationZ);
- float extraWidthForClipping = params.getWidth() - getWidth()
- + MathUtils.lerp(0, mOutlineRadius * 2, params.getProgress());
+ float extraWidthForClipping = params.getWidth() - getWidth();
setExtraWidthForClipping(extraWidthForClipping);
int top = params.getTop();
float interpolation = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(params.getProgress());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index b0b91bd..d3065aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -172,7 +172,6 @@
private int mContentHeightAtAnimationStart = UNDEFINED;
private boolean mFocusOnVisibilityChange;
private boolean mHeadsUpAnimatingAway;
- private boolean mShelfIconVisible;
private int mClipBottomAmount;
private boolean mIsLowPriority;
private boolean mIsContentExpandable;
@@ -877,10 +876,12 @@
public void setBackgroundTintColor(int color) {
if (mExpandedSmartReplyView != null) {
- mExpandedSmartReplyView.setBackgroundTintColor(color);
+ boolean colorized = mNotificationEntry.getSbn().getNotification().isColorized();
+ mExpandedSmartReplyView.setBackgroundTintColor(color, colorized);
}
if (mHeadsUpSmartReplyView != null) {
- mHeadsUpSmartReplyView.setBackgroundTintColor(color);
+ boolean colorized = mNotificationEntry.getSbn().getNotification().isColorized();
+ mHeadsUpSmartReplyView.setBackgroundTintColor(color, colorized);
}
}
@@ -1510,7 +1511,9 @@
smartReplyView.addPreInflatedButtons(
inflatedSmartReplyViewHolder.getSmartSuggestionButtons());
// Ensure the colors of the smart suggestion buttons are up-to-date.
- smartReplyView.setBackgroundTintColor(entry.getRow().getCurrentBackgroundTint());
+ int backgroundColor = entry.getRow().getCurrentBackgroundTint();
+ boolean colorized = mNotificationEntry.getSbn().getNotification().isColorized();
+ smartReplyView.setBackgroundTintColor(backgroundColor, colorized);
smartReplyContainer.setVisibility(View.VISIBLE);
}
return smartReplyView;
@@ -1739,23 +1742,6 @@
mFocusOnVisibilityChange = true;
}
- public void setShelfIconVisible(boolean iconsVisible) {
- mShelfIconVisible = iconsVisible;
- updateIconVisibilities();
- }
-
- private void updateIconVisibilities() {
- if (mContractedWrapper != null) {
- mContractedWrapper.setShelfIconVisible(mShelfIconVisible);
- }
- if (mHeadsUpWrapper != null) {
- mHeadsUpWrapper.setShelfIconVisible(mShelfIconVisible);
- }
- if (mExpandedWrapper != null) {
- mExpandedWrapper.setShelfIconVisible(mShelfIconVisible);
- }
- }
-
@Override
public void onVisibilityAggregated(boolean isVisible) {
super.onVisibilityAggregated(isVisible);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapper.java
index 7248bce..151840a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapper.java
@@ -44,9 +44,10 @@
private void updateImageTag(StatusBarNotification notification) {
final Bundle extras = notification.getNotification().extras;
- Icon overRiddenIcon = extras.getParcelable(Notification.EXTRA_LARGE_ICON_BIG);
- if (overRiddenIcon != null) {
- mPicture.setTag(ImageTransformState.ICON_TAG, overRiddenIcon);
+ Icon overriddenIcon = extras.getParcelable(Notification.EXTRA_LARGE_ICON_BIG);
+ if (overriddenIcon != null) {
+ mRightIcon.setTag(ImageTransformState.ICON_TAG, overriddenIcon);
+ mLeftIcon.setTag(ImageTransformState.ICON_TAG, overriddenIcon);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
index 905bccf..fb0fdcc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
@@ -132,20 +132,6 @@
)
}
- override fun setShelfIconVisible(visible: Boolean) {
- if (conversationLayout.isImportantConversation) {
- if (conversationIconView.visibility != View.GONE) {
- conversationIconView.isForceHidden = visible
- // We don't want the small icon to be hidden by the extended wrapper, as force
- // hiding the conversationIcon will already do that via its listener.
- return
- }
- } else {
- conversationIconView.isForceHidden = false
- }
- super.setShelfIconVisible(visible)
- }
-
override fun getShelfTransformationTarget(): View? =
if (conversationLayout.isImportantConversation)
if (conversationIconView.visibility != View.GONE)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index eb79e3c..bdafd23 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -313,12 +313,6 @@
}
@Override
- public void setShelfIconVisible(boolean visible) {
- super.setShelfIconVisible(visible);
- mIcon.setForceHidden(visible);
- }
-
- @Override
public TransformState getCurrentState(int fadingView) {
return mTransformationHelper.getCurrentState(fadingView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
index e9934c0..e0b5812 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
@@ -51,7 +51,8 @@
public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapper {
private final int mFullHeaderTranslation;
- protected ImageView mPicture;
+ protected ImageView mRightIcon;
+ protected ImageView mLeftIcon;
private ProgressBar mProgressBar;
private TextView mTitle;
private TextView mText;
@@ -140,9 +141,14 @@
}
private void resolveTemplateViews(StatusBarNotification notification) {
- mPicture = mView.findViewById(com.android.internal.R.id.right_icon);
- if (mPicture != null) {
- mPicture.setTag(ImageTransformState.ICON_TAG,
+ mRightIcon = mView.findViewById(com.android.internal.R.id.right_icon);
+ if (mRightIcon != null) {
+ mRightIcon.setTag(ImageTransformState.ICON_TAG,
+ notification.getNotification().getLargeIcon());
+ }
+ mLeftIcon = mView.findViewById(com.android.internal.R.id.left_icon);
+ if (mLeftIcon != null) {
+ mLeftIcon.setTag(ImageTransformState.ICON_TAG,
notification.getNotification().getLargeIcon());
}
mTitle = mView.findViewById(com.android.internal.R.id.title);
@@ -240,9 +246,9 @@
resolveTemplateViews(row.getEntry().getSbn());
super.onContentUpdated(row);
// With the modern templates, a large icon visually overlaps the header, so we can't
- // simply hide the header -- just show the
+ // hide the header, we must show it.
mCanHideHeader = mNotificationHeader != null
- && (mPicture == null || mPicture.getVisibility() != VISIBLE);
+ && (mRightIcon == null || mRightIcon.getVisibility() != VISIBLE);
if (row.getHeaderVisibleAmount() != DEFAULT_HEADER_VISIBLE_AMOUNT) {
setHeaderVisibleAmount(row.getHeaderVisibleAmount());
}
@@ -260,14 +266,15 @@
mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TEXT,
mText);
}
- if (mPicture != null) {
+ if (mRightIcon != null) {
mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_IMAGE,
- mPicture);
+ mRightIcon);
}
if (mProgressBar != null) {
mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_PROGRESS,
mProgressBar);
}
+ addViewsTransformingToSimilar(mLeftIcon);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 89babf0..9ced12d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -331,11 +331,6 @@
return null;
}
- /**
- * Set the shelf icon to be visible and hide our own icons.
- */
- public void setShelfIconVisible(boolean shelfIconVisible) {}
-
public int getHeaderTranslation(boolean forceNoHeader) {
return 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 756fe6c..8446b4e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -133,7 +133,7 @@
*/
public static int getNotificationLaunchHeight(Context context) {
int zDistance = getZDistanceBetweenElements(context);
- return getBaseHeight(zDistance) * 2;
+ return NOTIFICATIONS_HAVE_SHADOWS ? 2 * getBaseHeight(zDistance) : 4 * zDistance;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 3739424..d8ee102 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -1259,21 +1259,6 @@
return 0;
}
- public void setShelfIconVisible(boolean iconVisible) {
- if (mNotificationHeaderWrapper != null) {
- CachingIconView icon = mNotificationHeaderWrapper.getIcon();
- if (icon != null) {
- icon.setForceHidden(iconVisible);
- }
- }
- if (mNotificationHeaderWrapperLowPriority != null) {
- CachingIconView icon = mNotificationHeaderWrapperLowPriority.getIcon();
- if (icon != null) {
- icon.setForceHidden(iconVisible);
- }
- }
- }
-
public void setClipBottomAmount(int clipBottomAmount) {
mClipBottomAmount = clipBottomAmount;
updateChildrenClipping();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index bf36435..0807f8a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -4398,7 +4398,10 @@
*/
public static Bundle getActivityOptions(int displayId,
@Nullable RemoteAnimationAdapter animationAdapter) {
- return getDefaultActivityOptions(animationAdapter).toBundle();
+ ActivityOptions options = getDefaultActivityOptions(animationAdapter);
+ options.setLaunchDisplayId(displayId);
+ options.setCallerDisplayId(displayId);
+ return options.toBundle();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
index 38f3bc8..59c1138 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
@@ -94,15 +94,6 @@
goingToFullShade,
oldState);
}
-
- @Override
- public void onDozeAmountChanged(float linearAmount, float amount) {
- if (DEBUG) {
- Log.d(TAG, String.format("onDozeAmountChanged: linearAmount=%f amount=%f",
- linearAmount, amount));
- }
- setDarkAmount(amount);
- }
};
@Inject
@@ -294,20 +285,6 @@
}
}
- /**
- * Set the amount (ratio) that the device has transitioned to doze.
- *
- * @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake.
- */
- private void setDarkAmount(float darkAmount) {
- boolean isAwake = darkAmount != 0;
- if (darkAmount == mDarkAmount) {
- return;
- }
- mDarkAmount = darkAmount;
- mView.setVisibility(isAwake ? View.VISIBLE : View.GONE);
- }
-
private boolean isListAnimating() {
return mKeyguardVisibilityHelper.isVisibilityAnimating();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
index 8845a05..5a80c05 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -205,7 +205,7 @@
protected void onViewAttached() {
if (DEBUG) Log.d(TAG, "onViewAttached");
mAdapter.registerDataSetObserver(mDataSetObserver);
- mDataSetObserver.onChanged();
+ mAdapter.notifyDataSetChanged();
mKeyguardUpdateMonitor.registerCallback(mInfoCallback);
mStatusBarStateController.addCallback(mStatusBarStateListener);
mScreenLifecycle.addObserver(mScreenObserver);
@@ -373,14 +373,13 @@
* @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake.
*/
private void setDarkAmount(float darkAmount) {
- boolean isAwake = darkAmount != 0;
+ boolean isFullyDozed = darkAmount == 1;
if (darkAmount == mDarkAmount) {
return;
}
mDarkAmount = darkAmount;
mListView.setDarkAmount(darkAmount);
- mView.setVisibility(isAwake ? View.VISIBLE : View.GONE);
- if (!isAwake) {
+ if (isFullyDozed) {
closeSwitcherIfOpenAndNotSimple(false);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 738cab1..5638503 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -439,7 +439,7 @@
private final NetworkCallback mNetworkCallback = new NetworkCallback() {
@Override
public void onAvailable(Network network) {
- if (DEBUG) Log.d(TAG, "onAvailable " + network.netId);
+ if (DEBUG) Log.d(TAG, "onAvailable " + network.getNetId());
updateState();
fireCallbacks();
};
@@ -448,7 +448,7 @@
// how long the VPN connection is held on to.
@Override
public void onLost(Network network) {
- if (DEBUG) Log.d(TAG, "onLost " + network.netId);
+ if (DEBUG) Log.d(TAG, "onLost " + network.getNetId());
updateState();
fireCallbacks();
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index ad4fa64..edec618 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -92,6 +92,7 @@
@ColorInt private int mCurrentStrokeColor;
@ColorInt private int mCurrentTextColor;
@ColorInt private int mCurrentRippleColor;
+ private boolean mCurrentColorized;
private int mMaxSqueezeRemeasureAttempts;
private int mMaxNumActions;
private int mMinNumSystemGeneratedReplies;
@@ -143,7 +144,7 @@
mBreakIterator = BreakIterator.getLineInstance();
- setBackgroundTintColor(mDefaultBackgroundColor);
+ setBackgroundTintColor(mDefaultBackgroundColor, false /* colorized */);
reallocateCandidateButtonQueueForSqueezing();
}
@@ -182,7 +183,7 @@
public void resetSmartSuggestions(View newSmartReplyContainer) {
mSmartReplyContainer = newSmartReplyContainer;
removeAllViews();
- setBackgroundTintColor(mDefaultBackgroundColor);
+ setBackgroundTintColor(mDefaultBackgroundColor, false /* colorized */);
}
/** Add buttons to the {@link SmartReplyView} */
@@ -676,19 +677,24 @@
return lp.show && super.drawChild(canvas, child, drawingTime);
}
- public void setBackgroundTintColor(int backgroundColor) {
- if (backgroundColor == mCurrentBackgroundColor) {
+ /**
+ * Set the current background color of the notification so that the smart reply buttons can
+ * match it, and calculate other colors (e.g. text, ripple, stroke)
+ */
+ public void setBackgroundTintColor(int backgroundColor, boolean colorized) {
+ if (backgroundColor == mCurrentBackgroundColor && colorized == mCurrentColorized) {
// Same color ignoring.
return;
}
mCurrentBackgroundColor = backgroundColor;
+ mCurrentColorized = colorized;
final boolean dark = !ContrastColorUtil.isColorLight(backgroundColor);
mCurrentTextColor = ContrastColorUtil.ensureTextContrast(
dark ? mDefaultTextColorDarkBg : mDefaultTextColor,
backgroundColor | 0xff000000, dark);
- mCurrentStrokeColor = ContrastColorUtil.ensureContrast(
+ mCurrentStrokeColor = colorized ? mCurrentTextColor : ContrastColorUtil.ensureContrast(
mDefaultStrokeColor, backgroundColor | 0xff000000, dark, mMinStrokeContrast);
mCurrentRippleColor = dark ? mRippleColorDarkBg : mRippleColor;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 78cd3a82..d67bd76 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -328,12 +328,12 @@
@WMSingleton
@Provides
static Optional<OneHandedController> provideOneHandedController(Context context,
- DisplayController displayController, TaskStackListenerImpl taskStackListener,
- UiEventLogger uiEventLogger,
+ WindowManager windowManager, DisplayController displayController,
+ TaskStackListenerImpl taskStackListener, UiEventLogger uiEventLogger,
@ShellMainThread ShellExecutor mainExecutor,
@ShellMainThread Handler mainHandler) {
- return Optional.ofNullable(OneHandedController.create(context, displayController,
- taskStackListener, uiEventLogger, mainExecutor, mainHandler));
+ return Optional.ofNullable(OneHandedController.create(context, windowManager,
+ displayController, taskStackListener, uiEventLogger, mainExecutor, mainHandler));
}
//
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index fb778e8..f84aa59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -179,7 +179,7 @@
public void fingerDown() throws RemoteException {
// Configure UdfpsView to accept the ACTION_DOWN event
when(mUdfpsView.isIlluminationRequested()).thenReturn(false);
- when(mUdfpsView.isValidTouch(anyFloat(), anyFloat(), anyFloat())).thenReturn(true);
+ when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
// GIVEN that the overlay is showing
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
@@ -187,9 +187,12 @@
mFgExecutor.runAllReady();
// WHEN ACTION_DOWN is received
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
- MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
- mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
- event.recycle();
+ MotionEvent downEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+ downEvent.recycle();
+ MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+ moveEvent.recycle();
// THEN illumination begins
// AND onIlluminatedRunnable that notifies FingerprintManager is set
verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
index 800d859..f60fa09 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
@@ -19,14 +19,21 @@
import static android.app.Notification.CATEGORY_MISSED_CALL;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.people.ConversationStatus.ACTIVITY_ANNIVERSARY;
+import static android.app.people.ConversationStatus.ACTIVITY_BIRTHDAY;
+import static android.app.people.ConversationStatus.ACTIVITY_GAME;
+import static com.android.systemui.people.PeopleSpaceUtils.INVALID_USER_ID;
import static com.android.systemui.people.PeopleSpaceUtils.OPTIONS_PEOPLE_SPACE_TILE;
+import static com.android.systemui.people.PeopleSpaceUtils.PACKAGE_NAME;
+import static com.android.systemui.people.PeopleSpaceUtils.USER_ID;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -38,12 +45,15 @@
import android.app.NotificationChannel;
import android.app.Person;
import android.app.people.ConversationChannel;
+import android.app.people.ConversationStatus;
import android.app.people.IPeopleManager;
+import android.app.people.PeopleManager;
import android.app.people.PeopleSpaceTile;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
import android.graphics.drawable.Icon;
import android.net.Uri;
@@ -56,7 +66,6 @@
import androidx.preference.PreferenceManager;
import androidx.test.filters.SmallTest;
-import com.android.internal.appwidget.IAppWidgetService;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.people.PeopleSpaceUtils;
@@ -76,7 +85,9 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Arrays;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
@SmallTest
@@ -99,6 +110,7 @@
private static final String NOTIFICATION_CONTENT = "message text";
private static final Uri URI = Uri.parse("fake_uri");
private static final Icon ICON = Icon.createWithResource("package", R.drawable.ic_android);
+ private static final String KEY = PeopleSpaceUtils.getKey(SHORTCUT_ID, TEST_PACKAGE_A, 0);
private static final Person PERSON = new Person.Builder()
.setName("name")
.setKey("abc")
@@ -121,12 +133,15 @@
@Mock
private NotificationListener mListenerService;
- @Mock
- private IAppWidgetService mIAppWidgetService;
+
@Mock
private AppWidgetManager mAppWidgetManager;
@Mock
private IPeopleManager mIPeopleManager;
+ @Mock
+ private PeopleManager mPeopleManager;
+ @Mock
+ private LauncherApps mLauncherApps;
@Captor
private ArgumentCaptor<NotificationHandler> mListenerCaptor;
@@ -136,13 +151,19 @@
private final NoManSimulator mNoMan = new NoManSimulator();
private final FakeSystemClock mClock = new FakeSystemClock();
+ private PeopleSpaceWidgetProvider mProvider;
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mLauncherApps = mock(LauncherApps.class);
mManager =
new PeopleSpaceWidgetManager(mContext);
- mManager.setAppWidgetManager(mIAppWidgetService, mAppWidgetManager, mIPeopleManager);
+ mManager.setAppWidgetManager(mAppWidgetManager, mIPeopleManager, mPeopleManager,
+ mLauncherApps);
mManager.attach(mListenerService);
+ mProvider = new PeopleSpaceWidgetProvider();
+ mProvider.setPeopleSpaceWidgetManager(mManager);
verify(mListenerService).addNotificationHandler(mListenerCaptor.capture());
NotificationHandler serviceListener = requireNonNull(mListenerCaptor.getValue());
@@ -166,7 +187,7 @@
@Test
public void testDoNotUpdateAppWidgetIfNoWidgets() throws Exception {
int[] widgetIdsArray = {};
- when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+ when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
StatusBarNotification sbn = createNotification(
OTHER_SHORTCUT_ID, /* isMessagingStyle = */ false, /* isMissedCall = */ false);
@@ -182,7 +203,7 @@
@Test
public void testDoNotUpdateAppWidgetIfNoShortcutInfo() throws Exception {
int[] widgetIdsArray = {};
- when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+ when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
Notification notificationWithoutShortcut = new Notification.Builder(mContext)
.setContentTitle("TEST_TITLE")
@@ -206,7 +227,7 @@
@Test
public void testDoNotUpdateAppWidgetIfNoPackage() throws Exception {
int[] widgetIdsArray = {};
- when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+ when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
StatusBarNotification sbnWithoutPackageName = new SbnBuilder()
.setNotification(createMessagingStyleNotification(
@@ -224,7 +245,7 @@
@Test
public void testDoNotUpdateAppWidgetIfNonConversationChannelModified() throws Exception {
int[] widgetIdsArray = {1};
- when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+ when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
NotificationChannel channel =
new NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, IMPORTANCE_DEFAULT);
@@ -240,7 +261,7 @@
@Test
public void testUpdateAppWidgetIfConversationChannelModified() throws Exception {
int[] widgetIdsArray = {1};
- when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+ when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
NotificationChannel channel =
new NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, IMPORTANCE_DEFAULT);
@@ -257,7 +278,7 @@
@Test
public void testDoNotUpdateNotificationPostedIfDifferentShortcutId() throws Exception {
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
- when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+ when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
StatusBarNotification sbn = createNotification(
OTHER_SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false);
@@ -277,7 +298,7 @@
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0);
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
- when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+ when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
StatusBarNotification sbnWithDifferentPackageName = new SbnBuilder()
.setNotification(createMessagingStyleNotification(
@@ -298,7 +319,7 @@
@Test
public void testDoNotUpdateNotificationRemovedIfDifferentShortcutId() throws Exception {
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
- when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+ when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
StatusBarNotification sbn = createNotification(
OTHER_SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false);
@@ -318,7 +339,7 @@
@Test
public void testDoNotUpdateNotificationRemovedIfDifferentPackageName() throws Exception {
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
- when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+ when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
StatusBarNotification sbnWithDifferentPackageName = new SbnBuilder()
.setNotification(createMessagingStyleNotification(
@@ -339,9 +360,74 @@
}
@Test
+ public void testDoNotUpdateStatusPostedIfDifferentShortcutId() throws Exception {
+ int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
+ when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+
+ ConversationStatus status1 = new ConversationStatus.Builder(OTHER_SHORTCUT_ID,
+ ACTIVITY_GAME).setDescription("Playing a game!").build();
+ ConversationStatus status2 = new ConversationStatus.Builder(OTHER_SHORTCUT_ID,
+ ACTIVITY_BIRTHDAY).build();
+ ConversationChannel conversationChannel = getConversationWithShortcutId(OTHER_SHORTCUT_ID,
+ Arrays.asList(status1, status2));
+ mManager.updateWidgetsWithConversationChanged(conversationChannel);
+ mClock.advanceTime(MIN_LINGER_DURATION);
+
+ verify(mAppWidgetManager, never())
+ .updateAppWidgetOptions(anyInt(), any());
+ verify(mAppWidgetManager, never()).updateAppWidget(anyInt(),
+ any());
+ }
+
+ @Test
+ public void testUpdateStatusPostedIfExistingTile() throws Exception {
+ int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
+ when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+
+ ConversationStatus status = new ConversationStatus.Builder(SHORTCUT_ID,
+ ACTIVITY_GAME).setDescription("Playing a game!").build();
+ ConversationChannel conversationChannel = getConversationWithShortcutId(SHORTCUT_ID,
+ Arrays.asList(status));
+ mManager.updateWidgetsWithConversationChanged(conversationChannel);
+ mClock.advanceTime(MIN_LINGER_DURATION);
+
+ verify(mAppWidgetManager, times(1))
+ .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
+ mBundleArgumentCaptor.capture());
+ Bundle bundle = mBundleArgumentCaptor.getValue();
+ PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_SPACE_TILE);
+ assertThat(tile.getStatuses()).containsExactly(status);
+ verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
+ any());
+ }
+
+ @Test
+ public void testUpdateStatusPostedOnTwoExistingTiles() throws Exception {
+ addSecondWidgetForPersonTile();
+
+ ConversationStatus status = new ConversationStatus.Builder(SHORTCUT_ID,
+ ACTIVITY_ANNIVERSARY).build();
+ ConversationChannel conversationChannel = getConversationWithShortcutId(SHORTCUT_ID,
+ Arrays.asList(status));
+ mManager.updateWidgetsWithConversationChanged(conversationChannel);
+ mClock.advanceTime(MIN_LINGER_DURATION);
+
+ verify(mAppWidgetManager, times(1))
+ .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT),
+ any());
+ verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
+ any());
+ verify(mAppWidgetManager, times(1))
+ .updateAppWidgetOptions(eq(SECOND_WIDGET_ID_WITH_SHORTCUT),
+ any());
+ verify(mAppWidgetManager, times(1)).updateAppWidget(eq(SECOND_WIDGET_ID_WITH_SHORTCUT),
+ any());
+ }
+
+ @Test
public void testUpdateNotificationPostedIfExistingTile() throws Exception {
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
- when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+ when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
.setSbn(createNotification(
@@ -362,17 +448,7 @@
@Test
public void testUpdateNotificationPostedOnTwoExistingTiles() throws Exception {
- Bundle options = new Bundle();
- options.putParcelable(PeopleSpaceUtils.OPTIONS_PEOPLE_SPACE_TILE, PERSON_TILE);
- when(mAppWidgetManager.getAppWidgetOptions(eq(SECOND_WIDGET_ID_WITH_SHORTCUT)))
- .thenReturn(options);
- // Set the same Person associated on another People Tile widget ID.
- setStorageForTile(SHORTCUT_ID, TEST_PACKAGE_A, WIDGET_ID_WITH_SHORTCUT);
- setStorageForTile(SHORTCUT_ID, TEST_PACKAGE_A, SECOND_WIDGET_ID_WITH_SHORTCUT);
-
- int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT,
- SECOND_WIDGET_ID_WITH_SHORTCUT};
- when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+ addSecondWidgetForPersonTile();
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
.setSbn(createNotification(
@@ -395,19 +471,9 @@
@Test
public void testUpdateNotificationOnExistingTileAfterRemovingTileForSamePerson()
throws Exception {
- Bundle options = new Bundle();
- options.putParcelable(PeopleSpaceUtils.OPTIONS_PEOPLE_SPACE_TILE, PERSON_TILE);
- when(mAppWidgetManager.getAppWidgetOptions(eq(SECOND_WIDGET_ID_WITH_SHORTCUT)))
- .thenReturn(options);
- // Set the same Person associated on another People Tile widget ID.
- setStorageForTile(SHORTCUT_ID, TEST_PACKAGE_A, WIDGET_ID_WITH_SHORTCUT);
- setStorageForTile(SHORTCUT_ID, TEST_PACKAGE_A, SECOND_WIDGET_ID_WITH_SHORTCUT);
+ addSecondWidgetForPersonTile();
- int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT,
- SECOND_WIDGET_ID_WITH_SHORTCUT};
- when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
-
- PeopleSpaceUtils.removeStorageForTile(mContext, SECOND_WIDGET_ID_WITH_SHORTCUT);
+ PeopleSpaceUtils.removeStorageForTile(mContext, KEY, SECOND_WIDGET_ID_WITH_SHORTCUT);
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
.setSbn(createNotification(
SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false))
@@ -430,7 +496,7 @@
public void testUpdateMissedCallNotificationWithoutContentPostedIfExistingTile()
throws Exception {
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
- when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+ when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
setStorageForTile(SHORTCUT_ID, TEST_PACKAGE_A, WIDGET_ID_WITH_SHORTCUT);
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
@@ -456,7 +522,7 @@
public void testUpdateMissedCallNotificationWithContentPostedIfExistingTile()
throws Exception {
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
- when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+ when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
setStorageForTile(SHORTCUT_ID, TEST_PACKAGE_A, WIDGET_ID_WITH_SHORTCUT);
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
@@ -480,7 +546,7 @@
@Test
public void testUpdateNotificationRemovedIfExistingTile() throws Exception {
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
- when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+ when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
StatusBarNotification sbn = createNotification(
SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false);
@@ -502,14 +568,82 @@
any());
}
+ @Test
+ public void testDeleteAllWidgetsForConversationsUncachesShortcutAndRemovesListeners() {
+ addSecondWidgetForPersonTile();
+ mProvider.onUpdate(mContext, mAppWidgetManager,
+ new int[]{WIDGET_ID_WITH_SHORTCUT, SECOND_WIDGET_ID_WITH_SHORTCUT});
+
+ // Delete only one widget for the conversation.
+ mManager.deleteWidgets(new int[]{WIDGET_ID_WITH_SHORTCUT});
+
+ // Check deleted storage.
+ SharedPreferences widgetSp = mContext.getSharedPreferences(
+ String.valueOf(WIDGET_ID_WITH_SHORTCUT),
+ Context.MODE_PRIVATE);
+ assertThat(widgetSp.getString(PACKAGE_NAME, null)).isNull();
+ assertThat(widgetSp.getString(SHORTCUT_ID, null)).isNull();
+ assertThat(widgetSp.getInt(USER_ID, INVALID_USER_ID)).isEqualTo(INVALID_USER_ID);
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
+ assertThat(sp.getStringSet(KEY, new HashSet<>())).containsExactly(
+ String.valueOf(SECOND_WIDGET_ID_WITH_SHORTCUT));
+ // Check listener & shortcut caching remain for other widget.
+ verify(mPeopleManager, never()).unregisterConversationListener(any());
+ verify(mLauncherApps, never()).uncacheShortcuts(eq(TEST_PACKAGE_A),
+ eq(Arrays.asList(SHORTCUT_ID)), eq(UserHandle.of(0)),
+ eq(LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS));
+
+ // Delete all widgets for the conversation.
+ mProvider.onDeleted(mContext, new int[]{SECOND_WIDGET_ID_WITH_SHORTCUT});
+
+ // Check deleted storage.
+ SharedPreferences secondWidgetSp = mContext.getSharedPreferences(
+ String.valueOf(SECOND_WIDGET_ID_WITH_SHORTCUT),
+ Context.MODE_PRIVATE);
+ assertThat(secondWidgetSp.getString(PACKAGE_NAME, null)).isNull();
+ assertThat(secondWidgetSp.getString(SHORTCUT_ID, null)).isNull();
+ assertThat(secondWidgetSp.getInt(USER_ID, INVALID_USER_ID)).isEqualTo(INVALID_USER_ID);
+ assertThat(sp.getStringSet(KEY, new HashSet<>())).isEmpty();
+ // Check listener is removed and shortcut is uncached.
+ verify(mPeopleManager, times(1)).unregisterConversationListener(any());
+ verify(mLauncherApps, times(1)).uncacheShortcuts(eq(TEST_PACKAGE_A),
+ eq(Arrays.asList(SHORTCUT_ID)), eq(UserHandle.of(0)),
+ eq(LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS));
+ }
+
+ /**
+ * Adds another widget for {@code PERSON_TILE} with widget ID: {@code
+ * SECOND_WIDGET_ID_WITH_SHORTCUT}.
+ */
+ private void addSecondWidgetForPersonTile() {
+ Bundle options = new Bundle();
+ options.putParcelable(PeopleSpaceUtils.OPTIONS_PEOPLE_SPACE_TILE, PERSON_TILE);
+ when(mAppWidgetManager.getAppWidgetOptions(eq(SECOND_WIDGET_ID_WITH_SHORTCUT)))
+ .thenReturn(options);
+ // Set the same Person associated on another People Tile widget ID.
+ setStorageForTile(SHORTCUT_ID, TEST_PACKAGE_A, WIDGET_ID_WITH_SHORTCUT);
+ setStorageForTile(SHORTCUT_ID, TEST_PACKAGE_A, SECOND_WIDGET_ID_WITH_SHORTCUT);
+ int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT,
+ SECOND_WIDGET_ID_WITH_SHORTCUT};
+ when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+ }
+
/**
* Returns a single conversation associated with {@code shortcutId}.
*/
private ConversationChannel getConversationWithShortcutId(String shortcutId) throws Exception {
+ return getConversationWithShortcutId(shortcutId, Arrays.asList());
+ }
+
+ /**
+ * Returns a single conversation associated with {@code shortcutId} and {@code statuses}.
+ */
+ private ConversationChannel getConversationWithShortcutId(String shortcutId,
+ List<ConversationStatus> statuses) throws Exception {
ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mContext, shortcutId).setLongLabel(
"name").build();
ConversationChannel convo = new ConversationChannel(shortcutInfo, 0, null, null,
- 0L, false);
+ 0L, false, false, statuses);
return convo;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileBaseViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileBaseViewTest.kt
new file mode 100644
index 0000000..998e070
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileBaseViewTest.kt
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2021 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.systemui.qs.tileimpl
+
+import android.service.quicksettings.Tile
+import android.testing.AndroidTestingRunner
+import android.text.TextUtils
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.qs.QSIconView
+import com.android.systemui.plugins.qs.QSTile
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class QSTileBaseViewTest : SysuiTestCase() {
+
+ @Mock
+ private lateinit var iconView: QSIconView
+
+ private lateinit var tileView: QSTileBaseView
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ tileView = QSTileBaseView(context, iconView, false)
+ }
+
+ @Test
+ fun testSecondaryLabelNotModified_unavailable() {
+ val state = QSTile.State()
+ val testString = "TEST STRING"
+ state.state = Tile.STATE_UNAVAILABLE
+ state.secondaryLabel = testString
+
+ tileView.handleStateChanged(state)
+
+ assertThat(state.secondaryLabel as CharSequence).isEqualTo(testString)
+ }
+
+ @Test
+ fun testSecondaryLabelNotModified_booleanInactive() {
+ val state = QSTile.BooleanState()
+ val testString = "TEST STRING"
+ state.state = Tile.STATE_INACTIVE
+ state.secondaryLabel = testString
+
+ tileView.handleStateChanged(state)
+
+ assertThat(state.secondaryLabel as CharSequence).isEqualTo(testString)
+ }
+
+ @Test
+ fun testSecondaryLabelNotModified_booleanActive() {
+ val state = QSTile.BooleanState()
+ val testString = "TEST STRING"
+ state.state = Tile.STATE_ACTIVE
+ state.secondaryLabel = testString
+
+ tileView.handleStateChanged(state)
+
+ assertThat(state.secondaryLabel as CharSequence).isEqualTo(testString)
+ }
+
+ @Test
+ fun testSecondaryLabelNotModified_availableNotBoolean_inactive() {
+ val state = QSTile.State()
+ state.state = Tile.STATE_INACTIVE
+ state.secondaryLabel = ""
+
+ tileView.handleStateChanged(state)
+
+ assertThat(TextUtils.isEmpty(state.secondaryLabel)).isTrue()
+ }
+
+ @Test
+ fun testSecondaryLabelNotModified_availableNotBoolean_active() {
+ val state = QSTile.State()
+ state.state = Tile.STATE_ACTIVE
+ state.secondaryLabel = ""
+
+ tileView.handleStateChanged(state)
+
+ assertThat(TextUtils.isEmpty(state.secondaryLabel)).isTrue()
+ }
+
+ @Test
+ fun testSecondaryLabelDescription_unavailable() {
+ val state = QSTile.State()
+ state.state = Tile.STATE_UNAVAILABLE
+ state.secondaryLabel = ""
+
+ tileView.handleStateChanged(state)
+
+ assertThat(state.secondaryLabel as CharSequence).isEqualTo(
+ context.getString(R.string.tile_unavailable)
+ )
+ }
+
+ @Test
+ fun testSecondaryLabelDescription_booleanInactive() {
+ val state = QSTile.BooleanState()
+ state.state = Tile.STATE_INACTIVE
+ state.secondaryLabel = ""
+
+ tileView.handleStateChanged(state)
+
+ assertThat(state.secondaryLabel as CharSequence).isEqualTo(
+ context.getString(R.string.switch_bar_off)
+ )
+ }
+
+ @Test
+ fun testSecondaryLabelDescription_booleanActive() {
+ val state = QSTile.BooleanState()
+ state.state = Tile.STATE_ACTIVE
+ state.secondaryLabel = ""
+
+ tileView.handleStateChanged(state)
+
+ assertThat(state.secondaryLabel as CharSequence).isEqualTo(
+ context.getString(R.string.switch_bar_on)
+ )
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java
index 6d2b8e4..25104b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java
@@ -43,6 +43,7 @@
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
+import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.transition.RemoteTransitions;
import org.junit.Before;
@@ -79,6 +80,7 @@
@Mock private PackageManager mPackageManager;
@Mock private SysUiState mMockSysUiState;
@Mock private RemoteTransitions mMockTransitions;
+ @Mock private Optional<StartingSurface> mStartingSurface;
@Before
public void setUp() throws RemoteException {
@@ -93,7 +95,7 @@
mMockNavBarControllerLazy, mMockNavModeController, mMockStatusBarWinController,
mMockSysUiState, mMockPipOptional, mMockLegacySplitScreenOptional,
mMockSplitScreenOptional, mMockStatusBarOptionalLazy, mMockOneHandedOptional,
- mMockBroadcastDispatcher, mMockTransitions));
+ mMockBroadcastDispatcher, mMockTransitions, mStartingSurface));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index b1b71cc..999d282 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -50,11 +50,11 @@
import android.provider.Settings.Global;
import android.telephony.CellSignalStrength;
import android.telephony.NetworkRegistrationInfo;
-import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
import android.telephony.TelephonyDisplayInfo;
import android.telephony.TelephonyManager;
import android.testing.TestableLooper;
@@ -106,7 +106,6 @@
protected NetworkControllerImpl mNetworkController;
protected MobileSignalController mMobileSignalController;
- protected PhoneStateListener mPhoneStateListener;
protected SignalStrength mSignalStrength;
protected ServiceState mServiceState;
protected TelephonyDisplayInfo mTelephonyDisplayInfo;
@@ -250,8 +249,6 @@
setDefaultSubId(mSubId);
setSubscriptions(mSubId);
mMobileSignalController = mNetworkController.mMobileSignalControllers.get(mSubId);
- mPhoneStateListener = mMobileSignalController.mMobileStatusTracker.getPhoneStateListener();
-
ArgumentCaptor<ConnectivityManager.NetworkCallback> callbackArg =
ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
verify(mMockCm, atLeastOnce())
@@ -455,18 +452,16 @@
private void updateSignalStrength() {
Log.d(TAG, "Sending Signal Strength: " + mSignalStrength);
- mPhoneStateListener.onSignalStrengthsChanged(mSignalStrength);
+ mMobileSignalController.mMobileStatusTracker.getTelephonyCallback()
+ .onSignalStrengthsChanged(mSignalStrength);
}
protected void updateServiceState() {
Log.d(TAG, "Sending Service State: " + mServiceState);
- mPhoneStateListener.onServiceStateChanged(mServiceState);
- mPhoneStateListener.onDisplayInfoChanged(mTelephonyDisplayInfo);
- }
-
- public void updateCallState(int state) {
- // Inputs not currently used in NetworkControllerImpl.
- mPhoneStateListener.onCallStateChanged(state, "0123456789");
+ mMobileSignalController.mMobileStatusTracker.getTelephonyCallback()
+ .onServiceStateChanged(mServiceState);
+ mMobileSignalController.mMobileStatusTracker.getTelephonyCallback()
+ .onDisplayInfoChanged(mTelephonyDisplayInfo);
}
public void updateDataConnectionState(int dataState, int dataNetType) {
@@ -478,16 +473,19 @@
when(mServiceState.getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN))
.thenReturn(fakeRegInfo);
when(mTelephonyDisplayInfo.getNetworkType()).thenReturn(dataNetType);
- mPhoneStateListener.onDataConnectionStateChanged(dataState, dataNetType);
+ mMobileSignalController.mMobileStatusTracker.getTelephonyCallback()
+ .onDataConnectionStateChanged(dataState, dataNetType);
}
public void updateDataActivity(int dataActivity) {
- mPhoneStateListener.onDataActivity(dataActivity);
+ mMobileSignalController.mMobileStatusTracker.getTelephonyCallback()
+ .onDataActivity(dataActivity);
}
public void setCarrierNetworkChange(boolean enable) {
Log.d(TAG, "setCarrierNetworkChange(" + enable + ")");
- mPhoneStateListener.onCarrierNetworkChange(enable);
+ mMobileSignalController.mMobileStatusTracker.getTelephonyCallback()
+ .onCarrierNetworkChange(enable);
}
protected void verifyHasNoSims(boolean hasNoSimsVisible) {
diff --git a/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java b/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
index bafb641..6828dd9 100644
--- a/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
+++ b/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
@@ -40,29 +40,34 @@
private final IAccessibilityInteractionConnectionCallback mServiceCallback;
private final IAccessibilityInteractionConnection mConnectionWithReplacementActions;
private final int mInteractionId;
+ private final int mNodeWithReplacementActionsInteractionId;
private final Object mLock = new Object();
@GuardedBy("mLock")
- List<AccessibilityNodeInfo> mNodesWithReplacementActions;
+ private boolean mReplacementNodeIsReadyOrFailed;
+
+ @GuardedBy("mLock")
+ AccessibilityNodeInfo mNodeWithReplacementActions;
@GuardedBy("mLock")
List<AccessibilityNodeInfo> mNodesFromOriginalWindow;
@GuardedBy("mLock")
+ boolean mSetFindNodeFromOriginalWindowCalled = false;
+
+ @GuardedBy("mLock")
AccessibilityNodeInfo mNodeFromOriginalWindow;
- // Keep track of whether or not we've been called back for a single node
@GuardedBy("mLock")
- boolean mSingleNodeCallbackHappened;
+ boolean mSetFindNodesFromOriginalWindowCalled = false;
- // Keep track of whether or not we've been called back for multiple node
- @GuardedBy("mLock")
- boolean mMultiNodeCallbackHappened;
- // We shouldn't get any more callbacks after we've called back the original service, but
- // keep track to make sure we catch such strange things
@GuardedBy("mLock")
- boolean mDone;
+ List<AccessibilityNodeInfo> mPrefetchedNodesFromOriginalWindow;
+
+ @GuardedBy("mLock")
+ boolean mSetPrefetchFromOriginalWindowCalled = false;
+
public ActionReplacingCallback(IAccessibilityInteractionConnectionCallback serviceCallback,
IAccessibilityInteractionConnection connectionWithReplacementActions,
@@ -70,19 +75,20 @@
mServiceCallback = serviceCallback;
mConnectionWithReplacementActions = connectionWithReplacementActions;
mInteractionId = interactionId;
+ mNodeWithReplacementActionsInteractionId = interactionId + 1;
// Request the root node of the replacing window
final long identityToken = Binder.clearCallingIdentity();
try {
mConnectionWithReplacementActions.findAccessibilityNodeInfoByAccessibilityId(
- AccessibilityNodeInfo.ROOT_NODE_ID, null, interactionId + 1, this, 0,
+ AccessibilityNodeInfo.ROOT_NODE_ID, null,
+ mNodeWithReplacementActionsInteractionId, this, 0,
interrogatingPid, interrogatingTid, null, null);
} catch (RemoteException re) {
if (DEBUG) {
Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
}
- // Pretend we already got a (null) list of replacement nodes
- mMultiNodeCallbackHappened = true;
+ mReplacementNodeIsReadyOrFailed = true;
} finally {
Binder.restoreCallingIdentity(identityToken);
}
@@ -90,46 +96,67 @@
@Override
public void setFindAccessibilityNodeInfoResult(AccessibilityNodeInfo info, int interactionId) {
- boolean readyForCallback;
- synchronized(mLock) {
+ synchronized (mLock) {
if (interactionId == mInteractionId) {
mNodeFromOriginalWindow = info;
+ mSetFindNodeFromOriginalWindowCalled = true;
+ } else if (interactionId == mNodeWithReplacementActionsInteractionId) {
+ mNodeWithReplacementActions = info;
+ mReplacementNodeIsReadyOrFailed = true;
} else {
Slog.e(LOG_TAG, "Callback with unexpected interactionId");
return;
}
-
- mSingleNodeCallbackHappened = true;
- readyForCallback = mMultiNodeCallbackHappened;
}
- if (readyForCallback) {
- replaceInfoActionsAndCallService();
- }
+ replaceInfoActionsAndCallServiceIfReady();
}
@Override
public void setFindAccessibilityNodeInfosResult(List<AccessibilityNodeInfo> infos,
int interactionId) {
- boolean callbackForSingleNode;
- boolean callbackForMultipleNodes;
- synchronized(mLock) {
+ synchronized (mLock) {
if (interactionId == mInteractionId) {
mNodesFromOriginalWindow = infos;
- } else if (interactionId == mInteractionId + 1) {
- mNodesWithReplacementActions = infos;
+ mSetFindNodesFromOriginalWindowCalled = true;
+ } else if (interactionId == mNodeWithReplacementActionsInteractionId) {
+ setNodeWithReplacementActionsFromList(infos);
+ mReplacementNodeIsReadyOrFailed = true;
} else {
Slog.e(LOG_TAG, "Callback with unexpected interactionId");
return;
}
- callbackForSingleNode = mSingleNodeCallbackHappened;
- callbackForMultipleNodes = mMultiNodeCallbackHappened;
- mMultiNodeCallbackHappened = true;
}
- if (callbackForSingleNode) {
- replaceInfoActionsAndCallService();
+ replaceInfoActionsAndCallServiceIfReady();
+ }
+
+ @Override
+ public void setPrefetchAccessibilityNodeInfoResult(List<AccessibilityNodeInfo> infos,
+ int interactionId)
+ throws RemoteException {
+ synchronized (mLock) {
+ if (interactionId == mInteractionId) {
+ mPrefetchedNodesFromOriginalWindow = infos;
+ mSetPrefetchFromOriginalWindowCalled = true;
+ } else {
+ Slog.e(LOG_TAG, "Callback with unexpected interactionId");
+ return;
+ }
}
- if (callbackForMultipleNodes) {
- replaceInfosActionsAndCallService();
+ replaceInfoActionsAndCallServiceIfReady();
+ }
+
+ private void replaceInfoActionsAndCallServiceIfReady() {
+ replaceInfoActionsAndCallService();
+ replaceInfosActionsAndCallService();
+ replacePrefetchInfosActionsAndCallService();
+ }
+
+ private void setNodeWithReplacementActionsFromList(List<AccessibilityNodeInfo> infos) {
+ for (int i = 0; i < infos.size(); i++) {
+ AccessibilityNodeInfo info = infos.get(i);
+ if (info.getSourceNodeId() == AccessibilityNodeInfo.ROOT_NODE_ID) {
+ mNodeWithReplacementActions = info;
+ }
}
}
@@ -142,55 +169,81 @@
private void replaceInfoActionsAndCallService() {
final AccessibilityNodeInfo nodeToReturn;
+ boolean doCallback = false;
synchronized (mLock) {
- if (mDone) {
- if (DEBUG) {
- Slog.e(LOG_TAG, "Extra callback");
- }
- return;
- }
- if (mNodeFromOriginalWindow != null) {
+ doCallback = mReplacementNodeIsReadyOrFailed
+ && mSetFindNodeFromOriginalWindowCalled;
+ if (doCallback && mNodeFromOriginalWindow != null) {
replaceActionsOnInfoLocked(mNodeFromOriginalWindow);
+ mSetFindNodeFromOriginalWindowCalled = false;
}
- recycleReplaceActionNodesLocked();
nodeToReturn = mNodeFromOriginalWindow;
- mDone = true;
}
- try {
- mServiceCallback.setFindAccessibilityNodeInfoResult(nodeToReturn, mInteractionId);
- } catch (RemoteException re) {
- if (DEBUG) {
- Slog.e(LOG_TAG, "Failed to setFindAccessibilityNodeInfoResult");
+ if (doCallback) {
+ try {
+ mServiceCallback.setFindAccessibilityNodeInfoResult(nodeToReturn, mInteractionId);
+ } catch (RemoteException re) {
+ if (DEBUG) {
+ Slog.e(LOG_TAG, "Failed to setFindAccessibilityNodeInfoResult");
+ }
}
}
}
private void replaceInfosActionsAndCallService() {
- final List<AccessibilityNodeInfo> nodesToReturn;
+ List<AccessibilityNodeInfo> nodesToReturn = null;
+ boolean doCallback = false;
synchronized (mLock) {
- if (mDone) {
+ doCallback = mReplacementNodeIsReadyOrFailed
+ && mSetFindNodesFromOriginalWindowCalled;
+ if (doCallback) {
+ nodesToReturn = replaceActionsLocked(mNodesFromOriginalWindow);
+ mSetFindNodesFromOriginalWindowCalled = false;
+ }
+ }
+ if (doCallback) {
+ try {
+ mServiceCallback.setFindAccessibilityNodeInfosResult(nodesToReturn, mInteractionId);
+ } catch (RemoteException re) {
if (DEBUG) {
- Slog.e(LOG_TAG, "Extra callback");
- }
- return;
- }
- if (mNodesFromOriginalWindow != null) {
- for (int i = 0; i < mNodesFromOriginalWindow.size(); i++) {
- replaceActionsOnInfoLocked(mNodesFromOriginalWindow.get(i));
+ Slog.e(LOG_TAG, "Failed to setFindAccessibilityNodeInfosResult");
}
}
- recycleReplaceActionNodesLocked();
- nodesToReturn = (mNodesFromOriginalWindow == null)
- ? null : new ArrayList<>(mNodesFromOriginalWindow);
- mDone = true;
}
- try {
- mServiceCallback.setFindAccessibilityNodeInfosResult(nodesToReturn, mInteractionId);
- } catch (RemoteException re) {
- if (DEBUG) {
- Slog.e(LOG_TAG, "Failed to setFindAccessibilityNodeInfosResult");
+ }
+
+ private void replacePrefetchInfosActionsAndCallService() {
+ List<AccessibilityNodeInfo> nodesToReturn = null;
+ boolean doCallback = false;
+ synchronized (mLock) {
+ doCallback = mReplacementNodeIsReadyOrFailed
+ && mSetPrefetchFromOriginalWindowCalled;
+ if (doCallback) {
+ nodesToReturn = replaceActionsLocked(mPrefetchedNodesFromOriginalWindow);
+ mSetPrefetchFromOriginalWindowCalled = false;
}
}
+ if (doCallback) {
+ try {
+ mServiceCallback.setPrefetchAccessibilityNodeInfoResult(
+ nodesToReturn, mInteractionId);
+ } catch (RemoteException re) {
+ if (DEBUG) {
+ Slog.e(LOG_TAG, "Failed to setFindAccessibilityNodeInfosResult");
+ }
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ private List<AccessibilityNodeInfo> replaceActionsLocked(List<AccessibilityNodeInfo> infos) {
+ if (infos != null) {
+ for (int i = 0; i < infos.size(); i++) {
+ replaceActionsOnInfoLocked(infos.get(i));
+ }
+ }
+ return (infos == null)
+ ? null : new ArrayList<>(infos);
}
@GuardedBy("mLock")
@@ -204,40 +257,22 @@
info.setDismissable(false);
// We currently only replace actions for the root node
if ((info.getSourceNodeId() == AccessibilityNodeInfo.ROOT_NODE_ID)
- && mNodesWithReplacementActions != null) {
- // This list should always contain a single node with the root ID
- for (int i = 0; i < mNodesWithReplacementActions.size(); i++) {
- AccessibilityNodeInfo nodeWithReplacementActions =
- mNodesWithReplacementActions.get(i);
- if (nodeWithReplacementActions.getSourceNodeId()
- == AccessibilityNodeInfo.ROOT_NODE_ID) {
- List<AccessibilityAction> actions = nodeWithReplacementActions.getActionList();
- if (actions != null) {
- for (int j = 0; j < actions.size(); j++) {
- info.addAction(actions.get(j));
- }
- // The PIP needs to be able to take accessibility focus
- info.addAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS);
- info.addAction(AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
- }
- info.setClickable(nodeWithReplacementActions.isClickable());
- info.setFocusable(nodeWithReplacementActions.isFocusable());
- info.setContextClickable(nodeWithReplacementActions.isContextClickable());
- info.setScrollable(nodeWithReplacementActions.isScrollable());
- info.setLongClickable(nodeWithReplacementActions.isLongClickable());
- info.setDismissable(nodeWithReplacementActions.isDismissable());
+ && mNodeWithReplacementActions != null) {
+ List<AccessibilityAction> actions = mNodeWithReplacementActions.getActionList();
+ if (actions != null) {
+ for (int j = 0; j < actions.size(); j++) {
+ info.addAction(actions.get(j));
}
+ // The PIP needs to be able to take accessibility focus
+ info.addAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS);
+ info.addAction(AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
}
+ info.setClickable(mNodeWithReplacementActions.isClickable());
+ info.setFocusable(mNodeWithReplacementActions.isFocusable());
+ info.setContextClickable(mNodeWithReplacementActions.isContextClickable());
+ info.setScrollable(mNodeWithReplacementActions.isScrollable());
+ info.setLongClickable(mNodeWithReplacementActions.isLongClickable());
+ info.setDismissable(mNodeWithReplacementActions.isDismissable());
}
}
-
- @GuardedBy("mLock")
- private void recycleReplaceActionNodesLocked() {
- if (mNodesWithReplacementActions == null) return;
- for (int i = mNodesWithReplacementActions.size() - 1; i >= 0; i--) {
- AccessibilityNodeInfo nodeWithReplacementAction = mNodesWithReplacementActions.get(i);
- nodeWithReplacementAction.recycle();
- }
- mNodesWithReplacementActions = null;
- }
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 6d72ca7..2aa5d26 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -91,6 +91,7 @@
import android.util.ArraySet;
import android.util.LocalLog;
import android.util.Log;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -222,6 +223,13 @@
private final ArrayMap<AutofillId, ViewState> mViewStates = new ArrayMap<>();
/**
+ * Tracks the most recent IME inline request and the corresponding request id, for regular
+ * autofill.
+ */
+ @GuardedBy("mLock")
+ @Nullable private Pair<Integer, InlineSuggestionsRequest> mLastInlineSuggestionsRequest;
+
+ /**
* Id of the View currently being displayed.
*/
@GuardedBy("mLock")
@@ -330,7 +338,7 @@
@GuardedBy("mLock")
private ArrayList<AutofillId> mAugmentedAutofillableIds;
- @Nullable
+ @NonNull
private final AutofillInlineSessionController mInlineSessionController;
/**
@@ -821,11 +829,14 @@
/* isInlineRequest= */ true);
if (inlineSuggestionsRequestConsumer != null) {
final AutofillId focusedId = mCurrentViewId;
+ final int requestIdCopy = requestId;
remoteRenderService.getInlineSuggestionsRendererInfo(
new RemoteCallback((extras) -> {
synchronized (mLock) {
mInlineSessionController.onCreateInlineSuggestionsRequestLocked(
- focusedId, inlineSuggestionsRequestConsumer, extras);
+ focusedId, inlineSuggestionsRequestCacheDecorator(
+ inlineSuggestionsRequestConsumer, requestIdCopy),
+ extras);
}
}, mHandler)
);
@@ -3668,11 +3679,27 @@
requestId, mContexts);
return null;
}
+ if (mLastInlineSuggestionsRequest != null
+ && mLastInlineSuggestionsRequest.first == requestId) {
+ fillInIntent.putExtra(AutofillManager.EXTRA_INLINE_SUGGESTIONS_REQUEST,
+ mLastInlineSuggestionsRequest.second);
+ }
fillInIntent.putExtra(AutofillManager.EXTRA_ASSIST_STRUCTURE, context.getStructure());
fillInIntent.putExtra(AutofillManager.EXTRA_CLIENT_STATE, extras);
return fillInIntent;
}
+ @NonNull
+ private Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestCacheDecorator(
+ @NonNull Consumer<InlineSuggestionsRequest> consumer, int requestId) {
+ return inlineSuggestionsRequest -> {
+ consumer.accept(inlineSuggestionsRequest);
+ synchronized (mLock) {
+ mLastInlineSuggestionsRequest = Pair.create(requestId, inlineSuggestionsRequest);
+ }
+ };
+ }
+
private void startAuthentication(int authenticationId, IntentSender intent,
Intent fillInIntent, boolean authenticateInline) {
try {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 21cae45..52237c9 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -38,6 +38,7 @@
import static java.util.Objects.requireNonNull;
import static java.util.concurrent.TimeUnit.MINUTES;
+import android.Manifest;
import android.annotation.CheckResult;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -409,6 +410,7 @@
checkCallerIsSystemOr(callingPackage);
int userId = getCallingUserId();
checkUsesFeature(callingPackage, userId);
+ checkProfilePermissions(request);
mFindDeviceCallback = callback;
mRequest = request;
@@ -519,6 +521,21 @@
}
}
+ private void checkProfilePermissions(AssociationRequest request) {
+ checkProfilePermission(request,
+ AssociationRequest.DEVICE_PROFILE_WATCH,
+ Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH);
+ }
+
+ private void checkProfilePermission(
+ AssociationRequest request, String profile, String permission) {
+ if (profile.equals(request.getDeviceProfile())
+ && getContext().checkCallingOrSelfPermission(permission)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Using " + profile + " requires " + permission);
+ }
+ }
+
@Override
public PendingIntent requestNotificationAccess(ComponentName component)
throws RemoteException {
@@ -1330,7 +1347,7 @@
mPermissionControllerManager.getPrivilegesDescriptionStringForProfile(
deviceProfile, FgThread.getExecutor(), desc -> {
try {
- result.complete(desc);
+ result.complete(String.valueOf(desc));
} catch (Exception e) {
result.completeExceptionally(e);
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 99ce2db..8ccfad6 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -223,7 +223,6 @@
"java/com/android/server/TestNetworkService.java",
"java/com/android/server/connectivity/AutodestructReference.java",
"java/com/android/server/connectivity/ConnectivityConstants.java",
- "java/com/android/server/connectivity/DataConnectionStats.java",
"java/com/android/server/connectivity/DnsManager.java",
"java/com/android/server/connectivity/KeepaliveTracker.java",
"java/com/android/server/connectivity/LingerMonitor.java",
diff --git a/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
similarity index 76%
rename from core/java/com/android/server/BootReceiver.java
rename to services/core/java/com/android/server/BootReceiver.java
index fe3042d..d83e2fd 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -16,6 +16,8 @@
package com.android.server;
+import static android.system.OsConstants.O_RDONLY;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -24,12 +26,15 @@
import android.os.DropBoxManager;
import android.os.Environment;
import android.os.FileUtils;
+import android.os.MessageQueue.OnFileDescriptorEventListener;
import android.os.RecoverySystem;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.storage.StorageManager;
import android.provider.Downloads;
+import android.system.ErrnoException;
+import android.system.Os;
import android.text.TextUtils;
import android.util.AtomicFile;
import android.util.EventLog;
@@ -46,11 +51,15 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.regex.Matcher;
@@ -116,6 +125,12 @@
private static final String METRIC_SYSTEM_SERVER = "shutdown_system_server";
private static final String METRIC_SHUTDOWN_TIME_START = "begin_shutdown";
+ // Location of ftrace pipe for notifications from kernel memory tools like KFENCE and KASAN.
+ private static final String ERROR_REPORT_TRACE_PIPE =
+ "/sys/kernel/tracing/instances/bootreceiver/trace_pipe";
+ // Avoid reporing the same bug from processDmesg() twice.
+ private static String sLastReportedBug = null;
+
@Override
public void onReceive(final Context context, Intent intent) {
// Log boot events in the background to avoid blocking the main thread with I/O
@@ -143,6 +158,209 @@
}
}.start();
+
+ FileDescriptor tracefd = null;
+ try {
+ tracefd = Os.open(ERROR_REPORT_TRACE_PIPE, O_RDONLY, 0600);
+ } catch (ErrnoException e) {
+ Slog.wtf(TAG, "Could not open " + ERROR_REPORT_TRACE_PIPE, e);
+ return;
+ }
+
+ /*
+ * Event listener to watch for memory tool error reports.
+ * We read from /sys/kernel/tracing/instances/bootreceiver/trace_pipe (set up by the
+ * system), which will print an ftrace event when a memory corruption is detected in the
+ * kernel.
+ * When an error is detected, we run the dmesg shell command and process its output.
+ */
+ OnFileDescriptorEventListener traceCallback = new OnFileDescriptorEventListener() {
+ final int mBufferSize = 1024;
+ byte[] mTraceBuffer = new byte[mBufferSize];
+ @Override
+ public int onFileDescriptorEvents(FileDescriptor fd, int events) {
+ /*
+ * Read from the tracing pipe set up to monitor the error_report_end events.
+ * When a tracing event occurs, the kernel writes a short (~100 bytes) line to the
+ * pipe, e.g.:
+ * ...-11210 [004] d..1 285.322307: error_report_end: [kfence] ffffff8938a05000
+ * The buffer size we use for reading should be enough to read the whole
+ * line, but to be on the safe side we keep reading until the buffer
+ * contains a '\n' character. In the unlikely case of a very buggy kernel
+ * the buffer may contain multiple tracing events that cannot be attributed
+ * to particular error reports. In that case the latest error report
+ * residing in dmesg is picked.
+ */
+ try {
+ int nbytes = Os.read(fd, mTraceBuffer, 0, mBufferSize);
+ if (nbytes > 0) {
+ String readStr = new String(mTraceBuffer);
+ if (readStr.indexOf("\n") == -1) {
+ return OnFileDescriptorEventListener.EVENT_INPUT;
+ }
+ processDmesg(context);
+ }
+ } catch (Exception e) {
+ Slog.wtf(TAG, "Error processing dmesg output", e);
+ return 0; // Unregister the handler.
+ }
+ return OnFileDescriptorEventListener.EVENT_INPUT;
+ }
+ };
+
+ IoThread.get().getLooper().getQueue().addOnFileDescriptorEventListener(
+ tracefd, OnFileDescriptorEventListener.EVENT_INPUT, traceCallback);
+
+ }
+
+ /**
+ * Check whether it is safe to collect this dmesg line or not.
+ *
+ * We only consider lines belonging to KASAN or KFENCE reports, but those may still contain
+ * user information, namely the process name:
+ *
+ * [ 69.547684] [ T6006]c7 6006 CPU: 7 PID: 6006 Comm: sh Tainted: G S C O ...
+ *
+ * hardware information:
+ *
+ * [ 69.558923] [ T6006]c7 6006 Hardware name: <REDACTED>
+ *
+ * or register dump (in KASAN reports only):
+ *
+ * ... RIP: 0033:0x7f96443109da
+ * ... RSP: 002b:00007ffcf0b51b08 EFLAGS: 00000202 ORIG_RAX: 00000000000000af
+ * ... RAX: ffffffffffffffda RBX: 000055dc3ee521a0 RCX: 00007f96443109da
+ *
+ * (on x86_64)
+ *
+ * ... pc : lpm_cpuidle_enter+0x258/0x384
+ * ... lr : lpm_cpuidle_enter+0x1d4/0x384
+ * ... sp : ffffff800820bea0
+ * ... x29: ffffff800820bea0 x28: ffffffc2305f3ce0
+ * ... ...
+ * ... x9 : 0000000000000001 x8 : 0000000000000000
+ * (on ARM64)
+ *
+ * We therefore omit the lines that contain "Comm:", "Hardware name:", or match the general
+ * purpose register regexp.
+ *
+ * @param line single line of `dmesg` output.
+ * @return updated line with sensitive data removed, or null if the line must be skipped.
+ */
+ public static String stripSensitiveData(String line) {
+ /*
+ * General purpose register names begin with "R" on x86_64 and "x" on ARM64. The letter is
+ * followed by two symbols (numbers, letters or spaces) and a colon, which is followed by a
+ * 16-digit hex number. The optional "_" prefix accounts for ORIG_RAX on x86.
+ */
+ final String registerRegex = "[ _][Rx]..: [0-9a-f]{16}";
+ final Pattern registerPattern = Pattern.compile(registerRegex);
+
+ final String corruptionRegex = "Detected corrupted memory at 0x[0-9a-f]+";
+ final Pattern corruptionPattern = Pattern.compile(corruptionRegex);
+
+ if (line.contains("Comm: ") || line.contains("Hardware name: ")) return null;
+ if (registerPattern.matcher(line).find()) return null;
+
+ Matcher cm = corruptionPattern.matcher(line);
+ if (cm.find()) return cm.group(0);
+ return line;
+ }
+
+ /*
+ * Search dmesg output for the last error report from KFENCE or KASAN and copy it to Dropbox.
+ *
+ * Example report printed by the kernel (redacted to fit into 100 column limit):
+ * [ 69.236673] [ T6006]c7 6006 =========================================================
+ * [ 69.245688] [ T6006]c7 6006 BUG: KFENCE: out-of-bounds in kfence_handle_page_fault
+ * [ 69.245688] [ T6006]c7 6006
+ * [ 69.257816] [ T6006]c7 6006 Out-of-bounds access at 0xffffffca75c45000 (...)
+ * [ 69.267102] [ T6006]c7 6006 kfence_handle_page_fault+0x1bc/0x208
+ * [ 69.273536] [ T6006]c7 6006 __do_kernel_fault+0xa8/0x11c
+ * ...
+ * [ 69.355427] [ T6006]c7 6006 kfence-#2 [0xffffffca75c46f30-0xffffffca75c46fff, ...
+ * [ 69.366938] [ T6006]c7 6006 __d_alloc+0x3c/0x1b4
+ * [ 69.371946] [ T6006]c7 6006 d_alloc_parallel+0x48/0x538
+ * [ 69.377578] [ T6006]c7 6006 __lookup_slow+0x60/0x15c
+ * ...
+ * [ 69.547684] [ T6006]c7 6006 CPU: 7 PID: 6006 Comm: sh Tainted: G S C O ...
+ * [ 69.558923] [ T6006]c7 6006 Hardware name: <REDACTED>
+ * [ 69.567059] [ T6006]c7 6006 =========================================================
+ *
+ * We rely on the kernel printing task/CPU ID for every log line (CONFIG_PRINTK_CALLER=y).
+ * E.g. for the above report the task ID is T6006. Report lines may interleave with lines
+ * printed by other kernel tasks, which will have different task IDs, so in order to collect
+ * the report we:
+ * - find the next occurrence of the "BUG: " line in the kernel log, parse it to obtain the
+ * task ID and the tool name;
+ * - scan the rest of dmesg output and pick every line that has the same task ID, until we
+ * encounter a horizontal ruler, i.e.:
+ * [ 69.567059] [ T6006]c7 6006 ======================================================
+ * - add that line to the error report, unless it contains sensitive information (see
+ * logLinePotentiallySensitive())
+ * - repeat the above steps till the last report is found.
+ */
+ private void processDmesg(Context ctx) throws IOException {
+
+ /*
+ * Only SYSTEM_KASAN_ERROR_REPORT and SYSTEM_KFENCE_ERROR_REPORT are supported at the
+ * moment.
+ */
+ final String[] bugTypes = new String[] { "KASAN", "KFENCE" };
+ final String tsRegex = "^\\[[^]]+\\] ";
+ final String bugRegex =
+ tsRegex + "\\[([^]]+)\\].*BUG: (" + String.join("|", bugTypes) + "):";
+ final Pattern bugPattern = Pattern.compile(bugRegex);
+
+ Process p = new ProcessBuilder("/system/bin/timeout", "-k", "90s", "60s",
+ "dmesg").redirectErrorStream(true).start();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
+ String line = null;
+ String task = null;
+ String tool = null;
+ String bugTitle = null;
+ Pattern reportPattern = null;
+ ArrayList<String> currentReport = null;
+ String lastReport = null;
+
+ while ((line = reader.readLine()) != null) {
+ if (currentReport == null) {
+ Matcher bm = bugPattern.matcher(line);
+ if (!bm.find()) continue;
+ task = bm.group(1);
+ tool = bm.group(2);
+ bugTitle = line;
+ currentReport = new ArrayList<String>();
+ currentReport.add(line);
+ String reportRegex = tsRegex + "\\[" + task + "\\].*";
+ reportPattern = Pattern.compile(reportRegex);
+ continue;
+ }
+ Matcher rm = reportPattern.matcher(line);
+ if (!rm.matches()) continue;
+ if ((line = stripSensitiveData(line)) == null) continue;
+ if (line.contains("================================")) {
+ lastReport = String.join("\n", currentReport);
+ currentReport = null;
+ continue;
+ }
+ currentReport.add(line);
+ }
+ if (lastReport == null) {
+ Slog.w(TAG, "Could not find report in dmesg.");
+ return;
+ }
+
+ // Avoid sending the same bug report twice.
+ if (bugTitle == sLastReportedBug) return;
+
+ final String reportTag = "SYSTEM_" + tool + "_ERROR_REPORT";
+ final DropBoxManager db = ctx.getSystemService(DropBoxManager.class);
+ final String headers = getCurrentBootHeaders();
+ final String reportText = headers + lastReport;
+
+ addTextToDropBox(db, reportTag, reportText, "/dev/kmsg", LOG_SIZE);
+ sLastReportedBug = bugTitle;
}
private void removeOldUpdatePackages(Context context) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 986e2acf..2c9837d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -70,6 +70,7 @@
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
import android.app.PendingIntent;
+import android.app.usage.NetworkStatsManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -95,7 +96,6 @@
import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
import android.net.INetworkPolicyListener;
-import android.net.INetworkStatsService;
import android.net.IOnSetOemNetworkPreferenceListener;
import android.net.IQosCallback;
import android.net.ISocketKeepaliveCallback;
@@ -190,9 +190,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
-import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.AsyncChannel;
-import com.android.internal.util.BitUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.LocationPermissionChecker;
import com.android.internal.util.MessageUtils;
@@ -201,10 +199,10 @@
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult;
import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
+import com.android.net.module.util.NetworkCapabilitiesUtils;
import com.android.net.module.util.PermissionUtils;
import com.android.server.am.BatteryStatsService;
import com.android.server.connectivity.AutodestructReference;
-import com.android.server.connectivity.DataConnectionStats;
import com.android.server.connectivity.DnsManager;
import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate;
import com.android.server.connectivity.KeepaliveTracker;
@@ -331,7 +329,7 @@
protected IDnsResolver mDnsResolver;
@VisibleForTesting
protected INetd mNetd;
- private INetworkStatsService mStatsService;
+ private NetworkStatsManager mStatsManager;
private NetworkPolicyManager mPolicyManager;
private NetworkPolicyManagerInternal mPolicyManagerInternal;
private final NetdCallback mNetdCallback;
@@ -1042,15 +1040,14 @@
}
}
- public ConnectivityService(Context context, INetworkStatsService statsService) {
- this(context, statsService, getDnsResolver(context), new IpConnectivityLog(),
+ public ConnectivityService(Context context) {
+ this(context, getDnsResolver(context), new IpConnectivityLog(),
NetdService.getInstance(), new Dependencies());
}
@VisibleForTesting
- protected ConnectivityService(Context context, INetworkStatsService statsService,
- IDnsResolver dnsresolver, IpConnectivityLog logger,
- INetd netd, Dependencies deps) {
+ protected ConnectivityService(Context context, IDnsResolver dnsresolver,
+ IpConnectivityLog logger, INetd netd, Dependencies deps) {
if (DBG) log("ConnectivityService starting up");
mDeps = Objects.requireNonNull(deps, "missing Dependencies");
@@ -1096,7 +1093,7 @@
// TODO: Consider making the timer customizable.
mNascentDelayMs = DEFAULT_NASCENT_DELAY_MS;
- mStatsService = Objects.requireNonNull(statsService, "missing INetworkStatsService");
+ mStatsManager = mContext.getSystemService(NetworkStatsManager.class);
mPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
mPolicyManagerInternal = Objects.requireNonNull(
LocalServices.getService(NetworkPolicyManagerInternal.class),
@@ -1215,9 +1212,6 @@
mSettingsObserver = new SettingsObserver(mContext, mHandler);
registerSettingsCallbacks();
- final DataConnectionStats dataConnectionStats = new DataConnectionStats(mContext, mHandler);
- dataConnectionStats.startMonitoring();
-
mKeepaliveTracker = new KeepaliveTracker(mContext, mHandler);
mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager);
mQosCallbackTracker = new QosCallbackTracker(mHandler, mNetworkRequestCounter);
@@ -1480,7 +1474,10 @@
@NonNull
private NetworkInfo filterNetworkInfo(@NonNull NetworkInfo networkInfo, int type,
@NonNull NetworkCapabilities nc, int uid, boolean ignoreBlocked) {
- NetworkInfo filtered = new NetworkInfo(networkInfo);
+ final NetworkInfo filtered = new NetworkInfo(networkInfo);
+ // Many legacy types (e.g,. TYPE_MOBILE_HIPRI) are not actually a property of the network
+ // but only exists if an app asks about them or requests them. Ensure the requesting app
+ // gets the type it asks for.
filtered.setType(type);
final DetailedState state = isNetworkWithCapabilitiesBlocked(nc, uid, ignoreBlocked)
? DetailedState.BLOCKED
@@ -1889,27 +1886,49 @@
}
}
+ // TODO: Consider delete this function or turn it into a no-op method.
@Override
public NetworkState[] getAllNetworkState() {
// This contains IMSI details, so make sure the caller is privileged.
PermissionUtils.enforceNetworkStackPermission(mContext);
final ArrayList<NetworkState> result = new ArrayList<>();
- for (Network network : getAllNetworks()) {
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- // TODO: Consider include SUSPENDED networks.
+ for (NetworkStateSnapshot snapshot : getAllNetworkStateSnapshot()) {
+ // NetworkStateSnapshot doesn't contain NetworkInfo, so need to fetch it from the
+ // NetworkAgentInfo.
+ final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(snapshot.network);
if (nai != null && nai.networkInfo.isConnected()) {
- // TODO (b/73321673) : NetworkState contains a copy of the
- // NetworkCapabilities, which may contain UIDs of apps to which the
- // network applies. Should the UIDs be cleared so as not to leak or
- // interfere ?
- result.add(nai.getNetworkState());
+ result.add(new NetworkState(new NetworkInfo(nai.networkInfo),
+ snapshot.linkProperties, snapshot.networkCapabilities, snapshot.network,
+ snapshot.subscriberId));
}
}
return result.toArray(new NetworkState[result.size()]);
}
@Override
+ @NonNull
+ public List<NetworkStateSnapshot> getAllNetworkStateSnapshot() {
+ // This contains IMSI details, so make sure the caller is privileged.
+ PermissionUtils.enforceNetworkStackPermission(mContext);
+
+ final ArrayList<NetworkStateSnapshot> result = new ArrayList<>();
+ for (Network network : getAllNetworks()) {
+ final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+ // TODO: Consider include SUSPENDED networks, which should be considered as
+ // temporary shortage of connectivity of a connected network.
+ if (nai != null && nai.networkInfo.isConnected()) {
+ // TODO (b/73321673) : NetworkStateSnapshot contains a copy of the
+ // NetworkCapabilities, which may contain UIDs of apps to which the
+ // network applies. Should the UIDs be cleared so as not to leak or
+ // interfere ?
+ result.add(nai.getNetworkStateSnapshot());
+ }
+ }
+ return result;
+ }
+
+ @Override
public boolean isActiveNetworkMetered() {
enforceAccessPermission();
@@ -2387,13 +2406,6 @@
final BroadcastOptions opts = BroadcastOptions.makeBasic();
opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.M);
options = opts.toBundle();
- final IBatteryStats bs = mDeps.getBatteryStatsService();
- try {
- bs.noteConnectivityChanged(intent.getIntExtra(
- ConnectivityManager.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_NONE),
- ni.getState().toString());
- } catch (RemoteException e) {
- }
intent.addFlags(Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
}
try {
@@ -3193,16 +3205,16 @@
// Invoke ConnectivityReport generation for this Network test event.
final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(mNetId);
if (nai == null) return;
- final Message m = mConnectivityDiagnosticsHandler.obtainMessage(
- ConnectivityDiagnosticsHandler.EVENT_NETWORK_TESTED,
- new ConnectivityReportEvent(p.timestampMillis, nai));
final PersistableBundle extras = new PersistableBundle();
extras.putInt(KEY_NETWORK_VALIDATION_RESULT, p.result);
extras.putInt(KEY_NETWORK_PROBES_SUCCEEDED_BITMASK, p.probesSucceeded);
extras.putInt(KEY_NETWORK_PROBES_ATTEMPTED_BITMASK, p.probesAttempted);
- m.setData(new Bundle(extras));
+ ConnectivityReportEvent reportEvent =
+ new ConnectivityReportEvent(p.timestampMillis, nai, extras);
+ final Message m = mConnectivityDiagnosticsHandler.obtainMessage(
+ ConnectivityDiagnosticsHandler.EVENT_NETWORK_TESTED, reportEvent);
mConnectivityDiagnosticsHandler.sendMessage(m);
}
@@ -3289,8 +3301,7 @@
final Message msg = mConnectivityDiagnosticsHandler.obtainMessage(
ConnectivityDiagnosticsHandler.EVENT_DATA_STALL_SUSPECTED, detectionMethod, netId,
- p.timestampMillis);
- msg.setData(new Bundle(extras));
+ new Pair<>(p.timestampMillis, extras));
// NetworkStateTrackerHandler currently doesn't take any actions based on data
// stalls so send the message directly to ConnectivityDiagnosticsHandler and avoid
@@ -3831,7 +3842,24 @@
removeListenRequestFromNetworks(req);
}
}
- mDefaultNetworkRequests.remove(nri);
+ if (mDefaultNetworkRequests.remove(nri)) {
+ // If this request was one of the defaults, then the UID rules need to be updated
+ // WARNING : if the app(s) for which this network request is the default are doing
+ // traffic, this will kill their connected sockets, even if an equivalent request
+ // is going to be reinstated right away ; unconnected traffic will go on the default
+ // until the new default is set, which will happen very soon.
+ // TODO : The only way out of this is to diff old defaults and new defaults, and only
+ // remove ranges for those requests that won't have a replacement
+ final NetworkAgentInfo satisfier = nri.getSatisfier();
+ if (null != satisfier) {
+ try {
+ mNetd.networkRemoveUidRanges(satisfier.network.getNetId(),
+ toUidRangeStableParcels(nri.getUids()));
+ } catch (RemoteException e) {
+ loge("Exception setting network preference default network", e);
+ }
+ }
+ }
mNetworkRequestCounter.decrementCount(nri.mUid);
mNetworkRequestInfoLogs.log("RELEASE " + nri);
@@ -4144,13 +4172,6 @@
// nai.networkMonitor() is thread-safe
return nai.networkMonitor();
}
-
- @Override
- public void logEvent(int eventId, String packageName) {
- enforceSettingsPermission();
-
- new MetricsLogger().action(eventId, packageName);
- }
}
public boolean avoidBadWifi() {
@@ -4480,16 +4501,13 @@
case EVENT_SET_REQUIRE_VPN_FOR_UIDS:
handleSetRequireVpnForUids(toBool(msg.arg1), (UidRange[]) msg.obj);
break;
- case EVENT_SET_OEM_NETWORK_PREFERENCE:
+ case EVENT_SET_OEM_NETWORK_PREFERENCE: {
final Pair<OemNetworkPreferences, IOnSetOemNetworkPreferenceListener> arg =
(Pair<OemNetworkPreferences,
IOnSetOemNetworkPreferenceListener>) msg.obj;
- try {
- handleSetOemNetworkPreference(arg.first, arg.second);
- } catch (RemoteException e) {
- loge("handleMessage.EVENT_SET_OEM_NETWORK_PREFERENCE failed", e);
- }
+ handleSetOemNetworkPreference(arg.first, arg.second);
break;
+ }
case EVENT_REPORT_NETWORK_ACTIVITY:
mNetworkActivityTracker.handleReportNetworkActivity();
break;
@@ -5031,10 +5049,16 @@
private void onUserAdded(UserHandle user) {
mPermissionMonitor.onUserAdded(user);
+ if (mOemNetworkPreferences.getNetworkPreferences().size() > 0) {
+ handleSetOemNetworkPreference(mOemNetworkPreferences, null);
+ }
}
private void onUserRemoved(UserHandle user) {
mPermissionMonitor.onUserRemoved(user);
+ if (mOemNetworkPreferences.getNetworkPreferences().size() > 0) {
+ handleSetOemNetworkPreference(mOemNetworkPreferences, null);
+ }
}
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@@ -5247,11 +5271,20 @@
ensureAllNetworkRequestsHaveType(r);
mRequests = initializeRequests(r);
mNetworkRequestForCallback = nri.getNetworkRequestForCallback();
+ // Note here that the satisfier may have corresponded to an old request, that
+ // this code doesn't try to take over. While it is a small discrepancy in the
+ // structure of these requests, it will be fixed by the next rematch and it's
+ // not as bad as having an NRI not storing its real satisfier.
+ // Fixing this discrepancy would require figuring out in the copying code what
+ // is the new request satisfied by this, which is a bit complex and not very
+ // useful as no code is using it until rematch fixes it.
+ mSatisfier = nri.mSatisfier;
mMessenger = nri.mMessenger;
mBinder = nri.mBinder;
mPid = nri.mPid;
mUid = nri.mUid;
mPendingIntent = nri.mPendingIntent;
+ mNetworkRequestCounter.incrementCountOrThrow(mUid);
mCallingAttributionTag = nri.mCallingAttributionTag;
}
@@ -5298,6 +5331,8 @@
public String toString() {
return "uid/pid:" + mUid + "/" + mPid + " active request Id: "
+ (mActiveRequest == null ? null : mActiveRequest.requestId)
+ + " callback request Id: "
+ + mNetworkRequestForCallback.requestId
+ " " + mRequests
+ (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
}
@@ -6461,7 +6496,7 @@
@NonNull NetworkCapabilities agentCaps, @NonNull NetworkCapabilities newNc) {
underlyingNetworks = underlyingNetworksOrDefault(
agentCaps.getOwnerUid(), underlyingNetworks);
- long transportTypes = BitUtils.packBits(agentCaps.getTransportTypes());
+ long transportTypes = NetworkCapabilitiesUtils.packBits(agentCaps.getTransportTypes());
int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
// metered if any underlying is metered, or originally declared metered by the agent.
@@ -6511,7 +6546,7 @@
suspended = false;
}
- newNc.setTransportTypes(BitUtils.unpackBits(transportTypes));
+ newNc.setTransportTypes(NetworkCapabilitiesUtils.unpackBits(transportTypes));
newNc.setLinkDownstreamBandwidthKbps(downKbps);
newNc.setLinkUpstreamBandwidthKbps(upKbps);
newNc.setCapability(NET_CAPABILITY_NOT_METERED, !metered);
@@ -7154,7 +7189,7 @@
toUidRangeStableParcels(nri.getUids()));
}
} catch (RemoteException | ServiceSpecificException e) {
- loge("Exception setting OEM network preference default network :" + e);
+ loge("Exception setting app default network", e);
}
}
@@ -7209,13 +7244,13 @@
private static class NetworkReassignment {
static class RequestReassignment {
@NonNull public final NetworkRequestInfo mNetworkRequestInfo;
- @NonNull public final NetworkRequest mOldNetworkRequest;
- @NonNull public final NetworkRequest mNewNetworkRequest;
+ @Nullable public final NetworkRequest mOldNetworkRequest;
+ @Nullable public final NetworkRequest mNewNetworkRequest;
@Nullable public final NetworkAgentInfo mOldNetwork;
@Nullable public final NetworkAgentInfo mNewNetwork;
RequestReassignment(@NonNull final NetworkRequestInfo networkRequestInfo,
- @NonNull final NetworkRequest oldNetworkRequest,
- @NonNull final NetworkRequest newNetworkRequest,
+ @Nullable final NetworkRequest oldNetworkRequest,
+ @Nullable final NetworkRequest newNetworkRequest,
@Nullable final NetworkAgentInfo oldNetwork,
@Nullable final NetworkAgentInfo newNetwork) {
mNetworkRequestInfo = networkRequestInfo;
@@ -7226,7 +7261,9 @@
}
public String toString() {
- return mNetworkRequestInfo.mRequests.get(0).requestId + " : "
+ final NetworkRequest requestToShow = null != mNewNetworkRequest
+ ? mNewNetworkRequest : mNetworkRequestInfo.mRequests.get(0);
+ return requestToShow.requestId + " : "
+ (null != mOldNetwork ? mOldNetwork.network.getNetId() : "null")
+ " → " + (null != mNewNetwork ? mNewNetwork.network.getNetId() : "null");
}
@@ -7239,7 +7276,7 @@
}
void addRequestReassignment(@NonNull final RequestReassignment reassignment) {
- if (!Build.IS_USER) {
+ if (Build.IS_DEBUGGABLE) {
// The code is never supposed to add two reassignments of the same request. Make
// sure this stays true, but without imposing this expensive check on all
// reassignments on all user devices.
@@ -7286,14 +7323,14 @@
}
private void updateSatisfiersForRematchRequest(@NonNull final NetworkRequestInfo nri,
- @NonNull final NetworkRequest previousRequest,
- @NonNull final NetworkRequest newRequest,
+ @Nullable final NetworkRequest previousRequest,
+ @Nullable final NetworkRequest newRequest,
@Nullable final NetworkAgentInfo previousSatisfier,
@Nullable final NetworkAgentInfo newSatisfier,
final long now) {
if (null != newSatisfier && mNoServiceNetwork != newSatisfier) {
if (VDBG) log("rematch for " + newSatisfier.toShortString());
- if (null != previousSatisfier && mNoServiceNetwork != previousSatisfier) {
+ if (null != previousRequest && null != previousSatisfier) {
if (VDBG || DDBG) {
log(" accepting network in place of " + previousSatisfier.toShortString());
}
@@ -7310,12 +7347,13 @@
newSatisfier.unlingerRequest(NetworkRequest.REQUEST_ID_NONE);
}
+ // if newSatisfier is not null, then newRequest may not be null.
newSatisfier.unlingerRequest(newRequest.requestId);
if (!newSatisfier.addRequest(newRequest)) {
Log.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has "
+ newRequest);
}
- } else if (null != previousSatisfier) {
+ } else if (null != previousRequest && null != previousSatisfier) {
if (DBG) {
log("Network " + previousSatisfier.toShortString() + " stopped satisfying"
+ " request " + previousRequest.requestId);
@@ -7913,7 +7951,8 @@
*
* Must be called on the handler thread.
*/
- private Network[] getDefaultNetworks() {
+ @NonNull
+ private ArrayList<Network> getDefaultNetworks() {
ensureRunningOnConnectivityServiceThread();
final ArrayList<Network> defaultNetworks = new ArrayList<>();
final Set<Integer> activeNetIds = new ArraySet<>();
@@ -7927,7 +7966,7 @@
defaultNetworks.add(nai.network);
}
}
- return defaultNetworks.toArray(new Network[0]);
+ return defaultNetworks;
}
/**
@@ -7952,8 +7991,8 @@
state.legacyNetworkType);
snapshots.add(snapshot);
}
- mStatsService.forceUpdateIfaces(getDefaultNetworks(), snapshots.toArray(
- new NetworkStateSnapshot[0]), activeIface, underlyingNetworkInfos);
+ mStatsManager.notifyNetworkStatus(getDefaultNetworks(),
+ snapshots, activeIface, Arrays.asList(underlyingNetworkInfos));
} catch (Exception ignored) {
}
}
@@ -8272,24 +8311,16 @@
final ConnectivityReportEvent reportEvent =
(ConnectivityReportEvent) msg.obj;
- // This is safe because {@link
- // NetworkMonitorCallbacks#notifyNetworkTestedWithExtras} receives a
- // PersistableBundle and converts it to the Bundle in the incoming Message. If
- // {@link NetworkMonitorCallbacks#notifyNetworkTested} is called, msg.data will
- // not be set. This is also safe, as msg.getData() will return an empty Bundle.
- final PersistableBundle extras = new PersistableBundle(msg.getData());
- handleNetworkTestedWithExtras(reportEvent, extras);
+ handleNetworkTestedWithExtras(reportEvent, reportEvent.mExtras);
break;
}
case EVENT_DATA_STALL_SUSPECTED: {
final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
+ final Pair<Long, PersistableBundle> arg =
+ (Pair<Long, PersistableBundle>) msg.obj;
if (nai == null) break;
- // This is safe because NetworkMonitorCallbacks#notifyDataStallSuspected
- // receives a PersistableBundle and converts it to the Bundle in the incoming
- // Message.
- final PersistableBundle extras = new PersistableBundle(msg.getData());
- handleDataStallSuspected(nai, (long) msg.obj, msg.arg1, extras);
+ handleDataStallSuspected(nai, arg.first, msg.arg1, arg.second);
break;
}
case EVENT_NETWORK_CONNECTIVITY_REPORTED: {
@@ -8353,10 +8384,13 @@
private static class ConnectivityReportEvent {
private final long mTimestampMillis;
@NonNull private final NetworkAgentInfo mNai;
+ private final PersistableBundle mExtras;
- private ConnectivityReportEvent(long timestampMillis, @NonNull NetworkAgentInfo nai) {
+ private ConnectivityReportEvent(long timestampMillis, @NonNull NetworkAgentInfo nai,
+ PersistableBundle p) {
mTimestampMillis = timestampMillis;
mNai = nai;
+ mExtras = p;
}
}
@@ -9033,23 +9067,27 @@
private void handleSetOemNetworkPreference(
@NonNull final OemNetworkPreferences preference,
- @NonNull final IOnSetOemNetworkPreferenceListener listener) throws RemoteException {
+ @Nullable final IOnSetOemNetworkPreferenceListener listener) {
Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
if (DBG) {
log("set OEM network preferences :" + preference.toString());
}
final ArraySet<NetworkRequestInfo> nris =
new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(preference);
- updateDefaultNetworksForOemNetworkPreference(nris);
+ replaceDefaultNetworkRequestsForPreference(nris);
mOemNetworkPreferences = preference;
// TODO http://b/176496396 persist data to shared preferences.
if (null != listener) {
- listener.onComplete();
+ try {
+ listener.onComplete();
+ } catch (RemoteException e) {
+ loge("Can't send onComplete in handleSetOemNetworkPreference", e);
+ }
}
}
- private void updateDefaultNetworksForOemNetworkPreference(
+ private void replaceDefaultNetworkRequestsForPreference(
@NonNull final Set<NetworkRequestInfo> nris) {
// Pass in a defensive copy as this collection will be updated on remove.
handleRemoveNetworkRequests(new ArraySet<>(mDefaultNetworkRequests));
@@ -9061,10 +9099,10 @@
mDefaultNetworkRequests.addAll(nris);
final ArraySet<NetworkRequestInfo> perAppCallbackRequestsToUpdate =
getPerAppCallbackRequestsToUpdate();
- handleRemoveNetworkRequests(perAppCallbackRequestsToUpdate);
final ArraySet<NetworkRequestInfo> nrisToRegister = new ArraySet<>(nris);
nrisToRegister.addAll(
createPerAppCallbackRequestsToRegister(perAppCallbackRequestsToUpdate));
+ handleRemoveNetworkRequests(perAppCallbackRequestsToUpdate);
handleRegisterNetworkRequests(nrisToRegister);
}
@@ -9135,6 +9173,14 @@
return callbackRequestsToRegister;
}
+ private static void setNetworkRequestUids(@NonNull final List<NetworkRequest> requests,
+ @NonNull final Set<UidRange> uids) {
+ final Set<UidRange> ranges = new ArraySet<>(uids);
+ for (final NetworkRequest req : requests) {
+ req.networkCapabilities.setUids(ranges);
+ }
+ }
+
/**
* Class used to generate {@link NetworkRequestInfo} based off of {@link OemNetworkPreferences}.
*/
@@ -9163,6 +9209,14 @@
@NonNull final OemNetworkPreferences preference) {
final SparseArray<Set<Integer>> uids = new SparseArray<>();
final PackageManager pm = mContext.getPackageManager();
+ final List<UserHandle> users =
+ mContext.getSystemService(UserManager.class).getUserHandles(true);
+ if (null == users || users.size() == 0) {
+ if (VDBG || DDBG) {
+ log("No users currently available for setting the OEM network preference.");
+ }
+ return uids;
+ }
for (final Map.Entry<String, Integer> entry :
preference.getNetworkPreferences().entrySet()) {
@OemNetworkPreferences.OemNetworkPreference final int pref = entry.getValue();
@@ -9171,7 +9225,10 @@
if (!uids.contains(pref)) {
uids.put(pref, new ArraySet<>());
}
- uids.get(pref).add(uid);
+ for (final UserHandle ui : users) {
+ // Add the rules for all users as this policy is device wide.
+ uids.get(pref).add(UserHandle.getUid(ui, uid));
+ }
} catch (PackageManager.NameNotFoundException e) {
// Although this may seem like an error scenario, it is ok that uninstalled
// packages are sent on a network preference as the system will watch for
@@ -9211,7 +9268,11 @@
+ " called with invalid preference of " + preference);
}
- setOemNetworkRequestUids(requests, uids);
+ final ArraySet ranges = new ArraySet<Integer>();
+ for (final int uid : uids) {
+ ranges.add(new UidRange(uid, uid));
+ }
+ setNetworkRequestUids(requests, ranges);
return new NetworkRequestInfo(requests);
}
@@ -9244,16 +9305,5 @@
netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
return netCap;
}
-
- private void setOemNetworkRequestUids(@NonNull final List<NetworkRequest> requests,
- @NonNull final Set<Integer> uids) {
- final Set<UidRange> ranges = new ArraySet<>();
- for (final int uid : uids) {
- ranges.add(new UidRange(uid, uid));
- }
- for (final NetworkRequest req : requests) {
- req.networkCapabilities.setUids(ranges);
- }
- }
}
}
diff --git a/services/core/java/com/android/server/ConnectivityServiceInitializer.java b/services/core/java/com/android/server/ConnectivityServiceInitializer.java
index 097441f..b992208 100644
--- a/services/core/java/com/android/server/ConnectivityServiceInitializer.java
+++ b/services/core/java/com/android/server/ConnectivityServiceInitializer.java
@@ -20,8 +20,6 @@
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
import android.content.Context;
-import android.net.INetworkStatsService;
-import android.os.ServiceManager;
import android.util.Log;
/**
@@ -37,7 +35,7 @@
// Load JNI libraries used by ConnectivityService and its dependencies
System.loadLibrary("service-connectivity");
// TODO: Define formal APIs to get the needed services.
- mConnectivity = new ConnectivityService(context, getNetworkStatsService());
+ mConnectivity = new ConnectivityService(context);
}
@Override
@@ -46,9 +44,4 @@
publishBinderService(Context.CONNECTIVITY_SERVICE, mConnectivity,
/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
}
-
- private INetworkStatsService getNetworkStatsService() {
- return INetworkStatsService.Stub.asInterface(
- ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
- }
}
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index 2906cee..9067028 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -839,23 +839,34 @@
}
};
+ // Helper method to copy some of the maps.
+ private static <E> void copyInto(ArrayMap<String, E[]> l, ArrayMap<String, E[]> r) {
+ final int end = r.size();
+ l.ensureCapacity(end);
+ for (int i = 0; i < end; i++) {
+ final E[] val = r.valueAt(i);
+ final String key = r.keyAt(i);
+ l.put(key, Arrays.copyOf(val, val.length));
+ }
+ }
+
// Make <this> a copy of <orig>. The presumption is that <this> is empty but all
// arrays are cleared out explicitly, just to be sure.
protected void copyFrom(IntentResolver orig) {
mFilters.clear();
mFilters.addAll(orig.mFilters);
mTypeToFilter.clear();
- mTypeToFilter.putAll(orig.mTypeToFilter);
+ copyInto(mTypeToFilter, orig.mTypeToFilter);
mBaseTypeToFilter.clear();
- mBaseTypeToFilter.putAll(orig.mBaseTypeToFilter);
+ copyInto(mBaseTypeToFilter, orig.mBaseTypeToFilter);
mWildTypeToFilter.clear();
- mWildTypeToFilter.putAll(orig.mWildTypeToFilter);
+ copyInto(mWildTypeToFilter, orig.mWildTypeToFilter);
mSchemeToFilter.clear();
- mSchemeToFilter.putAll(orig.mSchemeToFilter);
+ copyInto(mSchemeToFilter, orig.mSchemeToFilter);
mActionToFilter.clear();
- mActionToFilter.putAll(orig.mActionToFilter);
+ copyInto(mActionToFilter, orig.mActionToFilter);
mTypedActionToFilter.clear();
- mTypedActionToFilter.putAll(orig.mTypedActionToFilter);
+ copyInto(mTypedActionToFilter, orig.mTypedActionToFilter);
}
/**
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index f5c2aac..960922e 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -182,6 +182,9 @@
private final Runnable mSaveToFile = this::saveToFile;
private final SystemClock mSystemClock;
private final BootThreshold mBootThreshold;
+ private final DeviceConfig.OnPropertiesChangedListener
+ mOnPropertyChangedListener = this::onPropertyChanged;
+
// The set of packages that have been synced with the ExplicitHealthCheckController
@GuardedBy("mLock")
private Set<String> mRequestedHealthCheckPackages = new ArraySet<>();
@@ -669,12 +672,20 @@
}
}
+ @VisibleForTesting
long getTriggerFailureCount() {
synchronized (mLock) {
return mTriggerFailureCount;
}
}
+ @VisibleForTesting
+ long getTriggerFailureDurationMs() {
+ synchronized (mLock) {
+ return mTriggerFailureDurationMs;
+ }
+ }
+
/**
* Serializes and syncs health check requests with the {@link ExplicitHealthCheckController}.
*/
@@ -983,21 +994,25 @@
}
}
+ private void onPropertyChanged(DeviceConfig.Properties properties) {
+ try {
+ updateConfigs();
+ } catch (Exception ignore) {
+ Slog.w(TAG, "Failed to reload device config changes");
+ }
+ }
+
/** Adds a {@link DeviceConfig#OnPropertiesChangedListener}. */
private void setPropertyChangedListenerLocked() {
DeviceConfig.addOnPropertiesChangedListener(
DeviceConfig.NAMESPACE_ROLLBACK,
mContext.getMainExecutor(),
- (properties) -> {
- if (!DeviceConfig.NAMESPACE_ROLLBACK.equals(properties.getNamespace())) {
- return;
- }
- try {
- updateConfigs();
- } catch (Exception ignore) {
- Slog.w(TAG, "Failed to reload device config changes");
- }
- });
+ mOnPropertyChangedListener);
+ }
+
+ @VisibleForTesting
+ void removePropertyChangedListener() {
+ DeviceConfig.removeOnPropertiesChangedListener(mOnPropertyChangedListener);
}
/**
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index c5233f4..27b648e 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -578,6 +578,12 @@
*/
private static final int PBKDF2_HASH_ROUNDS = 1024;
+ private static final String ANR_DELAY_MILLIS_DEVICE_CONFIG_KEY =
+ "anr_delay_millis";
+
+ private static final String ANR_DELAY_NOTIFY_EXTERNAL_STORAGE_SERVICE_DEVICE_CONFIG_KEY =
+ "anr_delay_notify_external_storage_service";
+
/**
* Mounted OBB tracking information. Used to track the current state of all
* OBBs.
@@ -948,25 +954,51 @@
}
}
- // TODO(b/170486601): Check transcoding status based on events pushed from the MediaProvider
private class ExternalStorageServiceAnrController implements AnrController {
@Override
public long getAnrDelayMillis(String packageName, int uid) {
- int delay = SystemProperties.getInt("sys.fuse.transcode_anr_delay", 0);
- Log.d(TAG, "getAnrDelayMillis: " + packageName + ". Delaying for " + delay + "ms");
+ if (!isAppIoBlocked(uid)) {
+ return 0;
+ }
+
+ int delay = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ ANR_DELAY_MILLIS_DEVICE_CONFIG_KEY, 0);
+ Slog.v(TAG, "getAnrDelayMillis for " + packageName + ". " + delay + "ms");
return delay;
}
@Override
public void onAnrDelayStarted(String packageName, int uid) {
- Log.d(TAG, "onAnrDelayStarted: " + packageName);
+ if (!isAppIoBlocked(uid)) {
+ return;
+ }
+
+ boolean notifyExternalStorageService = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ ANR_DELAY_NOTIFY_EXTERNAL_STORAGE_SERVICE_DEVICE_CONFIG_KEY, true);
+ if (notifyExternalStorageService) {
+ Slog.d(TAG, "onAnrDelayStarted for " + packageName
+ + ". Notifying external storage service");
+ try {
+ mStorageSessionController.notifyAnrDelayStarted(packageName, uid, 0 /* tid */,
+ StorageManager.APP_IO_BLOCKED_REASON_TRANSCODING);
+ } catch (ExternalStorageServiceException e) {
+ Slog.e(TAG, "Failed to notify ANR delay started for " + packageName, e);
+ }
+ } else {
+ // TODO(b/170973510): Implement framework spinning dialog for ANR delay
+ }
}
@Override
public boolean onAnrDelayCompleted(String packageName, int uid) {
- boolean show = SystemProperties.getBoolean("sys.fuse.transcode_anr_dialog_show", true);
- Log.d(TAG, "onAnrDelayCompleted: " + packageName + ". Show: " + show);
- return show;
+ if (isAppIoBlocked(uid)) {
+ Slog.d(TAG, "onAnrDelayCompleted for " + packageName + ". Showing ANR dialog...");
+ return true;
+ } else {
+ Slog.d(TAG, "onAnrDelayCompleted for " + packageName + ". Skipping ANR dialog...");
+ return false;
+ }
}
}
@@ -4690,5 +4722,19 @@
Binder.restoreCallingIdentity(token);
}
}
+
+ @Override
+ public List<String> getPrimaryVolumeIds() {
+ final List<String> primaryVolumeIds = new ArrayList<>();
+ synchronized (mLock) {
+ for (int i = 0; i < mVolumes.size(); i++) {
+ final VolumeInfo vol = mVolumes.valueAt(i);
+ if (vol.isPrimary()) {
+ primaryVolumeIds.add(vol.getId());
+ }
+ }
+ }
+ return primaryVolumeIds;
+ }
}
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 5a5f1a3..978bd64 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -72,6 +72,7 @@
import android.telephony.SignalStrength;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
import android.telephony.TelephonyDisplayInfo;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
@@ -153,7 +154,7 @@
int phoneId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
- boolean matchPhoneStateListenerEvent(int event) {
+ boolean matchTelephonyCallbackEvent(int event) {
return (callback != null) && (this.eventList.contains(event));
}
@@ -198,8 +199,8 @@
public int getRegistrationLimit() {
return Binder.withCleanCallingIdentity(() ->
DeviceConfig.getInt(DeviceConfig.NAMESPACE_TELEPHONY,
- PhoneStateListener.FLAG_PER_PID_REGISTRATION_LIMIT,
- PhoneStateListener.DEFAULT_PER_PID_REGISTRATION_LIMIT));
+ TelephonyCallback.FLAG_PER_PID_REGISTRATION_LIMIT,
+ TelephonyCallback.DEFAULT_PER_PID_REGISTRATION_LIMIT));
}
/**
@@ -210,7 +211,7 @@
*/
public boolean isRegistrationLimitEnabledInPlatformCompat(int uid) {
return Binder.withCleanCallingIdentity(() -> CompatChanges.isChangeEnabled(
- PhoneStateListener.PHONE_STATE_LISTENER_LIMIT_CHANGE_ID, uid));
+ TelephonyCallback.PHONE_STATE_LISTENER_LIMIT_CHANGE_ID, uid));
}
}
@@ -332,37 +333,37 @@
static {
REQUIRE_PRECISE_PHONE_STATE_PERMISSION = new HashSet<Integer>();
REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
- PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED);
+ TelephonyCallback.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED);
REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
- PhoneStateListener.EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED);
+ TelephonyCallback.EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED);
REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
- PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED);
+ TelephonyCallback.EVENT_PRECISE_CALL_STATE_CHANGED);
REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
- PhoneStateListener.EVENT_CALL_DISCONNECT_CAUSE_CHANGED);
+ TelephonyCallback.EVENT_CALL_DISCONNECT_CAUSE_CHANGED);
REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
- PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED);
+ TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED);
REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
- PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED);
- REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(PhoneStateListener.EVENT_REGISTRATION_FAILURE);
- REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(PhoneStateListener.EVENT_BARRING_INFO_CHANGED);
+ TelephonyCallback.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED);
+ REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(TelephonyCallback.EVENT_REGISTRATION_FAILURE);
+ REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(TelephonyCallback.EVENT_BARRING_INFO_CHANGED);
REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
- PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED);
+ TelephonyCallback.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED);
REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
- PhoneStateListener.EVENT_DATA_ENABLED_CHANGED);
+ TelephonyCallback.EVENT_DATA_ENABLED_CHANGED);
}
private boolean isLocationPermissionRequired(Set<Integer> events) {
- return events.contains(PhoneStateListener.EVENT_CELL_LOCATION_CHANGED)
- || events.contains(PhoneStateListener.EVENT_CELL_INFO_CHANGED)
- || events.contains(PhoneStateListener.EVENT_REGISTRATION_FAILURE)
- || events.contains(PhoneStateListener.EVENT_BARRING_INFO_CHANGED);
+ return events.contains(TelephonyCallback.EVENT_CELL_LOCATION_CHANGED)
+ || events.contains(TelephonyCallback.EVENT_CELL_INFO_CHANGED)
+ || events.contains(TelephonyCallback.EVENT_REGISTRATION_FAILURE)
+ || events.contains(TelephonyCallback.EVENT_BARRING_INFO_CHANGED);
}
private boolean isPhoneStatePermissionRequired(Set<Integer> events) {
- return events.contains(PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)
- || events.contains(PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)
- || events.contains(PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED)
- || events.contains(PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED);
+ return events.contains(TelephonyCallback.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)
+ || events.contains(TelephonyCallback.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)
+ || events.contains(TelephonyCallback.EVENT_EMERGENCY_NUMBER_LIST_CHANGED)
+ || events.contains(TelephonyCallback.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED);
}
private boolean isPrecisePhoneStatePermissionRequired(Set<Integer> events) {
@@ -375,14 +376,14 @@
}
private boolean isActiveEmergencySessionPermissionRequired(Set<Integer> events) {
- return events.contains(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_CALL)
- || events.contains(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_SMS);
+ return events.contains(TelephonyCallback.EVENT_OUTGOING_EMERGENCY_CALL)
+ || events.contains(TelephonyCallback.EVENT_OUTGOING_EMERGENCY_SMS);
}
private boolean isPrivilegedPhoneStatePermissionRequired(Set<Integer> events) {
- return events.contains(PhoneStateListener.EVENT_SRVCC_STATE_CHANGED)
- || events.contains(PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED)
- || events.contains(PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED);
+ return events.contains(TelephonyCallback.EVENT_SRVCC_STATE_CHANGED)
+ || events.contains(TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED)
+ || events.contains(TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED);
}
private static final int MSG_USER_SWITCHED = 1;
@@ -903,7 +904,7 @@
log("listen: Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId);
}
if (notifyNow && validatePhoneId(phoneId)) {
- if (events.contains(PhoneStateListener.EVENT_SERVICE_STATE_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_SERVICE_STATE_CHANGED)){
try {
if (VDBG) log("listen: call onSSC state=" + mServiceState[phoneId]);
ServiceState rawSs = new ServiceState(mServiceState[phoneId]);
@@ -920,7 +921,7 @@
remove(r.binder);
}
}
- if (events.contains(PhoneStateListener.EVENT_SIGNAL_STRENGTH_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_SIGNAL_STRENGTH_CHANGED)) {
try {
if (mSignalStrength[phoneId] != null) {
int gsmSignalStrength = mSignalStrength[phoneId]
@@ -933,7 +934,7 @@
}
}
if (events.contains(
- PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)) {
+ TelephonyCallback.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)) {
try {
r.callback.onMessageWaitingIndicatorChanged(
mMessageWaiting[phoneId]);
@@ -942,7 +943,7 @@
}
}
if (events.contains(
- PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)) {
+ TelephonyCallback.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)) {
try {
r.callback.onCallForwardingIndicatorChanged(
mCallForwarding[phoneId]);
@@ -951,7 +952,7 @@
}
}
if (validateEventAndUserLocked(
- r, PhoneStateListener.EVENT_CELL_LOCATION_CHANGED)) {
+ r, TelephonyCallback.EVENT_CELL_LOCATION_CHANGED)) {
try {
if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[phoneId]);
if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
@@ -963,7 +964,7 @@
remove(r.binder);
}
}
- if (events.contains(PhoneStateListener.EVENT_CALL_STATE_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_CALL_STATE_CHANGED)) {
try {
r.callback.onCallStateChanged(mCallState[phoneId],
getCallIncomingNumber(r, phoneId));
@@ -971,7 +972,7 @@
remove(r.binder);
}
}
- if (events.contains(PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED)) {
try {
r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
mDataConnectionNetworkType[phoneId]);
@@ -979,14 +980,14 @@
remove(r.binder);
}
}
- if (events.contains(PhoneStateListener.EVENT_DATA_ACTIVITY_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_DATA_ACTIVITY_CHANGED)) {
try {
r.callback.onDataActivity(mDataActivity[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
- if (events.contains(PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED)) {
try {
if (mSignalStrength[phoneId] != null) {
r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
@@ -996,7 +997,7 @@
}
}
if (events.contains(
- PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
+ TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
updateReportSignalStrengthDecision(r.subId);
try {
if (mSignalStrength[phoneId] != null) {
@@ -1007,7 +1008,7 @@
}
}
if (validateEventAndUserLocked(
- r, PhoneStateListener.EVENT_CELL_INFO_CHANGED)) {
+ r, TelephonyCallback.EVENT_CELL_INFO_CHANGED)) {
try {
if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
+ mCellInfo.get(phoneId));
@@ -1019,14 +1020,14 @@
remove(r.binder);
}
}
- if (events.contains(PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_PRECISE_CALL_STATE_CHANGED)) {
try {
r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
- if (events.contains(PhoneStateListener.EVENT_CALL_DISCONNECT_CAUSE_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_CALL_DISCONNECT_CAUSE_CHANGED)) {
try {
r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[phoneId],
mCallPreciseDisconnectCause[phoneId]);
@@ -1034,7 +1035,7 @@
remove(r.binder);
}
}
- if (events.contains(PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED)) {
try {
r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(phoneId));
} catch (RemoteException ex) {
@@ -1042,7 +1043,7 @@
}
}
if (events.contains(
- PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED)) {
+ TelephonyCallback.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED)) {
try {
for (PreciseDataConnectionState pdcs
: mPreciseDataConnectionStates.get(phoneId).values()) {
@@ -1052,14 +1053,14 @@
remove(r.binder);
}
}
- if (events.contains(PhoneStateListener.EVENT_CARRIER_NETWORK_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_CARRIER_NETWORK_CHANGED)) {
try {
r.callback.onCarrierNetworkChange(mCarrierNetworkChangeState);
} catch (RemoteException ex) {
remove(r.binder);
}
}
- if (events.contains(PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED)) {
try {
r.callback.onVoiceActivationStateChanged(
mVoiceActivationState[phoneId]);
@@ -1067,21 +1068,21 @@
remove(r.binder);
}
}
- if (events.contains(PhoneStateListener.EVENT_DATA_ACTIVATION_STATE_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_DATA_ACTIVATION_STATE_CHANGED)) {
try {
r.callback.onDataActivationStateChanged(mDataActivationState[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
- if (events.contains(PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_USER_MOBILE_DATA_STATE_CHANGED)) {
try {
r.callback.onUserMobileDataStateChanged(mUserMobileDataState[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
- if (events.contains(PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_DISPLAY_INFO_CHANGED)) {
try {
if (mTelephonyDisplayInfos[phoneId] != null) {
r.callback.onDisplayInfoChanged(mTelephonyDisplayInfos[phoneId]);
@@ -1090,14 +1091,14 @@
remove(r.binder);
}
}
- if (events.contains(PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_EMERGENCY_NUMBER_LIST_CHANGED)) {
try {
r.callback.onEmergencyNumberListChanged(mEmergencyNumberList);
} catch (RemoteException ex) {
remove(r.binder);
}
}
- if (events.contains(PhoneStateListener.EVENT_PHONE_CAPABILITY_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_PHONE_CAPABILITY_CHANGED)) {
try {
r.callback.onPhoneCapabilityChanged(mPhoneCapability);
} catch (RemoteException ex) {
@@ -1105,35 +1106,35 @@
}
}
if (events.contains(
- PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED)) {
+ TelephonyCallback.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED)) {
try {
r.callback.onActiveDataSubIdChanged(mActiveDataSubId);
} catch (RemoteException ex) {
remove(r.binder);
}
}
- if (events.contains(PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED)) {
try {
r.callback.onRadioPowerStateChanged(mRadioPowerState);
} catch (RemoteException ex) {
remove(r.binder);
}
}
- if (events.contains(PhoneStateListener.EVENT_SRVCC_STATE_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_SRVCC_STATE_CHANGED)) {
try {
r.callback.onSrvccStateChanged(mSrvccState[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
- if (events.contains(PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)) {
try {
r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
- if (events.contains(PhoneStateListener.EVENT_BARRING_INFO_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_BARRING_INFO_CHANGED)) {
BarringInfo barringInfo = mBarringInfo.get(phoneId);
BarringInfo biNoLocation = barringInfo != null
? barringInfo.createLocationInfoSanitizedCopy() : null;
@@ -1147,7 +1148,7 @@
}
}
if (events.contains(
- PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED)) {
+ TelephonyCallback.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED)) {
try {
r.callback.onPhysicalChannelConfigChanged(
mPhysicalChannelConfigs);
@@ -1156,7 +1157,7 @@
}
}
if (events.contains(
- PhoneStateListener.EVENT_DATA_ENABLED_CHANGED)) {
+ TelephonyCallback.EVENT_DATA_ENABLED_CHANGED)) {
try {
r.callback.onDataEnabledChanged(
mIsDataEnabled[phoneId], mDataEnabledReason[phoneId]);
@@ -1165,7 +1166,7 @@
}
}
if (events.contains(
- PhoneStateListener.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED)) {
+ TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED)) {
try {
r.callback.onAllowedNetworkTypesChanged(mAllowedNetworkTypesList);
} catch (RemoteException ex) {
@@ -1183,8 +1184,8 @@
for (Record r : mRecords) {
// If any of the system clients wants to always listen to signal strength,
// we need to set it on.
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
telephonyManager.createForSubscriptionId(subscriptionId)
.setAlwaysReportSignalStrength(true);
return;
@@ -1233,7 +1234,7 @@
throw new IllegalStateException(errorMsg);
}
} else if (doesLimitApply && numRecordsForPid
- >= PhoneStateListener.DEFAULT_PER_PID_REGISTRATION_LIMIT / 2) {
+ >= TelephonyCallback.DEFAULT_PER_PID_REGISTRATION_LIMIT / 2) {
// Log the warning independently of the dynamically set limit -- apps shouldn't be
// doing this regardless of whether we're throwing them an exception for it.
Rlog.w(TAG, "Pid " + callingPid + " has exceeded half the number of permissible"
@@ -1284,8 +1285,8 @@
// Every time a client that is registrating to always receive the signal
// strength is removed from registry records, we need to check if
// the signal strength decision needs to update on its slot.
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
updateReportSignalStrengthDecision(r.subId);
}
return;
@@ -1305,7 +1306,7 @@
synchronized (mRecords) {
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(PhoneStateListener.EVENT_CALL_STATE_CHANGED)
+ if (r.matchTelephonyCallbackEvent(TelephonyCallback.EVENT_CALL_STATE_CHANGED)
&& (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
try {
// Ensure the listener has read call log permission; if they do not return
@@ -1340,7 +1341,7 @@
mCallState[phoneId] = state;
mCallIncomingNumber[phoneId] = incomingNumber;
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(PhoneStateListener.EVENT_CALL_STATE_CHANGED)
+ if (r.matchTelephonyCallbackEvent(TelephonyCallback.EVENT_CALL_STATE_CHANGED)
&& (r.subId == subId)
&& (r.subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
try {
@@ -1382,8 +1383,8 @@
log("notifyServiceStateForSubscriber: r=" + r + " subId=" + subId
+ " phoneId=" + phoneId + " state=" + state);
}
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_SERVICE_STATE_CHANGED)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_SERVICE_STATE_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
@@ -1444,8 +1445,8 @@
}
try {
if ((activationType == SIM_ACTIVATION_TYPE_VOICE)
- && r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED)
+ && r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
if (DBG) {
log("notifyVoiceActivationStateForPhoneId: callback.onVASC r=" + r
@@ -1455,8 +1456,8 @@
r.callback.onVoiceActivationStateChanged(activationState);
}
if ((activationType == SIM_ACTIVATION_TYPE_DATA)
- && r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_DATA_ACTIVATION_STATE_CHANGED)
+ && r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_DATA_ACTIVATION_STATE_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
if (DBG) {
log("notifyDataActivationStateForPhoneId: callback.onDASC r=" + r
@@ -1495,11 +1496,10 @@
log("notifySignalStrengthForPhoneId: r=" + r + " subId=" + subId
+ " phoneId=" + phoneId + " ss=" + signalStrength);
}
- if ((r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED)
- || r.matchPhoneStateListenerEvent(
- PhoneStateListener.
- EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED))
+ if ((r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED)
+ || r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED))
&& idMatch(r.subId, subId, phoneId)) {
try {
if (DBG) {
@@ -1512,8 +1512,8 @@
mRemoveList.add(r.binder);
}
}
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_SIGNAL_STRENGTH_CHANGED)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_SIGNAL_STRENGTH_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
int gsmSignalStrength = signalStrength.getGsmSignalStrength();
@@ -1559,8 +1559,8 @@
log("notifyCarrierNetworkChange: active=" + active + "subId: " + subId);
}
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_CARRIER_NETWORK_CHANGED)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_CARRIER_NETWORK_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onCarrierNetworkChange(active);
@@ -1592,7 +1592,7 @@
mCellInfo.set(phoneId, cellInfo);
for (Record r : mRecords) {
if (validateEventAndUserLocked(
- r, PhoneStateListener.EVENT_CELL_INFO_CHANGED)
+ r, TelephonyCallback.EVENT_CELL_INFO_CHANGED)
&& idMatch(r.subId, subId, phoneId)
&& (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
&& checkFineLocationAccess(r, Build.VERSION_CODES.Q))) {
@@ -1625,8 +1625,8 @@
if (validatePhoneId(phoneId)) {
mMessageWaiting[phoneId] = mwi;
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onMessageWaitingIndicatorChanged(mwi);
@@ -1652,8 +1652,8 @@
if (validatePhoneId(phoneId)) {
mUserMobileDataState[phoneId] = state;
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_USER_MOBILE_DATA_STATE_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onUserMobileDataStateChanged(state);
@@ -1691,8 +1691,8 @@
if (validatePhoneId(phoneId)) {
mTelephonyDisplayInfos[phoneId] = telephonyDisplayInfo;
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_DISPLAY_INFO_CHANGED)
&& idMatchWithoutDefaultPhoneCheck(r.subId, subId)) {
try {
r.callback.onDisplayInfoChanged(telephonyDisplayInfo);
@@ -1723,8 +1723,8 @@
if (validatePhoneId(phoneId)) {
mCallForwarding[phoneId] = cfi;
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onCallForwardingIndicatorChanged(cfi);
@@ -1752,8 +1752,8 @@
mDataActivity[phoneId] = state;
for (Record r : mRecords) {
// Notify by correct subId.
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_DATA_ACTIVITY_CHANGED)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_DATA_ACTIVITY_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onDataActivity(state);
@@ -1800,8 +1800,8 @@
log(str);
mLocalLog.log(str);
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
if (DBG) {
@@ -1825,8 +1825,8 @@
.remove(key);
if (!Objects.equals(oldState, preciseState)) {
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onPreciseDataConnectionStateChanged(preciseState);
@@ -1872,7 +1872,7 @@
mCellIdentity[phoneId] = cellIdentity;
for (Record r : mRecords) {
if (validateEventAndUserLocked(
- r, PhoneStateListener.EVENT_CELL_LOCATION_CHANGED)
+ r, TelephonyCallback.EVENT_CELL_LOCATION_CHANGED)
&& idMatch(r.subId, subId, phoneId)
&& (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
&& checkFineLocationAccess(r, Build.VERSION_CODES.Q))) {
@@ -1925,8 +1925,8 @@
}
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_PRECISE_CALL_STATE_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]);
@@ -1934,8 +1934,8 @@
mRemoveList.add(r.binder);
}
}
- if (notifyCallAttributes && r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED)
+ if (notifyCallAttributes && r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
@@ -1959,8 +1959,9 @@
mCallDisconnectCause[phoneId] = disconnectCause;
mCallPreciseDisconnectCause[phoneId] = preciseDisconnectCause;
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(PhoneStateListener
- .LISTEN_CALL_DISCONNECT_CAUSES) && idMatch(r.subId, subId, phoneId)) {
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_CALL_DISCONNECT_CAUSE_CHANGED)
+ && idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[phoneId],
mCallPreciseDisconnectCause[phoneId]);
@@ -1983,8 +1984,8 @@
if (validatePhoneId(phoneId)) {
mImsReasonInfo.set(phoneId, imsReasonInfo);
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
if (DBG_LOC) {
@@ -2015,8 +2016,8 @@
if (validatePhoneId(phoneId)) {
mSrvccState[phoneId] = state;
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_SRVCC_STATE_CHANGED)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_SRVCC_STATE_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
if (DBG_LOC) {
@@ -2044,8 +2045,8 @@
if (VDBG) {
log("notifyOemHookRawEventForSubscriber: r=" + r + " subId=" + subId);
}
- if ((r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_OEM_HOOK_RAW))
+ if ((r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_OEM_HOOK_RAW))
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onOemHookRawEvent(rawData);
@@ -2072,8 +2073,8 @@
mPhoneCapability = capability;
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_PHONE_CAPABILITY_CHANGED)) {
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_PHONE_CAPABILITY_CHANGED)) {
try {
r.callback.onPhoneCapabilityChanged(capability);
} catch (RemoteException ex) {
@@ -2097,8 +2098,8 @@
mActiveDataSubId = activeDataSubId;
synchronized (mRecords) {
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED)) {
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED)) {
try {
r.callback.onActiveDataSubIdChanged(activeDataSubId);
} catch (RemoteException ex) {
@@ -2124,8 +2125,8 @@
mRadioPowerState = state;
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onRadioPowerStateChanged(state);
@@ -2153,8 +2154,8 @@
mEmergencyNumberList = tm.getEmergencyNumberList();
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_EMERGENCY_NUMBER_LIST_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onEmergencyNumberListChanged(mEmergencyNumberList);
@@ -2185,8 +2186,8 @@
}
for (Record r : mRecords) {
// Send to all listeners regardless of subscription
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_OUTGOING_EMERGENCY_CALL)) {
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_OUTGOING_EMERGENCY_CALL)) {
try {
r.callback.onOutgoingEmergencyCall(emergencyNumber, subId);
} catch (RemoteException ex) {
@@ -2204,13 +2205,14 @@
if (!checkNotifyPermission("notifyOutgoingEmergencySms()")) {
return;
}
+
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
mOutgoingSmsEmergencyNumber[phoneId] = emergencyNumber;
for (Record r : mRecords) {
// Send to all listeners regardless of subscription
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_OUTGOING_EMERGENCY_SMS)) {
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_OUTGOING_EMERGENCY_SMS)) {
try {
r.callback.onOutgoingEmergencySms(emergencyNumber, subId);
} catch (RemoteException ex) {
@@ -2239,8 +2241,8 @@
callNetworkType, callQuality);
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
@@ -2270,8 +2272,8 @@
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_REGISTRATION_FAILURE)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_REGISTRATION_FAILURE)
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onRegistrationFailed(
@@ -2313,8 +2315,8 @@
BarringInfo biNoLocation = barringInfo.createLocationInfoSanitizedCopy();
if (VDBG) log("listen: call onBarringInfoChanged=" + barringInfo);
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_BARRING_INFO_CHANGED)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_BARRING_INFO_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
if (DBG_LOC) {
@@ -2356,8 +2358,8 @@
if (validatePhoneId(phoneId)) {
mPhysicalChannelConfigs.set(phoneId, configs.get(phoneId));
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
if (DBG_LOC) {
@@ -2386,7 +2388,7 @@
* {@link TelephonyManager}.
*/
public void notifyDataEnabled(int phoneId, int subId, boolean enabled,
- @TelephonyManager.DataEnabledReason int reason) {
+ @TelephonyManager.DataEnabledReason int reason) {
if (!checkNotifyPermission("notifyDataEnabled()")) {
return;
}
@@ -2401,8 +2403,8 @@
mIsDataEnabled[phoneId] = enabled;
mDataEnabledReason[phoneId] = reason;
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_DATA_ENABLED_CHANGED)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_DATA_ENABLED_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
r.callback.onDataEnabledChanged(enabled, reason);
@@ -2435,8 +2437,8 @@
mAllowedNetworkTypesList = allowedNetworkTypesList;
for (Record r : mRecords) {
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED)
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED)
&& idMatch(r.subId, subId, phoneId)) {
try {
if (VDBG) {
@@ -2817,7 +2819,7 @@
android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION, null);
}
- if ((events.contains(PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED))) {
+ if ((events.contains(TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED))) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH, null);
}
@@ -2847,7 +2849,7 @@
try {
foregroundUser = ActivityManager.getCurrentUser();
valid = UserHandle.getUserId(r.callerUid) == foregroundUser
- && r.matchPhoneStateListenerEvent(event);
+ && r.matchTelephonyCallbackEvent(event);
if (DBG | DBG_LOC) {
log("validateEventAndUserLocked: valid=" + valid
+ " r.callerUid=" + r.callerUid + " foregroundUser=" + foregroundUser
@@ -2972,7 +2974,7 @@
return;
}
- if ((events.contains(PhoneStateListener.EVENT_SERVICE_STATE_CHANGED))) {
+ if ((events.contains(TelephonyCallback.EVENT_SERVICE_STATE_CHANGED))) {
try {
if (VDBG) log("checkPossibleMissNotify: onServiceStateChanged state=" +
mServiceState[phoneId]);
@@ -2991,9 +2993,9 @@
}
}
- if (events.contains(PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED)
+ if (events.contains(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED)
|| events.contains(
- PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
+ TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
try {
if (mSignalStrength[phoneId] != null) {
SignalStrength signalStrength = mSignalStrength[phoneId];
@@ -3008,7 +3010,7 @@
}
}
- if (events.contains(PhoneStateListener.EVENT_SIGNAL_STRENGTH_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_SIGNAL_STRENGTH_CHANGED)) {
try {
if (mSignalStrength[phoneId] != null) {
int gsmSignalStrength = mSignalStrength[phoneId]
@@ -3025,7 +3027,7 @@
}
}
- if (validateEventAndUserLocked(r, PhoneStateListener.EVENT_CELL_INFO_CHANGED)) {
+ if (validateEventAndUserLocked(r, TelephonyCallback.EVENT_CELL_INFO_CHANGED)) {
try {
if (DBG_LOC) {
log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = "
@@ -3040,7 +3042,7 @@
}
}
- if (events.contains(PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_USER_MOBILE_DATA_STATE_CHANGED)) {
try {
if (VDBG) {
log("checkPossibleMissNotify: onUserMobileDataStateChanged phoneId="
@@ -3052,7 +3054,7 @@
}
}
- if (events.contains(PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_DISPLAY_INFO_CHANGED)) {
try {
if (VDBG) {
log("checkPossibleMissNotify: onDisplayInfoChanged phoneId="
@@ -3066,7 +3068,7 @@
}
}
- if (events.contains(PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)) {
try {
if (VDBG) {
log("checkPossibleMissNotify: onMessageWaitingIndicatorChanged phoneId="
@@ -3079,7 +3081,7 @@
}
}
- if (events.contains(PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)) {
try {
if (VDBG) {
log("checkPossibleMissNotify: onCallForwardingIndicatorChanged phoneId="
@@ -3092,7 +3094,7 @@
}
}
- if (validateEventAndUserLocked(r, PhoneStateListener.EVENT_CELL_LOCATION_CHANGED)) {
+ if (validateEventAndUserLocked(r, TelephonyCallback.EVENT_CELL_LOCATION_CHANGED)) {
try {
if (DBG_LOC) {
log("checkPossibleMissNotify: onCellLocationChanged mCellIdentity = "
@@ -3108,7 +3110,7 @@
}
}
- if (events.contains(PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED)) {
+ if (events.contains(TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED)) {
try {
if (DBG) {
log("checkPossibleMissNotify: onDataConnectionStateChanged(mDataConnectionState"
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 8d5d3d9..ad2f524 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -35,6 +35,7 @@
import android.net.vcn.IVcnStatusCallback;
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
import android.net.vcn.VcnConfig;
+import android.net.vcn.VcnManager;
import android.net.vcn.VcnManager.VcnErrorCode;
import android.net.vcn.VcnUnderlyingNetworkPolicy;
import android.net.wifi.WifiInfo;
@@ -724,6 +725,26 @@
}
}
+ private boolean isCallbackPermissioned(
+ @NonNull VcnStatusCallbackInfo cbInfo, @NonNull ParcelUuid subgroup) {
+ if (!subgroup.equals(cbInfo.mSubGroup)) {
+ return false;
+ }
+
+ if (!mLastSnapshot.packageHasPermissionsForSubscriptionGroup(subgroup, cbInfo.mPkgName)) {
+ return false;
+ }
+
+ if (!mLocationPermissionChecker.checkLocationPermission(
+ cbInfo.mPkgName,
+ "VcnStatusCallback" /* featureId */,
+ cbInfo.mUid,
+ null /* message */)) {
+ return false;
+ }
+ return true;
+ }
+
/** Registers the provided callback for receiving VCN status updates. */
@Override
public void registerVcnStatusCallback(
@@ -758,6 +779,27 @@
}
mRegisteredStatusCallbacks.put(cbBinder, cbInfo);
+
+ // now that callback is registered, send it the VCN's current status
+ final VcnConfig vcnConfig = mConfigs.get(subGroup);
+ final Vcn vcn = mVcns.get(subGroup);
+ final int vcnStatus;
+ if (vcnConfig == null || !isCallbackPermissioned(cbInfo, subGroup)) {
+ vcnStatus = VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
+ } else if (vcn == null) {
+ vcnStatus = VcnManager.VCN_STATUS_CODE_INACTIVE;
+ } else if (vcn.isActive()) {
+ vcnStatus = VcnManager.VCN_STATUS_CODE_ACTIVE;
+ } else {
+ // TODO(b/181789060): create Vcn.getStatus() and Log.WTF() for unknown status
+ vcnStatus = VcnManager.VCN_STATUS_CODE_SAFE_MODE;
+ }
+
+ try {
+ cbInfo.mCallback.onVcnStatusChanged(vcnStatus);
+ } catch (RemoteException e) {
+ Slog.d(TAG, "VcnStatusCallback threw on VCN status change", e);
+ }
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -806,26 +848,6 @@
mSubGroup = Objects.requireNonNull(subGroup, "Missing subGroup");
}
- private boolean isCallbackPermissioned(@NonNull VcnStatusCallbackInfo cbInfo) {
- if (!mSubGroup.equals(cbInfo.mSubGroup)) {
- return false;
- }
-
- if (!mLastSnapshot.packageHasPermissionsForSubscriptionGroup(
- mSubGroup, cbInfo.mPkgName)) {
- return false;
- }
-
- if (!mLocationPermissionChecker.checkLocationPermission(
- cbInfo.mPkgName,
- "VcnStatusCallback" /* featureId */,
- cbInfo.mUid,
- null /* message */)) {
- return false;
- }
- return true;
- }
-
@Override
public void onEnteredSafeMode() {
synchronized (mLock) {
@@ -838,7 +860,7 @@
// Notify all registered StatusCallbacks for this subGroup
for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) {
- if (isCallbackPermissioned(cbInfo)) {
+ if (isCallbackPermissioned(cbInfo, mSubGroup)) {
Binder.withCleanCallingIdentity(
() ->
cbInfo.mCallback.onVcnStatusChanged(
@@ -862,7 +884,7 @@
// Notify all registered StatusCallbacks for this subGroup
for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) {
- if (isCallbackPermissioned(cbInfo)) {
+ if (isCallbackPermissioned(cbInfo, mSubGroup)) {
Binder.withCleanCallingIdentity(
() ->
cbInfo.mCallback.onGatewayConnectionError(
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index d998ebb..277cb8c 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -86,6 +86,7 @@
import android.app.ServiceStartArgs;
import android.app.admin.DevicePolicyEventLogger;
import android.app.compat.CompatChanges;
+import android.app.usage.UsageEvents;
import android.appwidget.AppWidgetManagerInternal;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
@@ -2464,6 +2465,10 @@
s.setAllowedBgFgsStartsByBinding(true);
}
+ if ((flags & Context.BIND_NOT_APP_COMPONENT_USAGE) != 0) {
+ s.isNotAppComponentUsage = true;
+ }
+
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app.mServices, c, true);
}
@@ -3332,6 +3337,14 @@
return msg;
}
+ // Report usage if binding is from a different package except for explicitly exempted
+ // bindings
+ if (!r.appInfo.packageName.equals(r.mRecentCallingPackage)
+ && !r.isNotAppComponentUsage) {
+ mAm.mUsageStatsService.reportEvent(
+ r.packageName, r.userId, UsageEvents.Event.APP_COMPONENT_USED);
+ }
+
// Service is now being launched, its package can't be stopped.
try {
AppGlobals.getPackageManager().setPackageStoppedState(
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e8a4fa2..9e5d7e4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -50,7 +50,6 @@
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
import static android.os.IServiceManager.DUMP_FLAG_PROTO;
import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED;
-import static android.os.PowerWhitelistManager.REASON_UNKNOWN;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.Process.BLUETOOTH_UID;
import static android.os.Process.FIRST_APPLICATION_UID;
@@ -92,6 +91,7 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALLOWLISTS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_CHECK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP;
@@ -104,7 +104,6 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALLOWLISTS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP;
@@ -1178,14 +1177,16 @@
final String tag;
final int type;
final @ReasonCode int reasonCode;
+ final int callingUid;
PendingTempAllowlist(int targetUid, long duration, @ReasonCode int reasonCode, String tag,
- int type) {
+ int type, int callingUid) {
this.targetUid = targetUid;
this.duration = duration;
this.tag = tag;
this.type = type;
this.reasonCode = reasonCode;
+ this.callingUid = callingUid;
}
void dumpDebug(ProtoOutputStream proto, long fieldId) {
@@ -1198,6 +1199,8 @@
proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.TYPE, type);
proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.REASON_CODE,
reasonCode);
+ proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.CALLING_UID,
+ callingUid);
proto.end(token);
}
}
@@ -2684,6 +2687,11 @@
}
if (mUsageStatsService != null) {
mUsageStatsService.reportEvent(activity, userId, event, appToken.hashCode(), taskRoot);
+ if (event == Event.ACTIVITY_RESUMED) {
+ // Report component usage as an activity is an app component
+ mUsageStatsService.reportEvent(
+ activity.getPackageName(), userId, Event.APP_COMPONENT_USED);
+ }
}
ContentCaptureManagerInternal contentCaptureService = mContentCaptureService;
if (contentCaptureService != null && (event == Event.ACTIVITY_PAUSED
@@ -4963,7 +4971,7 @@
}
@Override
- public List<ResolveInfo> queryIntentComponentsForIntentSender(
+ public ParceledListSlice<ResolveInfo> queryIntentComponentsForIntentSender(
IIntentSender pendingResult, int matchFlags) {
enforceCallingPermission(Manifest.permission.GET_INTENT_SENDER_INTENT,
"queryIntentComponentsForIntentSender()");
@@ -4981,15 +4989,15 @@
final int userId = res.key.userId;
switch (res.key.type) {
case ActivityManager.INTENT_SENDER_ACTIVITY:
- return mContext.getPackageManager().queryIntentActivitiesAsUser(
- intent, matchFlags, userId);
+ return new ParceledListSlice<>(mContext.getPackageManager()
+ .queryIntentActivitiesAsUser(intent, matchFlags, userId));
case ActivityManager.INTENT_SENDER_SERVICE:
case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE:
- return mContext.getPackageManager().queryIntentServicesAsUser(
- intent, matchFlags, userId);
+ return new ParceledListSlice<>(mContext.getPackageManager()
+ .queryIntentServicesAsUser(intent, matchFlags, userId));
case ActivityManager.INTENT_SENDER_BROADCAST:
- return mContext.getPackageManager().queryBroadcastReceiversAsUser(
- intent, matchFlags, userId);
+ return new ParceledListSlice<>(mContext.getPackageManager()
+ .queryBroadcastReceiversAsUser(intent, matchFlags, userId));
default: // ActivityManager.INTENT_SENDER_ACTIVITY_RESULT
throw new IllegalStateException("Unsupported intent sender type: " + res.key.type);
}
@@ -6099,6 +6107,10 @@
updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
}
+ // Report usage as process is persistent and being started.
+ mUsageStatsService.reportEvent(info.packageName, UserHandle.getUserId(app.uid),
+ Event.APP_COMPONENT_USED);
+
// This package really, really can not be stopped.
try {
AppGlobals.getPackageManager().setPackageStoppedState(
@@ -9222,6 +9234,8 @@
pw.print(ptw.type);
pw.print(" ");
pw.print(ptw.reasonCode);
+ pw.print(" ");
+ pw.print(ptw.callingUid);
}
}
}
@@ -10776,9 +10790,12 @@
pw.print(" unmapped + ");
pw.print(stringifyKBSize(ionPool));
pw.println(" pools)");
+ kernelUsed += ionUnmapped;
// Note: mapped ION memory is not accounted in PSS due to VM_PFNMAP flag being
- // set on ION VMAs, therefore consider the entire ION heap as used kernel memory
- kernelUsed += ionHeap;
+ // set on ION VMAs, however it might be included by the memtrack HAL.
+ // Replace memtrack HAL reported Graphics category with mapped dmabufs
+ ss[INDEX_TOTAL_PSS] -= ss[INDEX_TOTAL_MEMTRACK_GRAPHICS];
+ ss[INDEX_TOTAL_PSS] += dmabufMapped;
} else {
final long totalExportedDmabuf = Debug.getDmabufTotalExportedKb();
if (totalExportedDmabuf >= 0) {
@@ -14501,7 +14518,8 @@
String reason, int type, int callingUid) {
synchronized (mProcLock) {
mPendingTempAllowlist.put(targetUid,
- new PendingTempAllowlist(targetUid, duration, reasonCode, reason, type));
+ new PendingTempAllowlist(targetUid, duration, reasonCode, reason, type,
+ callingUid));
setUidTempAllowlistStateLSP(targetUid, true);
mUiHandler.obtainMessage(PUSH_TEMP_ALLOWLIST_UI_MSG).sendToTarget();
@@ -14532,7 +14550,8 @@
for (int i = 0; i < N; i++) {
PendingTempAllowlist ptw = list[i];
mLocalDeviceIdleController.addPowerSaveTempWhitelistAppDirect(ptw.targetUid,
- ptw.duration, ptw.type, true, ptw.reasonCode, ptw.tag);
+ ptw.duration, ptw.type, true, ptw.reasonCode, ptw.tag,
+ ptw.callingUid);
}
}
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index f8494d8..31ea14a 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -1517,17 +1517,21 @@
long kernelUsed = memInfo.getKernelUsedSizeKb();
final long ionHeap = Debug.getIonHeapsSizeKb();
final long ionPool = Debug.getIonPoolsSizeKb();
+ final long dmabufMapped = Debug.getDmabufMappedSizeKb();
if (ionHeap >= 0 && ionPool >= 0) {
+ final long ionUnmapped = ionHeap - dmabufMapped;
memInfoBuilder.append(" ION: ");
memInfoBuilder.append(stringifyKBSize(ionHeap + ionPool));
memInfoBuilder.append("\n");
+ kernelUsed += ionUnmapped;
// Note: mapped ION memory is not accounted in PSS due to VM_PFNMAP flag being
- // set on ION VMAs, therefore consider the entire ION heap as used kernel memory
- kernelUsed += ionHeap;
+ // set on ION VMAs, however it might be included by the memtrack HAL.
+ // Replace memtrack HAL reported Graphics category with mapped dmabufs
+ totalPss -= totalMemtrackGraphics;
+ totalPss += dmabufMapped;
} else {
final long totalExportedDmabuf = Debug.getDmabufTotalExportedKb();
if (totalExportedDmabuf >= 0) {
- final long dmabufMapped = Debug.getDmabufMappedSizeKb();
final long dmabufUnmapped = totalExportedDmabuf - dmabufMapped;
memInfoBuilder.append("DMA-BUF: ");
memInfoBuilder.append(stringifyKBSize(totalExportedDmabuf));
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 167c2b1..360e1b4 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -16,6 +16,9 @@
package com.android.server.am;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+
+import android.annotation.NonNull;
import android.bluetooth.BluetoothActivityEnergyInfo;
import android.content.ContentResolver;
import android.content.Context;
@@ -25,7 +28,9 @@
import android.hardware.power.stats.State;
import android.hardware.power.stats.StateResidency;
import android.hardware.power.stats.StateResidencyResult;
+import android.net.ConnectivityManager;
import android.net.INetworkManagementEventObserver;
+import android.net.Network;
import android.net.NetworkCapabilities;
import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
@@ -77,6 +82,7 @@
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.ParseUtils;
import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.net.module.util.NetworkCapabilitiesUtils;
import com.android.server.LocalServices;
import com.android.server.Watchdog;
import com.android.server.net.BaseNetworkObserver;
@@ -291,6 +297,23 @@
return builder.toString();
}
+ private ConnectivityManager.NetworkCallback mNetworkCallback =
+ new ConnectivityManager.NetworkCallback() {
+ @Override
+ public void onCapabilitiesChanged(@NonNull Network network,
+ @NonNull NetworkCapabilities networkCapabilities) {
+ final String state = networkCapabilities.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ ? "CONNECTED" : "SUSPENDED";
+ noteConnectivityChanged(NetworkCapabilitiesUtils.getDisplayTransport(
+ networkCapabilities.getTransportTypes()), state);
+ }
+
+ @Override
+ public void onLost(Network network) {
+ noteConnectivityChanged(-1, "DISCONNECTED");
+ }
+ };
+
BatteryStatsService(Context context, File systemDir, Handler handler) {
// BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through.
mContext = context;
@@ -330,8 +353,10 @@
mWorker.systemServicesReady();
final INetworkManagementService nms = INetworkManagementService.Stub.asInterface(
ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
+ final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
try {
nms.registerObserver(mActivityChangeObserver);
+ cm.registerDefaultNetworkCallback(mNetworkCallback);
} catch (RemoteException e) {
Slog.e(TAG, "Could not register INetworkManagement event observer " + e);
}
@@ -346,6 +371,9 @@
}
Watchdog.getInstance().addMonitor(this);
+
+ final DataConnectionStats dataConnectionStats = new DataConnectionStats(mContext, mHandler);
+ dataConnectionStats.startMonitoring();
}
private final class LocalService extends BatteryStatsInternal {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 2906193..81c4c86 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -29,6 +29,7 @@
import android.app.BroadcastOptions;
import android.app.IApplicationThread;
import android.app.PendingIntent;
+import android.app.usage.UsageEvents.Event;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.IIntentReceiver;
@@ -52,6 +53,7 @@
import android.os.Trace;
import android.os.UserHandle;
import android.permission.IPermissionManager;
+import android.text.TextUtils;
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseIntArray;
@@ -928,6 +930,8 @@
} else if (r.intent.getData() != null) {
b.append(r.intent.getData());
}
+ b.append(",reason:");
+ b.append(reason);
if (DEBUG_BROADCAST) {
Slog.v(TAG, "Broadcast temp allowlist uid=" + uid + " duration=" + duration
+ " type=" + type + " : " + b.toString());
@@ -1634,6 +1638,13 @@
brOptions.getTemporaryAppAllowlistReason());
}
+ // Report that a component is used for explicit broadcasts.
+ if (!r.intent.isExcludingStopped() && r.curComponent != null
+ && !TextUtils.equals(r.curComponent.getPackageName(), r.callerPackage)) {
+ mService.mUsageStatsService.reportEvent(
+ r.curComponent.getPackageName(), r.userId, Event.APP_COMPONENT_USED);
+ }
+
// Broadcast is being executed, its package can't be stopped.
try {
AppGlobals.getPackageManager().setPackageStoppedState(
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index f43c7f6..2c8794d 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -32,6 +32,7 @@
import android.app.ApplicationExitInfo;
import android.app.ContentProviderHolder;
import android.app.IApplicationThread;
+import android.app.usage.UsageEvents.Event;
import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentResolver;
@@ -57,6 +58,7 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
@@ -412,6 +414,12 @@
final long origId = Binder.clearCallingIdentity();
try {
+ if (!TextUtils.equals(cpr.appInfo.packageName, callingPackage)) {
+ // Report component used since a content provider is being bound.
+ mService.mUsageStatsService.reportEvent(
+ cpr.appInfo.packageName, userId, Event.APP_COMPONENT_USED);
+ }
+
// Content provider is now in use, its package can't be stopped.
try {
checkTime(startTime,
diff --git a/services/core/java/com/android/server/connectivity/DataConnectionStats.java b/services/core/java/com/android/server/am/DataConnectionStats.java
similarity index 90%
rename from services/core/java/com/android/server/connectivity/DataConnectionStats.java
rename to services/core/java/com/android/server/am/DataConnectionStats.java
index 15f43a0..6e39a4c 100644
--- a/services/core/java/com/android/server/connectivity/DataConnectionStats.java
+++ b/services/core/java/com/android/server/am/DataConnectionStats.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.connectivity;
+package com.android.server.am;
import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS;
@@ -34,11 +34,11 @@
import android.util.Log;
import com.android.internal.app.IBatteryStats;
-import com.android.server.am.BatteryStatsService;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
+/** Class for receiving data connection state to report to {@link BatteryStatsService}. */
public class DataConnectionStats extends BroadcastReceiver {
private static final String TAG = "DataConnectionStats";
private static final boolean DEBUG = false;
@@ -62,14 +62,14 @@
new PhoneStateListenerImpl(new PhoneStateListenerExecutor(listenerHandler));
}
+ /** Start data connection state monitoring. */
public void startMonitoring() {
- TelephonyManager phone =
- (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ TelephonyManager phone = mContext.getSystemService(TelephonyManager.class);
phone.listen(mPhoneStateListener,
PhoneStateListener.LISTEN_SERVICE_STATE
- | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
- | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
- | PhoneStateListener.LISTEN_DATA_ACTIVITY);
+ | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
+ | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
+ | PhoneStateListener.LISTEN_DATA_ACTIVITY);
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
@@ -103,8 +103,10 @@
if (mNrState == NetworkRegistrationInfo.NR_STATE_CONNECTED) {
networkType = TelephonyManager.NETWORK_TYPE_NR;
}
- if (DEBUG) Log.d(TAG, String.format("Noting data connection for network type %s: %svisible",
- networkType, visible ? "" : "not "));
+ if (DEBUG) {
+ Log.d(TAG, String.format("Noting data connection for network type %s: %svisible",
+ networkType, visible ? "" : "not "));
+ }
try {
mBatteryStats.notePhoneDataConnectionState(networkType, visible,
mServiceState.getState());
@@ -113,7 +115,7 @@
}
}
- private final void updateSimState(Intent intent) {
+ private void updateSimState(Intent intent) {
String stateExtra = intent.getStringExtra(Intent.EXTRA_SIM_STATE);
if (Intent.SIM_STATE_ABSENT.equals(stateExtra)) {
mSimState = TelephonyManager.SIM_STATE_ABSENT;
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index 3258f8a..d03a47a 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -329,6 +329,22 @@
info.append("Package is ").append((int) (loadingProgress * 100)).append("% loaded.\n");
}
+ // Retrieve controller with max ANR delay from AnrControllers
+ // Note that we retrieve the controller before dumping stacks because dumping stacks can
+ // take a few seconds, after which the cause of the ANR delay might have completed and
+ // there might no longer be a valid ANR controller to cancel the dialog in that case
+ AnrController anrController = mService.mActivityTaskManager.getAnrController(aInfo);
+ long anrDialogDelayMs = 0;
+ if (anrController != null) {
+ String packageName = aInfo.packageName;
+ int uid = aInfo.uid;
+ anrDialogDelayMs = anrController.getAnrDelayMillis(packageName, uid);
+ // Might execute an async binder call to a system app to show an interim
+ // ANR progress UI
+ anrController.onAnrDelayStarted(packageName, uid);
+ Slog.i(TAG, "ANR delay of " + anrDialogDelayMs + "ms started for " + packageName);
+ }
+
StringBuilder report = new StringBuilder();
report.append(MemoryPressureUtil.currentPsiState());
ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
@@ -417,20 +433,6 @@
return;
}
- // Retrieve max ANR delay from AnrControllers without the mService lock since the
- // controllers might in turn call into apps
- AnrController anrController = mService.mActivityTaskManager.getAnrController(aInfo);
- long anrDialogDelayMs = 0;
- if (anrController != null) {
- String packageName = aInfo.packageName;
- int uid = aInfo.uid;
- anrDialogDelayMs = anrController.getAnrDelayMillis(packageName, uid);
- // Might execute an async binder call to a system app to show an interim
- // ANR progress UI
- anrController.onAnrDelayStarted(packageName, uid);
- Slog.i(TAG, "ANR delay of " + anrDialogDelayMs + "ms started for " + packageName);
- }
-
synchronized (mService) {
// mBatteryStatsService can be null if the AMS is constructed with injector only. This
// will only happen in tests.
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 3ab95d1..9cd9902 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -107,6 +107,7 @@
boolean delayed; // are we waiting to start this service in the background?
boolean fgRequired; // is the service required to go foreground after starting?
boolean fgWaiting; // is a timeout for going foreground already scheduled?
+ boolean isNotAppComponentUsage; // is service binding not considered component/package usage?
boolean isForeground; // is service currently in foreground mode?
int foregroundId; // Notification ID of last foreground req.
Notification foregroundNoti; // Notification record of foreground state.
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 26ce0d7..0eae661 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -136,6 +136,7 @@
/**
* SystemService lifecycle for GameService.
+ *
* @hide
*/
public static class Lifecycle extends SystemService {
@@ -169,39 +170,69 @@
}
}
- private boolean hasPermission(String permission) {
- return mContext.checkCallingOrSelfPermission(permission)
- == PackageManager.PERMISSION_GRANTED;
+ private boolean isValidPackageName(String packageName) {
+ final PackageManager pm = mContext.getPackageManager();
+ try {
+ return pm.getPackageUid(packageName, 0) == Binder.getCallingUid();
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ return false;
+ }
}
- @Override
- @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
- public @GameMode int getGameMode(String packageName, int userId) {
- if (!hasPermission(Manifest.permission.MANAGE_GAME_MODE)) {
- Log.w(TAG, String.format("Caller or self does not have permission.MANAGE_GAME_MODE"));
- return GameManager.GAME_MODE_UNSUPPORTED;
+ private void checkPermission(String permission) throws SecurityException {
+ if (mContext.checkCallingOrSelfPermission(permission)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
+ + ", must have permission " + permission);
}
+ }
+
+ private @GameMode int getGameModeFromSettings(String packageName, int userId) {
+ synchronized (mLock) {
+ if (!mSettings.containsKey(userId)) {
+ Log.w(TAG, "User ID '" + userId + "' does not have a Game Mode"
+ + " selected for package: '" + packageName + "'");
+ return GameManager.GAME_MODE_UNSUPPORTED;
+ }
+
+ return mSettings.get(userId).getGameModeLocked(packageName);
+ }
+ }
+
+ /**
+ * Get the Game Mode for the package name.
+ * Verifies that the calling process is for the matching package UID or has
+ * {@link android.Manifest.permission#MANAGE_GAME_MODE}.
+ */
+ @Override
+ public @GameMode int getGameMode(String packageName, int userId)
+ throws SecurityException {
+ // TODO(b/178860939): Restrict to games only.
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, true, "getGameMode",
"com.android.server.app.GameManagerService");
- synchronized (mLock) {
- if (!mSettings.containsKey(userId)) {
- return GameManager.GAME_MODE_UNSUPPORTED;
- }
- GameManagerSettings userSettings = mSettings.get(userId);
- return userSettings.getGameModeLocked(packageName);
+ if (isValidPackageName(packageName)) {
+ return getGameModeFromSettings(packageName, userId);
}
+
+ checkPermission(Manifest.permission.MANAGE_GAME_MODE);
+ return getGameModeFromSettings(packageName, userId);
}
+ /**
+ * Sets the Game Mode for the package name.
+ * Verifies that the calling process has {@link android.Manifest.permission#MANAGE_GAME_MODE}.
+ */
@Override
@RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
- public void setGameMode(String packageName, @GameMode int gameMode, int userId) {
- if (!hasPermission(Manifest.permission.MANAGE_GAME_MODE)) {
- Log.w(TAG, String.format("Caller or self does not have permission.MANAGE_GAME_MODE"));
- return;
- }
+ public void setGameMode(String packageName, @GameMode int gameMode, int userId)
+ throws SecurityException {
+ // TODO(b/178860939): Restrict to games only.
+
+ checkPermission(Manifest.permission.MANAGE_GAME_MODE);
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, true, "setGameMode",
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationManagerInternal.java b/services/core/java/com/android/server/apphibernation/AppHibernationManagerInternal.java
new file mode 100644
index 0000000..b0335fe
--- /dev/null
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationManagerInternal.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 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.server.apphibernation;
+
+/**
+ * App hibernation manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class AppHibernationManagerInternal {
+
+ /**
+ * @see AppHibernationService#isHibernatingForUser
+ */
+ public abstract boolean isHibernatingForUser(String packageName, int userId);
+
+ /**
+ * @see AppHibernationService#setHibernatingForUser
+ */
+ public abstract void setHibernatingForUser(String packageName, int userId,
+ boolean isHibernating);
+
+ /**
+ * @see AppHibernationService#isHibernatingGlobally
+ */
+ public abstract boolean isHibernatingGlobally(String packageName);
+
+ /**
+ * @see AppHibernationService#setHibernatingGlobally
+ */
+ public abstract void setHibernatingGlobally(String packageName, boolean isHibernating);
+}
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index 32ae878..968cf5f 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -59,6 +59,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
import java.io.File;
@@ -134,6 +135,8 @@
intentFilter.addAction(ACTION_PACKAGE_REMOVED);
intentFilter.addDataScheme("package");
userAllContext.registerReceiver(mBroadcastReceiver, intentFilter);
+
+ LocalServices.addService(AppHibernationManagerInternal.class, mLocalService);
}
@Override
@@ -545,6 +548,36 @@
}
}
+ private final AppHibernationManagerInternal mLocalService = new LocalService(this);
+
+ private static final class LocalService extends AppHibernationManagerInternal {
+ private final AppHibernationService mService;
+
+ LocalService(AppHibernationService service) {
+ mService = service;
+ }
+
+ @Override
+ public boolean isHibernatingForUser(String packageName, int userId) {
+ return mService.isHibernatingForUser(packageName, userId);
+ }
+
+ @Override
+ public void setHibernatingForUser(String packageName, int userId, boolean isHibernating) {
+ mService.setHibernatingForUser(packageName, userId, isHibernating);
+ }
+
+ @Override
+ public void setHibernatingGlobally(String packageName, boolean isHibernating) {
+ mService.setHibernatingGlobally(packageName, isHibernating);
+ }
+
+ @Override
+ public boolean isHibernatingGlobally(String packageName) {
+ return mService.isHibernatingGlobally(packageName);
+ }
+ }
+
private final AppHibernationServiceStub mServiceStub = new AppHibernationServiceStub(this);
static final class AppHibernationServiceStub extends IAppHibernationService.Stub {
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 11125dd..4a12ff6 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -848,10 +848,7 @@
proxyAttributionTag, uidState, flags);
mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName,
- tag, uidState, flags);
-
- mHistoricalRegistry.mDiscreteRegistry.recordDiscreteAccess(parent.uid,
- parent.packageName, parent.op, tag, flags, uidState, accessTime, -1);
+ tag, uidState, flags, accessTime);
}
/**
@@ -955,9 +952,10 @@
mInProgressEvents = new ArrayMap<>(1);
}
+ long startTime = System.currentTimeMillis();
InProgressStartOpEvent event = mInProgressEvents.get(clientId);
if (event == null) {
- event = mInProgressStartOpEventPool.acquire(System.currentTimeMillis(),
+ event = mInProgressStartOpEventPool.acquire(startTime,
SystemClock.elapsedRealtime(), clientId,
PooledLambda.obtainRunnable(AppOpsService::onClientDeath, this, clientId),
proxyUid, proxyPackageName, proxyAttributionTag, uidState, flags);
@@ -971,7 +969,7 @@
event.numUnfinishedStarts++;
mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName,
- tag, uidState, flags);
+ tag, uidState, flags, startTime);
}
/**
@@ -1017,11 +1015,7 @@
mHistoricalRegistry.increaseOpAccessDuration(parent.op, parent.uid,
parent.packageName, tag, event.getUidState(),
- event.getFlags(), finishedEvent.getDuration());
-
- mHistoricalRegistry.mDiscreteRegistry.recordDiscreteAccess(parent.uid,
- parent.packageName, parent.op, tag, event.getFlags(), event.getUidState(),
- event.getStartTime(), accessDurationMillis);
+ event.getFlags(), finishedEvent.getNoteTime(), finishedEvent.getDuration());
mInProgressStartOpEventPool.release(event);
@@ -4769,7 +4763,7 @@
mFile.failWrite(stream);
}
}
- mHistoricalRegistry.mDiscreteRegistry.writeAndClearAccessHistory();
+ mHistoricalRegistry.writeAndClearDiscreteHistory();
}
static class Shell extends ShellCommand {
@@ -6125,8 +6119,7 @@
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
"clearHistory");
// Must not hold the appops lock
- mHistoricalRegistry.clearHistory();
- mHistoricalRegistry.mDiscreteRegistry.clearHistory();
+ mHistoricalRegistry.clearAllHistory();
}
@Override
diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java
index 7699045..a99d908 100644
--- a/services/core/java/com/android/server/appop/DiscreteRegistry.java
+++ b/services/core/java/com/android/server/appop/DiscreteRegistry.java
@@ -495,6 +495,12 @@
int nAttributedOps = attributedOps.size();
for (int i = nAttributedOps - 1; i >= 0; i--) {
DiscreteOpEvent previousOp = attributedOps.get(i);
+ if (i == nAttributedOps - 1 && previousOp.mNoteTime == accessTime
+ && accessDuration > -1) {
+ // existing event with updated duration
+ attributedOps.remove(i);
+ break;
+ }
if (previousOp.mNoteTime < accessTime) {
break;
}
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 1c43fed..0fcf5ee 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -138,7 +138,7 @@
private static final String PARAMETER_ASSIGNMENT = "=";
private static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled";
- volatile @NonNull DiscreteRegistry mDiscreteRegistry;
+ private volatile @NonNull DiscreteRegistry mDiscreteRegistry;
@GuardedBy("mLock")
private @NonNull LinkedList<HistoricalOps> mPendingWrites = new LinkedList<>();
@@ -477,7 +477,8 @@
}
void incrementOpAccessedCount(int op, int uid, @NonNull String packageName,
- @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags) {
+ @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags,
+ long accessTime) {
synchronized (mInMemoryLock) {
if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
if (!isPersistenceInitializedMLocked()) {
@@ -487,6 +488,9 @@
getUpdatedPendingHistoricalOpsMLocked(
System.currentTimeMillis()).increaseAccessCount(op, uid, packageName,
attributionTag, uidState, flags, 1);
+
+ mDiscreteRegistry.recordDiscreteAccess(uid, packageName, op, attributionTag,
+ flags, uidState, accessTime, -1);
}
}
}
@@ -508,7 +512,7 @@
void increaseOpAccessDuration(int op, int uid, @NonNull String packageName,
@Nullable String attributionTag, @UidState int uidState, @OpFlags int flags,
- long increment) {
+ long eventStartTime, long increment) {
synchronized (mInMemoryLock) {
if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
if (!isPersistenceInitializedMLocked()) {
@@ -518,6 +522,8 @@
getUpdatedPendingHistoricalOpsMLocked(
System.currentTimeMillis()).increaseAccessDuration(op, uid, packageName,
attributionTag, uidState, flags, increment);
+ mDiscreteRegistry.recordDiscreteAccess(uid, packageName, op, attributionTag,
+ flags, uidState, increment, eventStartTime);
}
}
}
@@ -562,7 +568,7 @@
return;
}
final List<HistoricalOps> history = mPersistence.readHistoryDLocked();
- clearHistory();
+ clearHistoricalRegistry();
if (history != null) {
final int historySize = history.size();
for (int i = 0; i < historySize; i++) {
@@ -631,7 +637,16 @@
}
}
- void clearHistory() {
+ void writeAndClearDiscreteHistory() {
+ mDiscreteRegistry.writeAndClearAccessHistory();
+ }
+
+ void clearAllHistory() {
+ clearHistoricalRegistry();
+ mDiscreteRegistry.clearHistory();
+ }
+
+ void clearHistoricalRegistry() {
synchronized (mOnDiskLock) {
synchronized (mInMemoryLock) {
if (!isPersistenceInitializedMLocked()) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index f5b9417..8363c9d2 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -6958,7 +6958,10 @@
private void onSetVolumeIndexOnDevice(@NonNull DeviceVolumeUpdate update) {
final VolumeStreamState streamState = mStreamStates[update.mStreamType];
if (update.hasVolumeIndex()) {
- final int index = update.getVolumeIndex();
+ int index = update.getVolumeIndex();
+ if (!checkSafeMediaVolume(update.mStreamType, index, update.mDevice)) {
+ index = safeMediaVolumeIndex(update.mDevice);
+ }
streamState.setIndex(index, update.mDevice, update.mCaller,
// trusted as index is always validated before message is posted
true /*hasModifyAudioSettings*/);
diff --git a/services/core/java/com/android/server/audio/FadeOutManager.java b/services/core/java/com/android/server/audio/FadeOutManager.java
new file mode 100644
index 0000000..9f0a2ba
--- /dev/null
+++ b/services/core/java/com/android/server/audio/FadeOutManager.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2021 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.server.audio;
+
+import android.annotation.NonNull;
+import android.media.AudioAttributes;
+import android.media.AudioPlaybackConfiguration;
+import android.media.VolumeShaper;
+import android.util.Log;
+
+import com.android.internal.util.ArrayUtils;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Class to handle fading out players
+ */
+public final class FadeOutManager {
+
+ public static final String TAG = "AudioService.FadeOutManager";
+
+ /*package*/ static final long FADE_OUT_DURATION_MS = 2500;
+
+ private static final boolean DEBUG = PlaybackActivityMonitor.DEBUG;
+
+ private static final VolumeShaper.Configuration FADEOUT_VSHAPE =
+ new VolumeShaper.Configuration.Builder()
+ .setId(PlaybackActivityMonitor.VOLUME_SHAPER_SYSTEM_FADEOUT_ID)
+ .setCurve(new float[]{0.f, 1.0f} /* times */,
+ new float[]{1.f, 0.0f} /* volumes */)
+ .setOptionFlags(VolumeShaper.Configuration.OPTION_FLAG_CLOCK_TIME)
+ .setDuration(FADE_OUT_DURATION_MS)
+ .build();
+ private static final VolumeShaper.Operation PLAY_CREATE_IF_NEEDED =
+ new VolumeShaper.Operation.Builder(VolumeShaper.Operation.PLAY)
+ .createIfNeeded()
+ .build();
+
+ private static final int[] UNFADEABLE_PLAYER_TYPES = {
+ AudioPlaybackConfiguration.PLAYER_TYPE_AAUDIO,
+ AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL,
+ };
+
+ private static final int[] UNFADEABLE_CONTENT_TYPES = {
+ AudioAttributes.CONTENT_TYPE_SPEECH,
+ };
+
+ private static final int[] FADEABLE_USAGES = {
+ AudioAttributes.USAGE_GAME,
+ AudioAttributes.USAGE_MEDIA,
+ };
+
+ // like a PLAY_CREATE_IF_NEEDED operation but with a skip to the end of the ramp
+ private static final VolumeShaper.Operation PLAY_SKIP_RAMP =
+ new VolumeShaper.Operation.Builder(PLAY_CREATE_IF_NEEDED).setXOffset(1.0f).build();
+
+ /**
+ * Evaluates whether the player associated with this configuration can and should be faded out
+ * @param apc the configuration of the player
+ * @return true if player type and AudioAttributes are compatible with fade out
+ */
+ static boolean canBeFadedOut(@NonNull AudioPlaybackConfiguration apc) {
+ if (ArrayUtils.contains(UNFADEABLE_PLAYER_TYPES, apc.getPlayerType())) {
+ if (DEBUG) { Log.i(TAG, "not fading: player type:" + apc.getPlayerType()); }
+ return false;
+ }
+ if (ArrayUtils.contains(UNFADEABLE_CONTENT_TYPES,
+ apc.getAudioAttributes().getContentType())) {
+ if (DEBUG) {
+ Log.i(TAG, "not fading: content type:"
+ + apc.getAudioAttributes().getContentType());
+ }
+ return false;
+ }
+ if (!ArrayUtils.contains(FADEABLE_USAGES, apc.getAudioAttributes().getUsage())) {
+ if (DEBUG) {
+ Log.i(TAG, "not fading: usage:" + apc.getAudioAttributes().getUsage());
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Map of uid (key) to faded out apps (value)
+ */
+ private final HashMap<Integer, FadedOutApp> mFadedApps = new HashMap<Integer, FadedOutApp>();
+
+ synchronized void fadeOutUid(int uid, ArrayList<AudioPlaybackConfiguration> players) {
+ Log.i(TAG, "fadeOutUid() uid:" + uid);
+ if (!mFadedApps.containsKey(uid)) {
+ mFadedApps.put(uid, new FadedOutApp(uid));
+ }
+ final FadedOutApp fa = mFadedApps.get(uid);
+ for (AudioPlaybackConfiguration apc : players) {
+ fa.addFade(apc, false /*skipRamp*/);
+ }
+ }
+
+ synchronized void unfadeOutUid(int uid, HashMap<Integer, AudioPlaybackConfiguration> players) {
+ Log.i(TAG, "unfadeOutUid() uid:" + uid);
+ final FadedOutApp fa = mFadedApps.remove(uid);
+ if (fa == null) {
+ return;
+ }
+ fa.removeUnfadeAll(players);
+ }
+
+ synchronized void forgetUid(int uid) {
+ //Log.v(TAG, "forget() uid:" + uid);
+ //mFadedApps.remove(uid);
+ // TODO unfade all players later in case they are reused or the app continued to play
+ }
+
+ // pre-condition: apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED
+ // see {@link PlaybackActivityMonitor#playerEvent}
+ synchronized void checkFade(@NonNull AudioPlaybackConfiguration apc) {
+ if (DEBUG) {
+ Log.v(TAG, "checkFade() player piid:"
+ + apc.getPlayerInterfaceId() + " uid:" + apc.getClientUid());
+ }
+ final FadedOutApp fa = mFadedApps.get(apc.getClientUid());
+ if (fa == null) {
+ return;
+ }
+ fa.addFade(apc, true);
+ }
+
+ /**
+ * Remove the player from the list of faded out players because it has been released
+ * @param apc the released player
+ */
+ synchronized void removeReleased(@NonNull AudioPlaybackConfiguration apc) {
+ final int uid = apc.getClientUid();
+ if (DEBUG) {
+ Log.v(TAG, "removedReleased() player piid: "
+ + apc.getPlayerInterfaceId() + " uid:" + uid);
+ }
+ final FadedOutApp fa = mFadedApps.get(uid);
+ if (fa == null) {
+ return;
+ }
+ fa.removeReleased(apc);
+ }
+
+ synchronized void dump(PrintWriter pw) {
+ for (FadedOutApp da : mFadedApps.values()) {
+ da.dump(pw);
+ }
+ }
+
+ //=========================================================================
+ /**
+ * Class to group players from a common app, that are faded out.
+ */
+ private static final class FadedOutApp {
+ private final int mUid;
+ private final ArrayList<Integer> mFadedPlayers = new ArrayList<Integer>();
+
+ FadedOutApp(int uid) {
+ mUid = uid;
+ }
+
+ void dump(PrintWriter pw) {
+ pw.print("\t uid:" + mUid + " piids:");
+ for (int piid : mFadedPlayers) {
+ pw.print(" " + piid);
+ }
+ pw.println("");
+ }
+
+ /**
+ * Add this player to the list of faded out players and apply the fade
+ * @param apc a config that satisfies
+ * apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED
+ * @param skipRamp true if the player should be directly into the end of ramp state.
+ * This value would for instance be false when adding players at the start of a fade.
+ */
+ void addFade(@NonNull AudioPlaybackConfiguration apc, boolean skipRamp) {
+ final int piid = new Integer(apc.getPlayerInterfaceId());
+ if (mFadedPlayers.contains(piid)) {
+ if (DEBUG) {
+ Log.v(TAG, "player piid:" + piid + " already faded out");
+ }
+ return;
+ }
+ try {
+ PlaybackActivityMonitor.sEventLogger.log(
+ (new PlaybackActivityMonitor.FadeOutEvent(apc, skipRamp)).printLog(TAG));
+ apc.getPlayerProxy().applyVolumeShaper(
+ FADEOUT_VSHAPE,
+ skipRamp ? PLAY_SKIP_RAMP : PLAY_CREATE_IF_NEEDED);
+ mFadedPlayers.add(piid);
+ } catch (Exception e) {
+ Log.e(TAG, "Error fading out player piid:" + piid
+ + " uid:" + apc.getClientUid(), e);
+ }
+ }
+
+ void removeUnfadeAll(HashMap<Integer, AudioPlaybackConfiguration> players) {
+ for (int piid : mFadedPlayers) {
+ final AudioPlaybackConfiguration apc = players.get(piid);
+ if (apc != null) {
+ try {
+ PlaybackActivityMonitor.sEventLogger.log(
+ (new AudioEventLogger.StringEvent("unfading out piid:"
+ + piid)).printLog(TAG));
+ apc.getPlayerProxy().applyVolumeShaper(
+ FADEOUT_VSHAPE,
+ VolumeShaper.Operation.REVERSE);
+ } catch (Exception e) {
+ Log.e(TAG, "Error unfading out player piid:" + piid + " uid:" + mUid, e);
+ }
+ } else {
+ // this piid was in the list of faded players, but wasn't found
+ if (DEBUG) {
+ Log.v(TAG, "Error unfading out player piid:" + piid
+ + ", player not found for uid " + mUid);
+ }
+ }
+ }
+ mFadedPlayers.clear();
+ }
+
+ void removeReleased(@NonNull AudioPlaybackConfiguration apc) {
+ mFadedPlayers.remove(new Integer(apc.getPlayerInterfaceId()));
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java
index b6d6472..cc60fe1 100644
--- a/services/core/java/com/android/server/audio/FocusRequester.java
+++ b/services/core/java/com/android/server/audio/FocusRequester.java
@@ -70,6 +70,11 @@
*/
private boolean mFocusLossWasNotified;
/**
+ * whether this focus owner has already lost focus, but is being faded out until focus loss
+ * dispatch occurs. It's in "limbo" mode: has lost focus but not released yet until notified
+ */
+ boolean mFocusLossFadeLimbo;
+ /**
* the audio attributes associated with the focus request
*/
private final @NonNull AudioAttributes mAttributes;
@@ -102,6 +107,7 @@
mGrantFlags = grantFlags;
mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
mFocusLossWasNotified = true;
+ mFocusLossFadeLimbo = false;
mFocusController = ctlr;
mSdkTarget = sdk;
}
@@ -115,6 +121,7 @@
mFocusGainRequest = afi.getGainRequest();
mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
mFocusLossWasNotified = true;
+ mFocusLossFadeLimbo = false;
mGrantFlags = afi.getFlags();
mSdkTarget = afi.getSdkTarget();
@@ -132,6 +139,13 @@
return ((mGrantFlags & AudioManager.AUDIOFOCUS_FLAG_LOCK) != 0);
}
+ /**
+ * @return true if the focus requester is scheduled to receive a focus loss
+ */
+ boolean isInFocusLossLimbo() {
+ return mFocusLossFadeLimbo;
+ }
+
boolean hasSameBinder(IBinder ib) {
return (mSourceRef != null) && mSourceRef.equals(ib);
}
@@ -231,11 +245,21 @@
+ " -- flags: " + flagsToString(mGrantFlags)
+ " -- loss: " + focusLossToString()
+ " -- notified: " + mFocusLossWasNotified
+ + " -- limbo" + mFocusLossFadeLimbo
+ " -- uid: " + mCallingUid
+ " -- attr: " + mAttributes
+ " -- sdk:" + mSdkTarget);
}
+ /**
+ * Clear all references, except for instances in "loss limbo" due to the current fade out
+ * for which there will be an attempt to be clear after the loss has been notified
+ */
+ void maybeRelease() {
+ if (!mFocusLossFadeLimbo) {
+ release();
+ }
+ }
void release() {
final IBinder srcRef = mSourceRef;
@@ -315,6 +339,7 @@
void handleFocusGain(int focusGain) {
try {
mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
+ mFocusLossFadeLimbo = false;
mFocusController.notifyExtPolicyFocusGrant_syncAf(toAudioFocusInfo(),
AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
final IAudioFocusDispatcher fd = mFocusDispatcher;
@@ -327,7 +352,7 @@
fd.dispatchAudioFocusChange(focusGain, mClientId);
}
}
- mFocusController.unduckPlayers(this);
+ mFocusController.restoreVShapedPlayers(this);
} catch (android.os.RemoteException e) {
Log.e(TAG, "Failure to signal gain of audio focus due to: ", e);
}
@@ -336,7 +361,7 @@
@GuardedBy("MediaFocusControl.mAudioFocusLock")
void handleFocusGainFromRequest(int focusRequestResult) {
if (focusRequestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
- mFocusController.unduckPlayers(this);
+ mFocusController.restoreVShapedPlayers(this);
}
}
@@ -375,7 +400,7 @@
if (handled) {
if (DEBUG) {
Log.v(TAG, "NOT dispatching " + focusChangeToString(mFocusLossReceived)
- + " to " + mClientId + ", ducking implemented by framework");
+ + " to " + mClientId + ", response handled by framework");
}
mFocusController.notifyExtPolicyFocusLoss_syncAf(
toAudioFocusInfo(), false /* wasDispatched */);
@@ -435,8 +460,27 @@
return false;
}
- return mFocusController.duckPlayers(frWinner, this, forceDuck);
+ return mFocusController.duckPlayers(frWinner, /*loser*/ this, forceDuck);
}
+
+ if (focusLoss == AudioManager.AUDIOFOCUS_LOSS) {
+ if (!MediaFocusControl.ENFORCE_FADEOUT_FOR_FOCUS_LOSS) {
+ return false;
+ }
+
+ // candidate for fade-out before a receiving a loss
+ boolean playersAreFaded = mFocusController.fadeOutPlayers(frWinner, /* loser */ this);
+ if (playersAreFaded) {
+ // active players are being faded out, delay the dispatch of focus loss
+ // mark this instance as being faded so it's not released yet as the focus loss
+ // will be dispatched later, it is now in limbo mode
+ mFocusLossFadeLimbo = true;
+ mFocusController.postDelayedLossAfterFade(this,
+ FadeOutManager.FADE_OUT_DURATION_MS);
+ return true;
+ }
+ }
+
return false;
}
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index b1633b0..1dcfdae 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -30,7 +30,10 @@
import android.media.audiopolicy.IAudioPolicyCallback;
import android.os.Binder;
import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.Message;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.Log;
@@ -80,6 +83,12 @@
*/
static final boolean ENFORCE_MUTING_FOR_RING_OR_CALL = true;
+ /**
+ * set to true so the framework enforces fading out apps that lose audio focus in a
+ * non-transient way.
+ */
+ static final boolean ENFORCE_FADEOUT_FOR_FOCUS_LOSS = true;
+
private final Context mContext;
private final AppOpsManager mAppOps;
private PlayerFocusEnforcer mFocusEnforcer; // never null
@@ -98,6 +107,7 @@
final ContentResolver cr = mContext.getContentResolver();
mMultiAudioFocusEnabled = Settings.System.getIntForUser(cr,
Settings.System.MULTI_AUDIO_FOCUS_ENABLED, 0, cr.getUserId()) != 0;
+ initFocusThreading();
}
protected void dump(PrintWriter pw) {
@@ -119,8 +129,8 @@
}
@Override
- public void unduckPlayers(@NonNull FocusRequester winner) {
- mFocusEnforcer.unduckPlayers(winner);
+ public void restoreVShapedPlayers(@NonNull FocusRequester winner) {
+ mFocusEnforcer.restoreVShapedPlayers(winner);
}
@Override
@@ -133,6 +143,16 @@
mFocusEnforcer.unmutePlayersForCall();
}
+ @Override
+ public boolean fadeOutPlayers(@NonNull FocusRequester winner, @NonNull FocusRequester loser) {
+ return mFocusEnforcer.fadeOutPlayers(winner, loser);
+ }
+
+ @Override
+ public void forgetUid(int uid) {
+ mFocusEnforcer.forgetUid(uid);
+ }
+
//==========================================================================================
// AudioFocus
//==========================================================================================
@@ -294,7 +314,7 @@
{
//Log.i(TAG, " removeFocusStackEntry() removing top of stack");
FocusRequester fr = mFocusStack.pop();
- fr.release();
+ fr.maybeRelease();
if (notifyFocusFollowers) {
abandonSource = fr.toAudioFocusInfo();
}
@@ -318,7 +338,7 @@
abandonSource = fr.toAudioFocusInfo();
}
// stack entry not used anymore, clear references
- fr.release();
+ fr.maybeRelease();
}
}
}
@@ -1134,4 +1154,57 @@
pw.println("------------------------------");
}
}
+
+ //=================================================================
+ // Async focus events
+ void postDelayedLossAfterFade(FocusRequester focusLoser, long delayMs) {
+ if (DEBUG) {
+ Log.v(TAG, "postDelayedLossAfterFade loser=" + focusLoser.getPackageName());
+ }
+ mFocusHandler.sendMessageDelayed(
+ mFocusHandler.obtainMessage(MSG_L_FOCUS_LOSS_AFTER_FADE, focusLoser),
+ FadeOutManager.FADE_OUT_DURATION_MS);
+ }
+ //=================================================================
+ // Message handling
+ private Handler mFocusHandler;
+ private HandlerThread mFocusThread;
+
+ /**
+ * dispatch a focus loss after an app has been faded out. Focus loser is to be released
+ * after dispatch as it has already left the stack
+ * args:
+ * msg.obj: the audio focus loser
+ * type:FocusRequester
+ */
+ private static final int MSG_L_FOCUS_LOSS_AFTER_FADE = 1;
+
+ private void initFocusThreading() {
+ mFocusThread = new HandlerThread(TAG);
+ mFocusThread.start();
+ mFocusHandler = new Handler(mFocusThread.getLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_L_FOCUS_LOSS_AFTER_FADE:
+ if (DEBUG) {
+ Log.d(TAG, "MSG_L_FOCUS_LOSS_AFTER_FADE loser="
+ + ((FocusRequester) msg.obj).getPackageName());
+ }
+ synchronized (mAudioFocusLock) {
+ final FocusRequester loser = (FocusRequester) msg.obj;
+ if (loser.isInFocusLossLimbo()) {
+ loser.dispatchFocusChange(AudioManager.AUDIOFOCUS_LOSS);
+ loser.release();
+ mFocusEnforcer.forgetUid(loser.getClientUid());
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ };
+
+ }
}
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 8af1b5be..47c91e6 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -51,8 +51,9 @@
public static final String TAG = "AudioService.PlaybackActivityMonitor";
- private static final boolean DEBUG = false;
- private static final int VOLUME_SHAPER_SYSTEM_DUCK_ID = 1;
+ /*package*/ static final boolean DEBUG = false;
+ /*package*/ static final int VOLUME_SHAPER_SYSTEM_DUCK_ID = 1;
+ /*package*/ static final int VOLUME_SHAPER_SYSTEM_FADEOUT_ID = 2;
private static final VolumeShaper.Configuration DUCK_VSHAPE =
new VolumeShaper.Configuration.Builder()
@@ -298,6 +299,7 @@
}
if (change && event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
mDuckingManager.checkDuck(apc);
+ mFadingManager.checkFade(apc);
}
}
if (change) {
@@ -320,6 +322,7 @@
"releasing player piid:" + piid));
mPlayers.remove(new Integer(piid));
mDuckingManager.removeReleased(apc);
+ mFadingManager.removeReleased(apc);
checkVolumeForPrivilegedAlarm(apc, AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
change = apc.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_RELEASED,
AudioPlaybackConfiguration.PLAYER_DEVICEID_INVALID);
@@ -442,6 +445,9 @@
// ducked players
pw.println("\n ducked players piids:");
mDuckingManager.dump(pw);
+ // faded out players
+ pw.println("\n faded out players piids:");
+ mFadingManager.dump(pw);
// players muted due to the device ringing or being in a call
pw.print("\n muted player piids:");
for (int piid : mMutedPlayers) {
@@ -606,10 +612,11 @@
}
@Override
- public void unduckPlayers(@NonNull FocusRequester winner) {
+ public void restoreVShapedPlayers(@NonNull FocusRequester winner) {
if (DEBUG) { Log.v(TAG, "unduckPlayers: uids winner=" + winner.getClientUid()); }
synchronized (mPlayerLock) {
mDuckingManager.unduckUid(winner.getClientUid(), mPlayers);
+ mFadingManager.unfadeOutUid(winner.getClientUid(), mPlayers);
}
}
@@ -678,6 +685,67 @@
}
}
+ private final FadeOutManager mFadingManager = new FadeOutManager();
+
+ /**
+ *
+ * @param winner the new non-transient focus owner
+ * @param loser the previous focus owner
+ * @return true if there are players being faded out
+ */
+ @Override
+ public boolean fadeOutPlayers(@NonNull FocusRequester winner, @NonNull FocusRequester loser) {
+ if (DEBUG) {
+ Log.v(TAG, "fadeOutPlayers: winner=" + winner.getPackageName()
+ + " loser=" + loser.getPackageName());
+ }
+ boolean loserHasActivePlayers = false;
+
+ // find which players to fade out
+ synchronized (mPlayerLock) {
+ if (mPlayers.isEmpty()) {
+ return false;
+ }
+ // check if this UID needs to be faded out (return false if not), and gather list of
+ // eligible players to fade out
+ final Iterator<AudioPlaybackConfiguration> apcIterator = mPlayers.values().iterator();
+ final ArrayList<AudioPlaybackConfiguration> apcsToFadeOut =
+ new ArrayList<AudioPlaybackConfiguration>();
+ while (apcIterator.hasNext()) {
+ final AudioPlaybackConfiguration apc = apcIterator.next();
+ if (!winner.hasSameUid(apc.getClientUid())
+ && loser.hasSameUid(apc.getClientUid())
+ && apc.getPlayerState()
+ == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
+ if (!FadeOutManager.canBeFadedOut(apc)) {
+ // the player is not eligible to be faded out, bail
+ Log.v(TAG, "not fading out player " + apc.getPlayerInterfaceId()
+ + " uid:" + apc.getClientUid() + " pid:" + apc.getClientPid()
+ + " type:"
+ + AudioPlaybackConfiguration.toLogFriendlyPlayerType(
+ apc.getPlayerType())
+ + " attr:" + apc.getAudioAttributes());
+ return false;
+ }
+ loserHasActivePlayers = true;
+ apcsToFadeOut.add(apc);
+ }
+ }
+ //###
+ //mDuckingManager.duckUid(loser.getClientUid(), apcsToFadeOut);
+ if (loserHasActivePlayers) {
+ mFadingManager.fadeOutUid(loser.getClientUid(), apcsToFadeOut);
+ }
+ }
+
+ return loserHasActivePlayers;
+ }
+
+ @Override
+ public void forgetUid(int uid) {
+ mFadingManager.forgetUid(uid);
+ }
+
//=================================================================
// Track playback activity listeners
@@ -964,13 +1032,15 @@
}
}
- private static final class DuckEvent extends AudioEventLogger.Event {
+ private abstract static class VolumeShaperEvent extends AudioEventLogger.Event {
private final int mPlayerIId;
private final boolean mSkipRamp;
private final int mClientUid;
private final int mClientPid;
- DuckEvent(@NonNull AudioPlaybackConfiguration apc, boolean skipRamp) {
+ abstract String getVSAction();
+
+ VolumeShaperEvent(@NonNull AudioPlaybackConfiguration apc, boolean skipRamp) {
mPlayerIId = apc.getPlayerInterfaceId();
mSkipRamp = skipRamp;
mClientUid = apc.getClientUid();
@@ -979,12 +1049,34 @@
@Override
public String eventToString() {
- return new StringBuilder("ducking player piid:").append(mPlayerIId)
+ return new StringBuilder(getVSAction()).append(" player piid:").append(mPlayerIId)
.append(" uid/pid:").append(mClientUid).append("/").append(mClientPid)
.append(" skip ramp:").append(mSkipRamp).toString();
}
}
+ static final class DuckEvent extends VolumeShaperEvent {
+ @Override
+ String getVSAction() {
+ return "ducking";
+ }
+
+ DuckEvent(@NonNull AudioPlaybackConfiguration apc, boolean skipRamp) {
+ super(apc, skipRamp);
+ }
+ }
+
+ static final class FadeOutEvent extends VolumeShaperEvent {
+ @Override
+ String getVSAction() {
+ return "fading out";
+ }
+
+ FadeOutEvent(@NonNull AudioPlaybackConfiguration apc, boolean skipRamp) {
+ super(apc, skipRamp);
+ }
+ }
+
private static final class AudioAttrEvent extends AudioEventLogger.Event {
private final int mPlayerIId;
private final AudioAttributes mPlayerAttr;
@@ -1000,6 +1092,6 @@
}
}
- private static final AudioEventLogger sEventLogger = new AudioEventLogger(100,
+ static final AudioEventLogger sEventLogger = new AudioEventLogger(100,
"playback activity as reported through PlayerBase");
}
diff --git a/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java b/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java
index 89e7b782..fb72ac2 100644
--- a/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java
+++ b/services/core/java/com/android/server/audio/PlayerFocusEnforcer.java
@@ -31,11 +31,12 @@
boolean forceDuck);
/**
- * Unduck the players that had been ducked with
- * {@link #duckPlayers(FocusRequester, FocusRequester, boolean)}
+ * Restore the initial state of any players that had had a volume ramp applied as the result
+ * of a duck or fade out through {@link #duckPlayers(FocusRequester, FocusRequester, boolean)}
+ * or {@link #fadeOutPlayers(FocusRequester, FocusRequester)}
* @param winner
*/
- void unduckPlayers(@NonNull FocusRequester winner);
+ void restoreVShapedPlayers(@NonNull FocusRequester winner);
/**
* Mute players at the beginning of a call
@@ -47,4 +48,20 @@
* Unmute players at the end of a call
*/
void unmutePlayersForCall();
+
+ /**
+ * Fade out whatever is still playing after the non-transient focus change
+ * @param winner the new non-transient focus owner
+ * @param loser the previous focus owner
+ * @return true if there were any active players for the loser that qualified for being
+ * faded out (because of audio attributes, or player types), and as such were faded
+ * out.
+ */
+ boolean fadeOutPlayers(@NonNull FocusRequester winner, @NonNull FocusRequester loser);
+
+ /**
+ * Mark this UID as no longer playing a role in focus enforcement
+ * @param uid
+ */
+ void forgetUid(int uid);
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index e19745e..050b28b 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -33,6 +33,7 @@
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.IAuthService;
import android.hardware.biometrics.IBiometricAuthenticator;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
@@ -337,6 +338,168 @@
Binder.restoreCallingIdentity(identity);
}
}
+
+ @Override
+ public CharSequence getButtonLabel(
+ int userId,
+ String opPackageName,
+ @Authenticators.Types int authenticators) throws RemoteException {
+
+ // Only allow internal clients to call getButtonLabel with a different userId.
+ final int callingUserId = UserHandle.getCallingUserId();
+
+ if (userId != callingUserId) {
+ checkInternalPermission();
+ } else {
+ checkPermission();
+ }
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ @BiometricAuthenticator.Modality final int modality =
+ mBiometricService.getCurrentModality(
+ opPackageName, userId, callingUserId, authenticators);
+
+ final String result;
+ switch (getCredentialBackupModality(modality)) {
+ case BiometricAuthenticator.TYPE_NONE:
+ result = null;
+ break;
+ case BiometricAuthenticator.TYPE_CREDENTIAL:
+ result = getContext().getString(R.string.screen_lock_app_setting_name);
+ break;
+ case BiometricAuthenticator.TYPE_FINGERPRINT:
+ result = getContext().getString(R.string.fingerprint_app_setting_name);
+ break;
+ case BiometricAuthenticator.TYPE_FACE:
+ result = getContext().getString(R.string.face_app_setting_name);
+ break;
+ default:
+ result = getContext().getString(R.string.biometric_app_setting_name);
+ break;
+ }
+
+ return result;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public CharSequence getPromptMessage(
+ int userId,
+ String opPackageName,
+ @Authenticators.Types int authenticators) throws RemoteException {
+
+ // Only allow internal clients to call getButtonLabel with a different userId.
+ final int callingUserId = UserHandle.getCallingUserId();
+
+ if (userId != callingUserId) {
+ checkInternalPermission();
+ } else {
+ checkPermission();
+ }
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ @BiometricAuthenticator.Modality final int modality =
+ mBiometricService.getCurrentModality(
+ opPackageName, userId, callingUserId, authenticators);
+
+ final String result;
+ switch (getCredentialBackupModality(modality)) {
+ case BiometricAuthenticator.TYPE_NONE:
+ result = null;
+ break;
+ case BiometricAuthenticator.TYPE_CREDENTIAL:
+ result = getContext().getString(
+ R.string.screen_lock_dialog_default_subtitle);
+ break;
+ case BiometricAuthenticator.TYPE_FINGERPRINT:
+ result = getContext().getString(
+ R.string.fingerprint_dialog_default_subtitle);
+ break;
+ case BiometricAuthenticator.TYPE_FACE:
+ result = getContext().getString(R.string.face_dialog_default_subtitle);
+ break;
+ default:
+ result = getContext().getString(R.string.biometric_dialog_default_subtitle);
+ break;
+ }
+ return result;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public CharSequence getSettingName(
+ int userId,
+ String opPackageName,
+ @Authenticators.Types int authenticators) throws RemoteException {
+
+ // Only allow internal clients to call getButtonLabel with a different userId.
+ final int callingUserId = UserHandle.getCallingUserId();
+
+ if (userId != callingUserId) {
+ checkInternalPermission();
+ } else {
+ checkPermission();
+ }
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ @BiometricAuthenticator.Modality final int modality =
+ mBiometricService.getSupportedModalities(authenticators);
+
+ final String result;
+ switch (modality) {
+ // Handle the case of a single supported modality.
+ case BiometricAuthenticator.TYPE_NONE:
+ result = null;
+ break;
+ case BiometricAuthenticator.TYPE_CREDENTIAL:
+ result = getContext().getString(R.string.screen_lock_app_setting_name);
+ break;
+ case BiometricAuthenticator.TYPE_IRIS:
+ result = getContext().getString(R.string.biometric_app_setting_name);
+ break;
+ case BiometricAuthenticator.TYPE_FINGERPRINT:
+ result = getContext().getString(R.string.fingerprint_app_setting_name);
+ break;
+ case BiometricAuthenticator.TYPE_FACE:
+ result = getContext().getString(R.string.face_app_setting_name);
+ break;
+
+ // Handle other possible modality combinations.
+ default:
+ if ((modality & BiometricAuthenticator.TYPE_CREDENTIAL) == 0) {
+ // 2+ biometric modalities are supported (but not device credential).
+ result = getContext().getString(R.string.biometric_app_setting_name);
+ } else {
+ @BiometricAuthenticator.Modality final int biometricModality =
+ modality & ~BiometricAuthenticator.TYPE_CREDENTIAL;
+ if (biometricModality == BiometricAuthenticator.TYPE_FINGERPRINT) {
+ // Only device credential and fingerprint are supported.
+ result = getContext().getString(
+ R.string.fingerprint_or_screen_lock_app_setting_name);
+ } else if (biometricModality == BiometricAuthenticator.TYPE_FACE) {
+ // Only device credential and face are supported.
+ result = getContext().getString(
+ R.string.face_or_screen_lock_app_setting_name);
+ } else {
+ // Device credential and 1+ other biometric(s) are supported.
+ result = getContext().getString(
+ R.string.biometric_or_screen_lock_app_setting_name);
+ }
+ }
+ break;
+ }
+ return result;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
}
public AuthService(Context context) {
@@ -442,4 +605,10 @@
return mInjector.getAppOps(getContext()).noteOp(AppOpsManager.OP_USE_BIOMETRIC, uid,
opPackageName, null /* attributionTag */, reason) == AppOpsManager.MODE_ALLOWED;
}
+
+ @BiometricAuthenticator.Modality
+ private static int getCredentialBackupModality(@BiometricAuthenticator.Modality int modality) {
+ return modality == BiometricAuthenticator.TYPE_CREDENTIAL
+ ? modality : (modality & ~BiometricAuthenticator.TYPE_CREDENTIAL);
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 00a4e43..a888209 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -666,14 +666,9 @@
throw new SecurityException("Invalid authenticator configuration");
}
- final PromptInfo promptInfo = new PromptInfo();
- promptInfo.setAuthenticators(authenticators);
-
try {
- PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager,
- mDevicePolicyManager, mSettingObserver, mSensors, userId, promptInfo,
- opPackageName,
- false /* checkDevicePolicyManager */);
+ final PreAuthInfo preAuthInfo =
+ createPreAuthInfo(opPackageName, userId, authenticators);
return preAuthInfo.getCanAuthenticateResult();
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
@@ -807,6 +802,64 @@
return Authenticators.EMPTY_SET;
}
+ @Override // Binder call
+ public int getCurrentModality(
+ String opPackageName,
+ int userId,
+ int callingUserId,
+ @Authenticators.Types int authenticators) {
+
+ checkInternalPermission();
+
+ Slog.d(TAG, "getCurrentModality: User=" + userId
+ + ", Caller=" + callingUserId
+ + ", Authenticators=" + authenticators);
+
+ if (!Utils.isValidAuthenticatorConfig(authenticators)) {
+ throw new SecurityException("Invalid authenticator configuration");
+ }
+
+ try {
+ final PreAuthInfo preAuthInfo =
+ createPreAuthInfo(opPackageName, userId, authenticators);
+ return preAuthInfo.getPreAuthenticateStatus().first;
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ return BiometricAuthenticator.TYPE_NONE;
+ }
+ }
+
+ @Override // Binder call
+ public int getSupportedModalities(@Authenticators.Types int authenticators) {
+ checkInternalPermission();
+
+ Slog.d(TAG, "getSupportedModalities: Authenticators=" + authenticators);
+
+ if (!Utils.isValidAuthenticatorConfig(authenticators)) {
+ throw new SecurityException("Invalid authenticator configuration");
+ }
+
+ @BiometricAuthenticator.Modality int modality =
+ Utils.isCredentialRequested(authenticators)
+ ? BiometricAuthenticator.TYPE_CREDENTIAL
+ : BiometricAuthenticator.TYPE_NONE;
+
+ if (Utils.isBiometricRequested(authenticators)) {
+ @Authenticators.Types final int requestedStrength =
+ Utils.getPublicBiometricStrength(authenticators);
+
+ // Add modalities of all biometric sensors that meet the authenticator requirements.
+ for (final BiometricSensor sensor : mSensors) {
+ @Authenticators.Types final int sensorStrength = sensor.getCurrentStrength();
+ if (Utils.isAtLeastStrength(sensorStrength, requestedStrength)) {
+ modality |= sensor.modality;
+ }
+ }
+ }
+
+ return modality;
+ }
+
@Override
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
@@ -845,6 +898,19 @@
"Must have USE_BIOMETRIC_INTERNAL permission");
}
+ @NonNull
+ private PreAuthInfo createPreAuthInfo(
+ @NonNull String opPackageName,
+ int userId,
+ @Authenticators.Types int authenticators) throws RemoteException {
+
+ final PromptInfo promptInfo = new PromptInfo();
+ promptInfo.setAuthenticators(authenticators);
+
+ return PreAuthInfo.create(mTrustManager, mDevicePolicyManager, mSettingObserver, mSensors,
+ userId, promptInfo, opPackageName, false /* checkDevicePolicyManager */);
+ }
+
/**
* Class for injecting dependencies into BiometricService.
* TODO(b/141025588): Replace with a dependency injection framework (e.g. Guice, Dagger).
diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java
index 5cd0bbf..d9e21a8 100644
--- a/services/core/java/com/android/server/biometrics/Utils.java
+++ b/services/core/java/com/android/server/biometrics/Utils.java
@@ -153,6 +153,16 @@
/**
* Checks if any of the publicly defined strengths are set.
*
+ * @param authenticators composed of one or more values from {@link Authenticators}
+ * @return true if biometric authentication is allowed.
+ */
+ static boolean isBiometricRequested(@Authenticators.Types int authenticators) {
+ return getPublicBiometricStrength(authenticators) != 0;
+ }
+
+ /**
+ * Checks if any of the publicly defined strengths are set.
+ *
* @param promptInfo should be first processed by
* {@link #combineAuthenticatorBundles(PromptInfo)}
* @return true if biometric authentication is allowed.
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClient.java
index d7e08e4..7a846f5 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClient.java
@@ -32,7 +32,6 @@
*/
public class FaceGenerateChallengeClient extends GenerateChallengeClient<ISession> {
private static final String TAG = "FaceGenerateChallengeClient";
- private static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes
FaceGenerateChallengeClient(@NonNull Context context,
@NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
@@ -43,7 +42,7 @@
@Override
protected void startHalOperation() {
try {
- getFreshDaemon().generateChallenge(mSequentialId, CHALLENGE_TIMEOUT_SEC);
+ getFreshDaemon().generateChallenge(mSequentialId);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to generateChallenge", e);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java
index afa5bd2..b4c9b29 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java
@@ -45,7 +45,7 @@
return new ISession.Stub() {
@Override
- public void generateChallenge(int cookie, int timeoutSec) throws RemoteException {
+ public void generateChallenge(int cookie) throws RemoteException {
Slog.w(TAG, "generateChallenge, cookie: " + cookie);
cb.onChallengeGenerated(0L);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGenerateChallengeClient.java
index 402886b..3c9cced 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGenerateChallengeClient.java
@@ -32,7 +32,6 @@
*/
class FingerprintGenerateChallengeClient extends GenerateChallengeClient<ISession> {
private static final String TAG = "FingerprintGenerateChallengeClient";
- private static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes
FingerprintGenerateChallengeClient(@NonNull Context context,
@NonNull LazyDaemon<ISession> lazyDaemon,
@@ -45,7 +44,7 @@
@Override
protected void startHalOperation() {
try {
- getFreshDaemon().generateChallenge(mSequentialId, CHALLENGE_TIMEOUT_SEC);
+ getFreshDaemon().generateChallenge(mSequentialId);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to generateChallenge", e);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestHal.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestHal.java
index 9db2fcf..8547a68 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestHal.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestHal.java
@@ -45,7 +45,7 @@
return new ISession.Stub() {
@Override
- public void generateChallenge(int cookie, int timeoutSec) throws RemoteException {
+ public void generateChallenge(int cookie) throws RemoteException {
Slog.w(TAG, "generateChallenge, cookie: " + cookie);
cb.onChallengeGenerated(0L);
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index cac6cab..1d0e115 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -35,7 +35,7 @@
import android.net.NetworkInfo;
import android.net.NetworkMonitorManager;
import android.net.NetworkRequest;
-import android.net.NetworkState;
+import android.net.NetworkStateSnapshot;
import android.net.QosCallbackException;
import android.net.QosFilter;
import android.net.QosFilterParcelable;
@@ -890,15 +890,18 @@
mScore = score;
}
- public NetworkState getNetworkState() {
+ /**
+ * Return a {@link NetworkStateSnapshot} for this network.
+ */
+ @NonNull
+ public NetworkStateSnapshot getNetworkStateSnapshot() {
synchronized (this) {
// Network objects are outwardly immutable so there is no point in duplicating.
// Duplicating also precludes sharing socket factories and connection pools.
final String subscriberId = (networkAgentConfig != null)
? networkAgentConfig.subscriberId : null;
- return new NetworkState(new NetworkInfo(networkInfo),
- new LinkProperties(linkProperties),
- new NetworkCapabilities(networkCapabilities), network, subscriberId);
+ return new NetworkStateSnapshot(network, new NetworkCapabilities(networkCapabilities),
+ new LinkProperties(linkProperties), subscriberId, networkInfo.getType());
}
}
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
index 816bf2b..0f5400d 100644
--- a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
+++ b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
@@ -27,7 +27,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.telephony.data.EpsBearerQosSessionAttributes;
-import android.util.Slog;
+import android.util.Log;
import java.util.Objects;
@@ -175,18 +175,14 @@
}
private static void log(@NonNull final String msg) {
- Slog.d(TAG, msg);
+ Log.d(TAG, msg);
}
private static void logw(@NonNull final String msg) {
- Slog.w(TAG, msg);
+ Log.w(TAG, msg);
}
private static void loge(@NonNull final String msg, final Throwable t) {
- Slog.e(TAG, msg, t);
- }
-
- private static void logwtf(@NonNull final String msg) {
- Slog.wtf(TAG, msg);
+ Log.e(TAG, msg, t);
}
}
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
index 7ef315c..8bda532 100644
--- a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
+++ b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
@@ -29,7 +29,7 @@
import android.telephony.data.EpsBearerQosSessionAttributes;
import android.util.Log;
-import com.android.internal.util.CollectionUtils;
+import com.android.net.module.util.CollectionUtils;
import com.android.server.ConnectivityService;
import java.util.ArrayList;
@@ -156,12 +156,13 @@
private void handleUnregisterCallback(@NonNull final IBinder binder,
final boolean sendToNetworkAgent) {
- final QosCallbackAgentConnection agentConnection =
- CollectionUtils.find(mConnections, c -> c.getBinder().equals(binder));
- if (agentConnection == null) {
- logw("handleUnregisterCallback: agentConnection is null");
+ final int connIndex =
+ CollectionUtils.indexOf(mConnections, c -> c.getBinder().equals(binder));
+ if (connIndex < 0) {
+ logw("handleUnregisterCallback: no matching agentConnection");
return;
}
+ final QosCallbackAgentConnection agentConnection = mConnections.get(connIndex);
if (DBG) {
log("handleUnregisterCallback: unregister "
@@ -226,10 +227,10 @@
* @param network the network that was released
*/
public void handleNetworkReleased(@Nullable final Network network) {
- final List<QosCallbackAgentConnection> connections =
- CollectionUtils.filter(mConnections, ac -> ac.getNetwork().equals(network));
-
- for (final QosCallbackAgentConnection agentConnection : connections) {
+ // Iterate in reverse order as agent connections will be removed when unregistering
+ for (int i = mConnections.size() - 1; i >= 0; i--) {
+ final QosCallbackAgentConnection agentConnection = mConnections.get(i);
+ if (!agentConnection.getNetwork().equals(network)) continue;
agentConnection.sendEventQosCallbackError(
QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED);
@@ -247,15 +248,14 @@
@NonNull final String logPrefix,
@NonNull final AgentConnectionAction action) {
mConnectivityServiceHandler.post(() -> {
- final QosCallbackAgentConnection ac =
- CollectionUtils.find(mConnections,
+ final int acIndex = CollectionUtils.indexOf(mConnections,
c -> c.getAgentCallbackId() == qosCallbackId);
- if (ac == null) {
+ if (acIndex == -1) {
loge(logPrefix + ": " + qosCallbackId + " missing callback id");
return;
}
- action.execute(ac);
+ action.execute(mConnections.get(acIndex));
});
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 3709963..a0d9365 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -767,6 +767,12 @@
}
private void setDisplayBrightness(float brightness) {
+ // Ensure brightnessState is valid, before processing and sending to
+ // surface control
+ if (Float.isNaN(brightness)) {
+ return;
+ }
+
if (DEBUG) {
Slog.d(TAG, "setDisplayBrightness("
+ "id=" + physicalDisplayId
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 8d6bcad..7235a92 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -666,8 +666,19 @@
mSelectRequestBuffer.process();
resetSelectRequestBuffer();
- addAndStartAction(new HotplugDetectionAction(HdmiCecLocalDeviceTv.this));
- addAndStartAction(new PowerStatusMonitorAction(HdmiCecLocalDeviceTv.this));
+ List<HotplugDetectionAction> hotplugActions
+ = getActions(HotplugDetectionAction.class);
+ if (hotplugActions.isEmpty()) {
+ addAndStartAction(
+ new HotplugDetectionAction(HdmiCecLocalDeviceTv.this));
+ }
+
+ List<PowerStatusMonitorAction> powerStatusActions
+ = getActions(PowerStatusMonitorAction.class);
+ if (powerStatusActions.isEmpty()) {
+ addAndStartAction(
+ new PowerStatusMonitorAction(HdmiCecLocalDeviceTv.this));
+ }
HdmiDeviceInfo avr = getAvrDeviceInfo();
if (avr != null) {
@@ -1062,7 +1073,21 @@
// Ignore this message.
return true;
}
- setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message));
+ boolean tvSystemAudioMode = isSystemAudioControlFeatureEnabled();
+ boolean avrSystemAudioMode = HdmiUtils.parseCommandParamSystemAudioStatus(message);
+ // Set System Audio Mode according to TV's settings.
+ // Handle <System Audio Mode Status> here only when
+ // SystemAudioAutoInitiationAction timeout
+ HdmiDeviceInfo avr = getAvrDeviceInfo();
+ if (avr == null) {
+ setSystemAudioMode(false);
+ } else if (avrSystemAudioMode != tvSystemAudioMode) {
+ addAndStartAction(new SystemAudioActionFromTv(this, avr.getLogicalAddress(),
+ tvSystemAudioMode, null));
+ } else {
+ setSystemAudioMode(tvSystemAudioMode);
+ }
+
return true;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java b/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java
index 8c40424..6f7473d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java
@@ -106,9 +106,7 @@
addHandler(Constants.MESSAGE_SET_STREAM_PATH, mBystander);
addHandler(Constants.MESSAGE_STANDBY, mBystander);
addHandler(Constants.MESSAGE_SET_MENU_LANGUAGE, mBystander);
- addHandler(Constants.MESSAGE_DEVICE_VENDOR_ID, mBystander);
addHandler(Constants.MESSAGE_USER_CONTROL_RELEASED, mBystander);
- addHandler(Constants.MESSAGE_REPORT_POWER_STATUS, mBystander);
addHandler(Constants.MESSAGE_FEATURE_ABORT, mBystander);
addHandler(Constants.MESSAGE_INACTIVE_SOURCE, mBystander);
addHandler(Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS, mBystander);
@@ -133,6 +131,8 @@
addHandler(Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID, mBypasser);
addHandler(Constants.MESSAGE_GIVE_OSD_NAME, mBypasser);
addHandler(Constants.MESSAGE_SET_OSD_NAME, mBypasser);
+ addHandler(Constants.MESSAGE_DEVICE_VENDOR_ID, mBypasser);
+ addHandler(Constants.MESSAGE_REPORT_POWER_STATUS, mBypasser);
addHandler(Constants.MESSAGE_USER_CONTROL_PRESSED, mUserControlProcessedHandler);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index c0d577c..4e8fcf7 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -159,6 +159,7 @@
import com.android.internal.content.PackageMonitor;
import com.android.internal.inputmethod.CallbackUtils;
import com.android.internal.inputmethod.IBooleanResultCallback;
+import com.android.internal.inputmethod.IIInputContentUriTokenResultCallback;
import com.android.internal.inputmethod.IInputBindResultResultCallback;
import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.inputmethod.IInputMethodInfoListResultCallback;
@@ -5883,87 +5884,102 @@
@BinderThread
@Override
- public void setImeWindowStatus(int vis, int backDisposition) {
- mImms.setImeWindowStatus(mToken, vis, backDisposition);
+ public void setImeWindowStatus(int vis, int backDisposition,
+ IVoidResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback,
+ () -> mImms.setImeWindowStatus(mToken, vis, backDisposition));
}
@BinderThread
@Override
- public void reportStartInput(IBinder startInputToken) {
- mImms.reportStartInput(mToken, startInputToken);
+ public void reportStartInput(IBinder startInputToken, IVoidResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback,
+ () -> mImms.reportStartInput(mToken, startInputToken));
}
@BinderThread
@Override
- public IInputContentUriToken createInputContentUriToken(Uri contentUri,
- String packageName) {
- return mImms.createInputContentUriToken(mToken, contentUri, packageName);
+ public void createInputContentUriToken(Uri contentUri, String packageName,
+ IIInputContentUriTokenResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback,
+ () -> mImms.createInputContentUriToken(mToken, contentUri, packageName));
}
@BinderThread
@Override
- public void reportFullscreenMode(boolean fullscreen) {
- mImms.reportFullscreenMode(mToken, fullscreen);
+ public void reportFullscreenMode(boolean fullscreen, IVoidResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback,
+ () -> mImms.reportFullscreenMode(mToken, fullscreen));
}
@BinderThread
@Override
- public void setInputMethod(String id) {
- mImms.setInputMethod(mToken, id);
+ public void setInputMethod(String id, IVoidResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback, () -> mImms.setInputMethod(mToken, id));
}
@BinderThread
@Override
- public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype) {
- mImms.setInputMethodAndSubtype(mToken, id, subtype);
+ public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype,
+ IVoidResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback,
+ () -> mImms.setInputMethodAndSubtype(mToken, id, subtype));
}
@BinderThread
@Override
- public void hideMySoftInput(int flags) {
- mImms.hideMySoftInput(mToken, flags);
+ public void hideMySoftInput(int flags, IVoidResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback, () -> mImms.hideMySoftInput(mToken, flags));
}
@BinderThread
@Override
- public void showMySoftInput(int flags) {
- mImms.showMySoftInput(mToken, flags);
+ public void showMySoftInput(int flags, IVoidResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback, () -> mImms.showMySoftInput(mToken, flags));
}
@BinderThread
@Override
- public void updateStatusIcon(String packageName, @DrawableRes int iconId) {
- mImms.updateStatusIcon(mToken, packageName, iconId);
+ public void updateStatusIcon(String packageName, @DrawableRes int iconId,
+ IVoidResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback,
+ () -> mImms.updateStatusIcon(mToken, packageName, iconId));
}
@BinderThread
@Override
- public boolean switchToPreviousInputMethod() {
- return mImms.switchToPreviousInputMethod(mToken);
+ public void switchToPreviousInputMethod(IBooleanResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback, () -> mImms.switchToPreviousInputMethod(mToken));
}
@BinderThread
@Override
- public boolean switchToNextInputMethod(boolean onlyCurrentIme) {
- return mImms.switchToNextInputMethod(mToken, onlyCurrentIme);
+ public void switchToNextInputMethod(boolean onlyCurrentIme,
+ IBooleanResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback,
+ () -> mImms.switchToNextInputMethod(mToken, onlyCurrentIme));
}
@BinderThread
@Override
- public boolean shouldOfferSwitchingToNextInputMethod() {
- return mImms.shouldOfferSwitchingToNextInputMethod(mToken);
+ public void shouldOfferSwitchingToNextInputMethod(
+ IBooleanResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback,
+ () -> mImms.shouldOfferSwitchingToNextInputMethod(mToken));
}
@BinderThread
@Override
- public void notifyUserAction() {
- mImms.notifyUserAction(mToken);
+ public void notifyUserAction(IVoidResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback, () -> mImms.notifyUserAction(mToken));
}
@BinderThread
@Override
- public void applyImeVisibility(IBinder windowToken, boolean setVisible) {
- mImms.applyImeVisibility(mToken, windowToken, setVisible);
+ public void applyImeVisibility(IBinder windowToken, boolean setVisible,
+ IVoidResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback,
+ () -> mImms.applyImeVisibility(mToken, windowToken, setVisible));
}
}
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
index 60b7447..7db234a 100644
--- a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
+++ b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
@@ -71,11 +71,6 @@
private static final String CONFIG_GPS_LOCK = "GPS_LOCK";
private static final String CONFIG_ES_EXTENSION_SEC = "ES_EXTENSION_SEC";
public static final String CONFIG_NFW_PROXY_APPS = "NFW_PROXY_APPS";
- private static final String CONFIG_LONGTERM_PSDS_SERVER_1 = "LONGTERM_PSDS_SERVER_1";
- private static final String CONFIG_LONGTERM_PSDS_SERVER_2 = "LONGTERM_PSDS_SERVER_2";
- private static final String CONFIG_LONGTERM_PSDS_SERVER_3 = "LONGTERM_PSDS_SERVER_3";
- private static final String CONFIG_NORMAL_PSDS_SERVER = "NORMAL_PSDS_SERVER";
- private static final String CONFIG_REALTIME_PSDS_SERVER = "REALTIME_PSDS_SERVER";
// Limit on NI emergency mode time extension after emergency sessions ends
private static final int MAX_EMERGENCY_MODE_EXTENSION_SECONDS = 300; // 5 minute maximum
@@ -227,9 +222,6 @@
mProperties.setProperty(CONFIG_LPP_PROFILE, lpp_prof);
}
- // Load Psds servers from resources
- loadPsdsServersFromResources();
-
/*
* Overlay carrier properties from a debug configuration file.
*/
@@ -317,7 +309,7 @@
int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId();
PersistableBundle configs = SubscriptionManager.isValidSubscriptionId(ddSubId)
- ? configManager.getConfigForSubId(ddSubId) : null;
+ ? configManager.getConfigForSubId(ddSubId) : configManager.getConfig();
if (configs == null) {
if (DEBUG) Log.d(TAG, "SIM not ready, use default carrier config.");
configs = CarrierConfigManager.getDefaultConfig();
@@ -382,34 +374,6 @@
}
}
- void loadPsdsServersFromResources() {
- String longTermPsdsServer1 = mContext.getResources().getString(
- com.android.internal.R.string.config_longterm_psds_server_1);
- if (!TextUtils.isEmpty(longTermPsdsServer1)) {
- mProperties.setProperty(CONFIG_LONGTERM_PSDS_SERVER_1, longTermPsdsServer1);
- }
- String longTermPsdsServer2 = mContext.getResources().getString(
- com.android.internal.R.string.config_longterm_psds_server_2);
- if (!TextUtils.isEmpty(longTermPsdsServer2)) {
- mProperties.setProperty(CONFIG_LONGTERM_PSDS_SERVER_2, longTermPsdsServer2);
- }
- String longTermPsdsServer3 = mContext.getResources().getString(
- com.android.internal.R.string.config_longterm_psds_server_3);
- if (!TextUtils.isEmpty(longTermPsdsServer3)) {
- mProperties.setProperty(CONFIG_LONGTERM_PSDS_SERVER_3, longTermPsdsServer3);
- }
- String normalPsdsServer = mContext.getResources().getString(
- com.android.internal.R.string.config_normal_psds_server);
- if (!TextUtils.isEmpty(normalPsdsServer)) {
- mProperties.setProperty(CONFIG_NORMAL_PSDS_SERVER, normalPsdsServer);
- }
- String realtimePsdsServer = mContext.getResources().getString(
- com.android.internal.R.string.config_realtime_psds_server);
- if (!TextUtils.isEmpty(realtimePsdsServer)) {
- mProperties.setProperty(CONFIG_REALTIME_PSDS_SERVER, realtimePsdsServer);
- }
- }
-
private static boolean isConfigEsExtensionSecSupported(
HalInterfaceVersion gnssConfiguartionIfaceVersion) {
// ES_EXTENSION_SEC is introduced in @2.0::IGnssConfiguration.hal
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index 1df29ab..1e5a15e 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -353,6 +353,8 @@
reloadGpsProperties();
} else {
if (DEBUG) Log.d(TAG, "SIM MCC/MNC is still not available");
+ // Reload gnss config for no SIM case
+ mGnssConfiguration.reloadGpsProperties();
}
}
diff --git a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java
index 05d0aef..dbd8dd9 100644
--- a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java
+++ b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java
@@ -21,7 +21,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.os.SystemClock;
-import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import com.android.server.FgThread;
@@ -55,8 +55,8 @@
// TODO: this doesn't account for multisim phones
- mTelephonyManager.registerPhoneStateListener(FgThread.getExecutor(),
- new EmergencyCallPhoneStateListener());
+ mTelephonyManager.registerTelephonyCallback(FgThread.getExecutor(),
+ new EmergencyCallTelephonyCallback());
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -78,8 +78,8 @@
|| mTelephonyManager.isInEmergencySmsMode();
}
- private class EmergencyCallPhoneStateListener extends PhoneStateListener implements
- PhoneStateListener.CallStateChangedListener {
+ private class EmergencyCallTelephonyCallback extends TelephonyCallback implements
+ TelephonyCallback.CallStateListener{
@Override
public void onCallStateChanged(int state, String incomingNumber) {
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 7e00fd6..364aa2c 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -193,6 +193,17 @@
0);
}
+ public int getLoadEscrowDataRetryLimit() {
+ return DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA,
+ "load_escrow_data_retry_count", DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT);
+ }
+
+ public int getLoadEscrowDataRetryIntervalSeconds() {
+ return DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA,
+ "load_escrow_data_retry_interval_seconds",
+ DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS);
+ }
+
public void reportMetric(boolean success) {
// TODO(b/179105110) design error code; and report the true value for other fields.
FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, 0, 1, 1,
@@ -251,11 +262,8 @@
List<UserInfo> users, List<UserInfo> rebootEscrowUsers) {
Objects.requireNonNull(retryHandler);
- final int retryLimit = DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA,
- "load_escrow_data_retry_count", DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT);
- final int retryIntervalInSeconds = DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA,
- "load_escrow_data_retry_interval_seconds",
- DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS);
+ final int retryLimit = mInjector.getLoadEscrowDataRetryLimit();
+ final int retryIntervalInSeconds = mInjector.getLoadEscrowDataRetryIntervalSeconds();
if (attemptNumber < retryLimit) {
Slog.i(TAG, "Scheduling loadRebootEscrowData retry number: " + attemptNumber);
diff --git a/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
index 9c471b8..ec80521 100644
--- a/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
+++ b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
@@ -136,7 +136,7 @@
}
/** Bind to the service */
- public void bindToService(long timeOut) throws TimeoutException {
+ public void bindToService(long timeOut) throws RemoteException, TimeoutException {
if (mBinder == null || !mBinder.asBinder().isBinderAlive()) {
CountDownLatch connectionLatch = new CountDownLatch(1);
Intent intent = new Intent();
@@ -210,27 +210,25 @@
private void throwTypedException(
ParcelableException exception)
- throws IOException {
- if (exception.getCause() instanceof IOException) {
+ throws IOException, RemoteException {
+ if (exception != null && exception.getCause() instanceof IOException) {
exception.maybeRethrow(IOException.class);
- } else if (exception.getCause() instanceof IllegalStateException) {
- exception.maybeRethrow(IllegalStateException.class);
} else {
- // This should not happen. Wrap the cause in IllegalStateException so that it
- // doesn't disrupt the exception handling
- throw new IllegalStateException(exception.getCause());
+ // Wrap the exception and throw it as a RemoteException.
+ throw new RemoteException(TAG + " wrap/unwrap failed", exception,
+ true /* enableSuppression */, true /* writableStackTrace */);
}
}
private void waitForLatch(CountDownLatch latch, String reason, long timeOut)
- throws TimeoutException {
+ throws RemoteException, TimeoutException {
try {
if (!latch.await(timeOut, TimeUnit.SECONDS)) {
throw new TimeoutException("Latch wait for " + reason + " elapsed");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
- throw new IllegalStateException("Latch wait for " + reason + " interrupted");
+ throw new RemoteException("Latch wait for " + reason + " interrupted");
}
}
}
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 7ab8b27..a5763ae 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -35,6 +35,7 @@
import android.service.gatekeeper.GateKeeperResponse;
import android.service.gatekeeper.IGateKeeperService;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -906,7 +907,7 @@
if (!tokenMap.containsKey(userId)) {
return Collections.emptySet();
}
- return tokenMap.get(userId).keySet();
+ return new ArraySet<>(tokenMap.get(userId).keySet());
}
public boolean removePendingToken(long handle, int userId) {
diff --git a/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java b/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java
index 639dda6..23195bb 100644
--- a/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java
+++ b/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java
@@ -93,8 +93,7 @@
StatsLog.write(statsEvent);
}
- @Override
- public String getSessionId(int userId) {
+ private String getSessionIdInternal(int userId) {
byte[] byteId = new byte[16]; // 128 bits
mSecureRandom.nextBytes(byteId);
String id = Base64.encodeToString(byteId, Base64.DEFAULT);
@@ -102,6 +101,16 @@
}
@Override
+ public String getPlaybackSessionId(int userId) {
+ return getSessionIdInternal(userId);
+ }
+
+ @Override
+ public String getRecordingSessionId(int userId) {
+ return getSessionIdInternal(userId);
+ }
+
+ @Override
public void reportPlaybackErrorEvent(
String sessionId, PlaybackErrorEvent event, int userId) {
StatsEvent statsEvent = StatsEvent.newBuilder()
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 067c5c0e..da62aca 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -169,11 +169,10 @@
import android.net.NetworkPolicy;
import android.net.NetworkPolicyManager;
import android.net.NetworkPolicyManager.UidState;
-import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.net.NetworkStack;
-import android.net.NetworkState;
+import android.net.NetworkStateSnapshot;
import android.net.NetworkStats;
import android.net.NetworkTemplate;
import android.net.TelephonyNetworkSpecifier;
@@ -431,7 +430,7 @@
private final CarrierConfigManager mCarrierConfigManager;
private final MultipathPolicyTracker mMultipathPolicyTracker;
- private IConnectivityManager mConnManager;
+ private ConnectivityManager mConnManager;
private PowerManagerInternal mPowerManagerInternal;
private PowerWhitelistManager mPowerWhitelistManager;
@@ -711,8 +710,9 @@
new NetworkPolicyManagerInternalImpl());
}
- public void bindConnectivityManager(IConnectivityManager connManager) {
- mConnManager = Objects.requireNonNull(connManager, "missing IConnectivityManager");
+ public void bindConnectivityManager() {
+ mConnManager = Objects.requireNonNull(mContext.getSystemService(ConnectivityManager.class),
+ "missing ConnectivityManager");
}
@GuardedBy("mUidRulesFirstLock")
@@ -943,7 +943,7 @@
mContext.registerReceiver(mCarrierConfigReceiver, carrierConfigFilter, null, mHandler);
// listen for meteredness changes
- mContext.getSystemService(ConnectivityManager.class).registerNetworkCallback(
+ mConnManager.registerNetworkCallback(
new NetworkRequest.Builder().build(), mNetworkCallback);
mAppStandby.addListener(new NetPolicyAppIdleStateChangeListener());
@@ -1887,14 +1887,14 @@
}
/**
- * Collect all ifaces from a {@link NetworkState} into the given set.
+ * Collect all ifaces from a {@link NetworkStateSnapshot} into the given set.
*/
- private static void collectIfaces(ArraySet<String> ifaces, NetworkState state) {
- final String baseIface = state.linkProperties.getInterfaceName();
+ private static void collectIfaces(ArraySet<String> ifaces, NetworkStateSnapshot snapshot) {
+ final String baseIface = snapshot.linkProperties.getInterfaceName();
if (baseIface != null) {
ifaces.add(baseIface);
}
- for (LinkProperties stackedLink : state.linkProperties.getStackedLinks()) {
+ for (LinkProperties stackedLink : snapshot.linkProperties.getStackedLinks()) {
final String stackedIface = stackedLink.getInterfaceName();
if (stackedIface != null) {
ifaces.add(stackedIface);
@@ -1964,7 +1964,7 @@
}
/**
- * Examine all connected {@link NetworkState}, looking for
+ * Examine all connected {@link NetworkStateSnapshot}, looking for
* {@link NetworkPolicy} that need to be enforced. When matches found, set
* remaining quota based on usage cycle and historical stats.
*/
@@ -1973,29 +1973,21 @@
if (LOGV) Slog.v(TAG, "updateNetworkRulesNL()");
Trace.traceBegin(TRACE_TAG_NETWORK, "updateNetworkRulesNL");
- final NetworkState[] states;
- try {
- states = defeatNullable(mConnManager.getAllNetworkState());
- } catch (RemoteException e) {
- // ignored; service lives in system_server
- return;
- }
+ final List<NetworkStateSnapshot> snapshots = mConnManager.getAllNetworkStateSnapshot();
// First, generate identities of all connected networks so we can
// quickly compare them against all defined policies below.
mNetIdToSubId.clear();
- final ArrayMap<NetworkState, NetworkIdentity> identified = new ArrayMap<>();
- for (NetworkState state : states) {
- if (state.network != null) {
- mNetIdToSubId.put(state.network.netId, parseSubId(state));
- }
+ final ArrayMap<NetworkStateSnapshot, NetworkIdentity> identified = new ArrayMap<>();
+ for (final NetworkStateSnapshot snapshot : snapshots) {
+ mNetIdToSubId.put(snapshot.network.netId, parseSubId(snapshot));
// Policies matched by NPMS only match by subscriber ID or by ssid. Thus subtype
// in the object created here is never used and its value doesn't matter, so use
// NETWORK_TYPE_UNKNOWN.
- final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state,
+ final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot,
true, TelephonyManager.NETWORK_TYPE_UNKNOWN /* subType */);
- identified.put(state, ident);
+ identified.put(snapshot, ident);
}
final ArraySet<String> newMeteredIfaces = new ArraySet<>();
@@ -2069,10 +2061,10 @@
// One final pass to catch any metered ifaces that don't have explicitly
// defined policies; typically Wi-Fi networks.
- for (NetworkState state : states) {
- if (!state.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) {
+ for (final NetworkStateSnapshot snapshot : snapshots) {
+ if (!snapshot.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) {
matchingIfaces.clear();
- collectIfaces(matchingIfaces, state);
+ collectIfaces(matchingIfaces, snapshot);
for (int j = matchingIfaces.size() - 1; j >= 0; j--) {
final String iface = matchingIfaces.valueAt(j);
if (!newMeteredIfaces.contains(iface)) {
@@ -2104,16 +2096,16 @@
// Finally, calculate our opportunistic quotas
mSubscriptionOpportunisticQuota.clear();
- for (NetworkState state : states) {
+ for (final NetworkStateSnapshot snapshot : snapshots) {
if (!quotaEnabled) continue;
- if (state.network == null) continue;
- final int subId = getSubIdLocked(state.network);
+ if (snapshot.network == null) continue;
+ final int subId = getSubIdLocked(snapshot.network);
final SubscriptionPlan plan = getPrimarySubscriptionPlanLocked(subId);
if (plan == null) continue;
final long quotaBytes;
final long limitBytes = plan.getDataLimitBytes();
- if (!state.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING)) {
+ if (!snapshot.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING)) {
// Clamp to 0 when roaming
quotaBytes = 0;
} else if (limitBytes == SubscriptionPlan.BYTES_UNKNOWN) {
@@ -2131,7 +2123,7 @@
.truncatedTo(ChronoUnit.DAYS)
.toInstant().toEpochMilli();
final long totalBytes = getTotalBytes(
- NetworkTemplate.buildTemplateMobileAll(state.subscriberId),
+ NetworkTemplate.buildTemplateMobileAll(snapshot.subscriberId),
start, startOfDay);
final long remainingBytes = limitBytes - totalBytes;
// Number of remaining days including current day
@@ -3164,14 +3156,6 @@
}
}
- @Override
- @Deprecated
- public NetworkQuotaInfo getNetworkQuotaInfo(NetworkState state) {
- Log.w(TAG, "Shame on UID " + Binder.getCallingUid()
- + " for calling the hidden API getNetworkQuotaInfo(). Shame!");
- return new NetworkQuotaInfo();
- }
-
private void enforceSubscriptionPlanAccess(int subId, int callingUid, String callingPackage) {
// Verify they're not lying about package name
mAppOps.checkPackage(callingUid, callingPackage);
@@ -5635,11 +5619,10 @@
}
}
- private int parseSubId(NetworkState state) {
+ private int parseSubId(@NonNull NetworkStateSnapshot snapshot) {
int subId = INVALID_SUBSCRIPTION_ID;
- if (state != null && state.networkCapabilities != null
- && state.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
- NetworkSpecifier spec = state.networkCapabilities.getNetworkSpecifier();
+ if (snapshot.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
+ NetworkSpecifier spec = snapshot.networkCapabilities.getNetworkSpecifier();
if (spec instanceof TelephonyNetworkSpecifier) {
subId = ((TelephonyNetworkSpecifier) spec).getSubscriptionId();
}
@@ -5716,10 +5699,6 @@
return (uidRules & rule) != 0;
}
- private static @NonNull NetworkState[] defeatNullable(@Nullable NetworkState[] val) {
- return (val != null) ? val : new NetworkState[0];
- }
-
private static boolean getBooleanDefeatingNullable(@Nullable PersistableBundle bundle,
String key, boolean defaultValue) {
return (bundle != null) ? bundle.getBoolean(key, defaultValue) : defaultValue;
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index ebf1fe9..e0f5346 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -24,7 +24,6 @@
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.EXTRA_UID;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.ConnectivityManager.isNetworkTypeMobile;
import static android.net.NetworkIdentity.SUBTYPE_COMBINED;
import static android.net.NetworkStack.checkNetworkStackPermission;
@@ -45,6 +44,7 @@
import static android.net.NetworkStatsHistory.FIELD_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
+import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.TrafficStats.KB_IN_BYTES;
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.net.TrafficStats.UNSUPPORTED;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7da53b5..b751503 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -20368,6 +20368,11 @@
return;
}
+ if (isIncrementalPath(pkg.getPath()) && IncrementalManager.getVersion()
+ < IncrementalManager.MIN_VERSION_TO_SUPPORT_FSVERITY) {
+ return;
+ }
+
// Collect files we care for fs-verity setup.
ArrayMap<String, String> fsverityCandidates = new ArrayMap<>();
if (legacyMode) {
diff --git a/services/core/java/com/android/server/pm/SettingsXml.java b/services/core/java/com/android/server/pm/SettingsXml.java
index ec643f5..c53fef7 100644
--- a/services/core/java/com/android/server/pm/SettingsXml.java
+++ b/services/core/java/com/android/server/pm/SettingsXml.java
@@ -83,7 +83,7 @@
@Override
public void close() throws IOException {
mWriteSection.closeCompletely();
- mXmlSerializer.endDocument();
+ mXmlSerializer.flush();
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index a377f1c..d1cf55d 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -103,6 +103,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.infra.AndroidFuture;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.CollectionUtils;
@@ -142,6 +143,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -1885,8 +1887,8 @@
// === APIs ===
@Override
- public boolean setDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList,
- @UserIdInt int userId) {
+ public void setDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList,
+ @UserIdInt int userId, @NonNull AndroidFuture callback) {
verifyCaller(packageName, userId);
final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
@@ -1913,7 +1915,7 @@
// Throttling.
if (!ps.tryApiCall(unlimited)) {
- return false;
+ callback.complete(false);
}
// Initialize the implicit ranks for ShortcutPackage.adjustRanks().
@@ -1949,12 +1951,12 @@
verifyStates();
- return true;
+ callback.complete(true);
}
@Override
- public boolean updateShortcuts(String packageName, ParceledListSlice shortcutInfoList,
- @UserIdInt int userId) {
+ public void updateShortcuts(String packageName, ParceledListSlice shortcutInfoList,
+ @UserIdInt int userId, AndroidFuture callback) {
verifyCaller(packageName, userId);
final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
@@ -1981,7 +1983,8 @@
// Throttling.
if (!ps.tryApiCall(unlimited)) {
- return false;
+ callback.complete(false);
+ return;
}
// Initialize the implicit ranks for ShortcutPackage.adjustRanks().
@@ -2046,12 +2049,12 @@
verifyStates();
- return true;
+ callback.complete(true);
}
@Override
- public boolean addDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList,
- @UserIdInt int userId) {
+ public void addDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList,
+ @UserIdInt int userId, AndroidFuture callback) {
verifyCaller(packageName, userId);
final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
@@ -2081,7 +2084,8 @@
// Throttling.
if (!ps.tryApiCall(unlimited)) {
- return false;
+ callback.complete(false);
+ return;
}
for (int i = 0; i < size; i++) {
final ShortcutInfo newShortcut = newShortcuts.get(i);
@@ -2109,7 +2113,7 @@
verifyStates();
- return true;
+ callback.complete(true);
}
@Override
@@ -2174,15 +2178,17 @@
}
@Override
- public boolean requestPinShortcut(String packageName, ShortcutInfo shortcut,
- IntentSender resultIntent, int userId) {
+ public void requestPinShortcut(String packageName, ShortcutInfo shortcut,
+ IntentSender resultIntent, int userId, AndroidFuture callback) {
Objects.requireNonNull(shortcut);
+ Objects.requireNonNull(callback);
Preconditions.checkArgument(shortcut.isEnabled(), "Shortcut must be enabled");
- return requestPinItem(packageName, userId, shortcut, null, null, resultIntent);
+ callback.complete(requestPinItem(packageName, userId, shortcut, null, null, resultIntent));
}
@Override
- public Intent createShortcutResultIntent(String packageName, ShortcutInfo shortcut, int userId)
+ public void createShortcutResultIntent(String packageName, ShortcutInfo shortcut, int userId,
+ AndroidFuture callback)
throws RemoteException {
Objects.requireNonNull(shortcut);
Preconditions.checkArgument(shortcut.isEnabled(), "Shortcut must be enabled");
@@ -2198,7 +2204,7 @@
}
verifyStates();
- return ret;
+ callback.complete(ret);
}
/**
@@ -2455,8 +2461,9 @@
}
@Override
- public ParceledListSlice<ShortcutInfo> getShortcuts(String packageName,
- @ShortcutManager.ShortcutMatchFlags int matchFlags, @UserIdInt int userId) {
+ public void getShortcuts(String packageName,
+ @ShortcutManager.ShortcutMatchFlags int matchFlags, @UserIdInt int userId,
+ AndroidFuture<ParceledListSlice<ShortcutInfo>> callback) {
verifyCaller(packageName, userId);
synchronized (mLock) {
@@ -2472,16 +2479,16 @@
| (matchManifest ? ShortcutInfo.FLAG_MANIFEST : 0)
| (matchCached ? ShortcutInfo.FLAG_CACHED_ALL : 0);
- return getShortcutsWithQueryLocked(
+ callback.complete(getShortcutsWithQueryLocked(
packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
(ShortcutInfo si) ->
- si.isVisibleToPublisher() && (si.getFlags() & shortcutFlags) != 0);
+ si.isVisibleToPublisher() && (si.getFlags() & shortcutFlags) != 0));
}
}
@Override
- public ParceledListSlice<ShortcutManager.ShareShortcutInfo> getShareTargets(String packageName,
- IntentFilter filter, @UserIdInt int userId) {
+ public void getShareTargets(String packageName, IntentFilter filter, @UserIdInt int userId,
+ AndroidFuture<ParceledListSlice> callback) {
Preconditions.checkStringNotEmpty(packageName, "packageName");
Objects.requireNonNull(filter, "intentFilter");
@@ -2497,7 +2504,7 @@
final ShortcutUser user = getUserShortcutsLocked(userId);
user.forAllPackages(p -> shortcutInfoList.addAll(p.getMatchingShareTargets(filter)));
- return new ParceledListSlice<>(shortcutInfoList);
+ callback.complete(new ParceledListSlice<>(shortcutInfoList));
}
}
@@ -3081,8 +3088,14 @@
@Override
public List<ShortcutManager.ShareShortcutInfo> getShareTargets(
@NonNull String callingPackage, @NonNull IntentFilter intentFilter, int userId) {
- return ShortcutService.this.getShareTargets(
- callingPackage, intentFilter, userId).getList();
+ final AndroidFuture<ParceledListSlice> future = new AndroidFuture<>();
+ ShortcutService.this.getShareTargets(
+ callingPackage, intentFilter, userId, future);
+ try {
+ return future.get().getList();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException(e);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 871576e..8283ac6 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1544,7 +1544,7 @@
public String getUserName() {
final int callingUid = Binder.getCallingUid();
if (!hasManageOrCreateUsersPermission()
- || hasPermissionGranted(
+ && !hasPermissionGranted(
android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED, callingUid)) {
throw new SecurityException("You need MANAGE_USERS or CREATE_USERS or "
+ "GET_ACCOUNTS_PRIVILEGED permissions to: get user name");
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
index c9067a3..b61fd8d 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
@@ -33,9 +33,9 @@
import com.android.internal.util.CollectionUtils;
import com.android.server.pm.PackageSetting;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
import com.android.server.pm.verify.domain.models.DomainVerificationStateMap;
-import com.android.server.pm.verify.domain.models.DomainVerificationUserState;
import java.util.Arrays;
import java.util.function.Function;
@@ -169,8 +169,8 @@
}
ArraySet<String> allWebDomains = mCollector.collectAllWebDomains(pkg);
- SparseArray<DomainVerificationUserState> userStates =
- pkgState.getUserSelectionStates();
+ SparseArray<DomainVerificationInternalUserState> userStates =
+ pkgState.getUserStates();
if (userId == UserHandle.USER_ALL) {
int size = userStates.size();
if (size == 0) {
@@ -178,13 +178,13 @@
wasHeaderPrinted);
} else {
for (int index = 0; index < size; index++) {
- DomainVerificationUserState userState = userStates.valueAt(index);
+ DomainVerificationInternalUserState userState = userStates.valueAt(index);
printState(writer, pkgState, userState.getUserId(), userState, reusedSet,
allWebDomains, wasHeaderPrinted);
}
}
} else {
- DomainVerificationUserState userState = userStates.get(userId);
+ DomainVerificationInternalUserState userState = userStates.get(userId);
printState(writer, pkgState, userId, userState, reusedSet, allWebDomains,
wasHeaderPrinted);
}
@@ -192,8 +192,9 @@
boolean printState(@NonNull IndentingPrintWriter writer,
@NonNull DomainVerificationPkgState pkgState, @UserIdInt int userId,
- @Nullable DomainVerificationUserState userState, @NonNull ArraySet<String> reusedSet,
- @NonNull ArraySet<String> allWebDomains, boolean wasHeaderPrinted) {
+ @Nullable DomainVerificationInternalUserState userState,
+ @NonNull ArraySet<String> reusedSet, @NonNull ArraySet<String> allWebDomains,
+ boolean wasHeaderPrinted) {
reusedSet.clear();
reusedSet.addAll(allWebDomains);
if (userState != null) {
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationEnforcer.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationEnforcer.java
index ed37fa0..1721a18 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationEnforcer.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationEnforcer.java
@@ -132,6 +132,21 @@
/**
* Enforced when mutating user selection state inside an exposed API method.
*/
+ public boolean assertApprovedUserStateQuerent(int callingUid, @UserIdInt int callingUserId,
+ @NonNull String packageName, @UserIdInt int targetUserId) throws SecurityException {
+ if (callingUserId != targetUserId) {
+ mContext.enforcePermission(
+ Manifest.permission.INTERACT_ACROSS_USERS,
+ Binder.getCallingPid(), callingUid,
+ "Caller is not allowed to edit other users");
+ }
+
+ return !mCallback.filterAppAccess(packageName, callingUid, targetUserId);
+ }
+
+ /**
+ * Enforced when mutating user selection state inside an exposed API method.
+ */
public boolean assertApprovedUserSelector(int callingUid, @UserIdInt int callingUserId,
@Nullable String packageName, @UserIdInt int targetUserId) throws SecurityException {
if (callingUserId != targetUserId) {
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationLegacySettings.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationLegacySettings.java
index c787356..4bad102 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationLegacySettings.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationLegacySettings.java
@@ -32,7 +32,6 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
-import java.util.Map;
/**
* Reads and writes the old {@link android.content.pm.IntentFilterVerificationInfo} so that it can
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
index a68b3da..0c2b4c5 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
@@ -48,7 +48,7 @@
import java.util.UUID;
import java.util.function.Function;
-public interface DomainVerificationManagerInternal extends DomainVerificationManager {
+public interface DomainVerificationManagerInternal {
UUID DISABLED_ID = new UUID(0, 0);
@@ -69,8 +69,8 @@
* during the legacy transition period.
*
* TODO(b/177923646): The legacy values can be removed once the Settings API changes are
- * shipped. These values are not stable, so just deleting the constant and shifting others is
- * fine.
+ * shipped. These values are not stable, so just deleting the constant and shifting others is
+ * fine.
*/
int APPROVAL_LEVEL_LEGACY_ASK = 1;
@@ -84,14 +84,15 @@
/**
* The app has been chosen by the user through
- * {@link #setDomainVerificationUserSelection(UUID, Set, boolean)}, indictag an explicit
- * choice to use this app to open an unverified domain.
+ * {@link DomainVerificationManager#setDomainVerificationUserSelection(UUID, Set, boolean)},
+ * indicating an explicit choice to use this app to open an unverified domain.
*/
int APPROVAL_LEVEL_SELECTION = 2;
/**
* The app is approved through the digital asset link statement being hosted at the domain
- * it is capturing. This is set through {@link #setDomainVerificationStatus(UUID, Set, int)} by
+ * it is capturing. This is set through
+ * {@link DomainVerificationManager#setDomainVerificationStatus(UUID, Set, int)} by
* the domain verification agent on device.
*/
int APPROVAL_LEVEL_VERIFIED = 3;
@@ -102,7 +103,7 @@
* declares against the digital asset link statements before allowing it to be installed.
*
* The user is still able to disable instant app link handling through
- * {@link #setDomainVerificationLinkHandlingAllowed(String, boolean)}.
+ * {@link DomainVerificationManager#setDomainVerificationLinkHandlingAllowed(String, boolean)}.
*/
int APPROVAL_LEVEL_INSTANT_APP = 4;
@@ -122,7 +123,17 @@
APPROVAL_LEVEL_VERIFIED,
APPROVAL_LEVEL_INSTANT_APP
})
- @interface ApprovalLevel{}
+ @interface ApprovalLevel {
+ }
+
+ /** @see DomainVerificationManager#getDomainVerificationInfo(String) */
+ @Nullable
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.DOMAIN_VERIFICATION_AGENT,
+ android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION
+ })
+ DomainVerificationInfo getDomainVerificationInfo(@NonNull String packageName)
+ throws NameNotFoundException;
/**
* Generate a new domain set ID to be used for attaching new packages.
@@ -173,9 +184,9 @@
/**
* Migrates verification state from a previous install to a new one. It is expected that the
* {@link PackageSetting#getDomainSetId()} already be set to the correct value, usually from
- * {@link #generateNewId()}. This will preserve {@link #STATE_SUCCESS} domains under the
- * assumption that the new package will pass the same server side config as the previous
- * package, as they have matching signatures.
+ * {@link #generateNewId()}. This will preserve {@link DomainVerificationManager#STATE_SUCCESS}
+ * domains under the assumption that the new package will pass the same server side config as
+ * the previous package, as they have matching signatures.
* <p>
* This will mutate internal {@link DomainVerificationPkgState} and so will hold the internal
* lock. This should never be called from within the domain verification classes themselves.
@@ -229,8 +240,10 @@
* tag has already been entered.
* <p>
* This is <b>only</b> for restore, and will override package states, ignoring if their {@link
- * DomainVerificationInfo#getIdentifier()}s match. It's expected that any restored domains marked
- * as success verify against the server correctly, although the verification agent may decide to
+ * DomainVerificationInfo#getIdentifier()}s match. It's expected that any restored domains
+ * marked
+ * as success verify against the server correctly, although the verification agent may decide
+ * to
* re-verify them when it gets the chance.
*/
/*
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java
index 6f28107..a7a52e0 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerStub.java
@@ -23,29 +23,29 @@
import android.content.pm.verify.domain.DomainOwner;
import android.content.pm.verify.domain.DomainSet;
import android.content.pm.verify.domain.DomainVerificationInfo;
+import android.content.pm.verify.domain.DomainVerificationManager;
import android.content.pm.verify.domain.DomainVerificationManager.InvalidDomainSetException;
-import android.content.pm.verify.domain.DomainVerificationManagerImpl;
-import android.content.pm.verify.domain.DomainVerificationUserSelection;
+import android.content.pm.verify.domain.DomainVerificationUserState;
import android.content.pm.verify.domain.IDomainVerificationManager;
import android.os.ServiceSpecificException;
import java.util.List;
import java.util.UUID;
-class DomainVerificationManagerStub extends IDomainVerificationManager.Stub {
+public class DomainVerificationManagerStub extends IDomainVerificationManager.Stub {
@NonNull
- private DomainVerificationService mService;
+ private final DomainVerificationService mService;
- DomainVerificationManagerStub(DomainVerificationService service) {
+ public DomainVerificationManagerStub(DomainVerificationService service) {
mService = service;
}
@NonNull
@Override
- public List<String> getValidVerificationPackageNames() {
+ public List<String> queryValidVerificationPackageNames() {
try {
- return mService.getValidVerificationPackageNames();
+ return mService.queryValidVerificationPackageNames();
} catch (Exception e) {
throw rethrow(e);
}
@@ -95,10 +95,10 @@
@Nullable
@Override
- public DomainVerificationUserSelection getDomainVerificationUserSelection(
+ public DomainVerificationUserState getDomainVerificationUserState(
String packageName, @UserIdInt int userId) {
try {
- return mService.getDomainVerificationUserSelection(packageName, userId);
+ return mService.getDomainVerificationUserState(packageName, userId);
} catch (Exception e) {
throw rethrow(e);
}
@@ -117,13 +117,13 @@
private RuntimeException rethrow(Exception exception) throws RuntimeException {
if (exception instanceof InvalidDomainSetException) {
- int packedErrorCode = DomainVerificationManagerImpl.ERROR_INVALID_DOMAIN_SET;
+ int packedErrorCode = DomainVerificationManager.ERROR_INVALID_DOMAIN_SET;
packedErrorCode |= ((InvalidDomainSetException) exception).getReason() << 16;
return new ServiceSpecificException(packedErrorCode,
((InvalidDomainSetException) exception).getPackageName());
} else if (exception instanceof NameNotFoundException) {
return new ServiceSpecificException(
- DomainVerificationManagerImpl.ERROR_NAME_NOT_FOUND);
+ DomainVerificationManager.ERROR_NAME_NOT_FOUND);
} else if (exception instanceof RuntimeException) {
return (RuntimeException) exception;
} else {
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationPersistence.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationPersistence.java
index c864b29..abb8d2f 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationPersistence.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationPersistence.java
@@ -27,9 +27,9 @@
import android.util.TypedXmlSerializer;
import com.android.server.pm.SettingsXml;
+import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
import com.android.server.pm.verify.domain.models.DomainVerificationStateMap;
-import com.android.server.pm.verify.domain.models.DomainVerificationUserState;
import org.xmlpull.v1.XmlPullParserException;
@@ -157,7 +157,7 @@
UUID id = UUID.fromString(idString);
final ArrayMap<String, Integer> stateMap = new ArrayMap<>();
- final SparseArray<DomainVerificationUserState> userStates = new SparseArray<>();
+ final SparseArray<DomainVerificationInternalUserState> userStates = new SparseArray<>();
SettingsXml.ChildSection child = section.children();
while (child.moveToNext()) {
@@ -176,10 +176,10 @@
}
private static void readUserStates(@NonNull SettingsXml.ReadSection section,
- @NonNull SparseArray<DomainVerificationUserState> userStates) {
+ @NonNull SparseArray<DomainVerificationInternalUserState> userStates) {
SettingsXml.ChildSection child = section.children();
while (child.moveToNext(TAG_USER_STATE)) {
- DomainVerificationUserState userState = createUserStateFromXml(child);
+ DomainVerificationInternalUserState userState = createUserStateFromXml(child);
if (userState != null) {
userStates.put(userState.getUserId(), userState);
}
@@ -205,12 +205,12 @@
.attribute(ATTR_HAS_AUTO_VERIFY_DOMAINS,
pkgState.isHasAutoVerifyDomains())) {
writeStateMap(parentSection, pkgState.getStateMap());
- writeUserStates(parentSection, pkgState.getUserSelectionStates());
+ writeUserStates(parentSection, pkgState.getUserStates());
}
}
private static void writeUserStates(@NonNull SettingsXml.WriteSection parentSection,
- @NonNull SparseArray<DomainVerificationUserState> states) throws IOException {
+ @NonNull SparseArray<DomainVerificationInternalUserState> states) throws IOException {
int size = states.size();
if (size == 0) {
return;
@@ -245,7 +245,7 @@
* entered.
*/
@Nullable
- public static DomainVerificationUserState createUserStateFromXml(
+ public static DomainVerificationInternalUserState createUserStateFromXml(
@NonNull SettingsXml.ReadSection section) {
int userId = section.getInt(ATTR_USER_ID);
if (userId == -1) {
@@ -260,7 +260,7 @@
readEnabledHosts(child, enabledHosts);
}
- return new DomainVerificationUserState(userId, enabledHosts, allowLinkHandling);
+ return new DomainVerificationInternalUserState(userId, enabledHosts, allowLinkHandling);
}
private static void readEnabledHosts(@NonNull SettingsXml.ReadSection section,
@@ -275,7 +275,7 @@
}
public static void writeUserStateToXml(@NonNull SettingsXml.WriteSection parentSection,
- @NonNull DomainVerificationUserState userState) throws IOException {
+ @NonNull DomainVerificationInternalUserState userState) throws IOException {
try (SettingsXml.WriteSection section =
parentSection.startSection(TAG_USER_STATE)
.attribute(ATTR_USER_ID, userState.getUserId())
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index dbd7f96..e85bbe4 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -34,8 +34,9 @@
import android.content.pm.verify.domain.DomainOwner;
import android.content.pm.verify.domain.DomainVerificationInfo;
import android.content.pm.verify.domain.DomainVerificationManager;
+import android.content.pm.verify.domain.DomainVerificationManager.InvalidDomainSetException;
import android.content.pm.verify.domain.DomainVerificationState;
-import android.content.pm.verify.domain.DomainVerificationUserSelection;
+import android.content.pm.verify.domain.DomainVerificationUserState;
import android.content.pm.verify.domain.IDomainVerificationManager;
import android.os.UserHandle;
import android.util.ArrayMap;
@@ -55,9 +56,9 @@
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.PackageSetting;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
import com.android.server.pm.verify.domain.models.DomainVerificationStateMap;
-import com.android.server.pm.verify.domain.models.DomainVerificationUserState;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyUnavailable;
@@ -208,8 +209,7 @@
}
@NonNull
- @Override
- public List<String> getValidVerificationPackageNames() {
+ public List<String> queryValidVerificationPackageNames() {
mEnforcer.assertApprovedVerifier(mConnection.getCallingUid(), mProxy);
List<String> packageNames = new ArrayList<>();
synchronized (mLock) {
@@ -272,7 +272,6 @@
}
}
- @Override
public void setDomainVerificationStatus(@NonNull UUID domainSetId, @NonNull Set<String> domains,
int state) throws InvalidDomainSetException, NameNotFoundException {
if (state < DomainVerificationState.STATE_FIRST_VERIFIER_DEFINED) {
@@ -314,7 +313,7 @@
int size = verifiedDomains.size();
for (int index = 0; index < size; index++) {
- removeUserSelectionsForDomain(verifiedDomains.get(index));
+ removeUserStatesForDomain(verifiedDomains.get(index));
}
}
@@ -401,12 +400,12 @@
}
}
- private void removeUserSelectionsForDomain(@NonNull String domain) {
+ private void removeUserStatesForDomain(@NonNull String domain) {
synchronized (mLock) {
final int size = mAttachedPkgStates.size();
for (int index = 0; index < size; index++) {
DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index);
- SparseArray<DomainVerificationUserState> array = pkgState.getUserSelectionStates();
+ SparseArray<DomainVerificationInternalUserState> array = pkgState.getUserStates();
int arraySize = array.size();
for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) {
array.valueAt(arrayIndex).removeHost(domain);
@@ -415,13 +414,6 @@
}
}
- @Override
- public void setDomainVerificationLinkHandlingAllowed(@NonNull String packageName,
- boolean allowed) throws NameNotFoundException {
- setDomainVerificationLinkHandlingAllowed(packageName, allowed,
- mConnection.getCallingUserId());
- }
-
public void setDomainVerificationLinkHandlingAllowed(@NonNull String packageName,
boolean allowed, @UserIdInt int userId) throws NameNotFoundException {
if (!mEnforcer.assertApprovedUserSelector(mConnection.getCallingUid(),
@@ -434,7 +426,7 @@
throw DomainVerificationUtils.throwPackageUnavailable(packageName);
}
- pkgState.getOrCreateUserSelectionState(userId)
+ pkgState.getOrCreateUserState(userId)
.setLinkHandlingAllowed(allowed);
}
@@ -452,11 +444,11 @@
DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(pkgStateIndex);
if (userId == UserHandle.USER_ALL) {
for (int aUserId : mConnection.getAllUserIds()) {
- pkgState.getOrCreateUserSelectionState(aUserId)
+ pkgState.getOrCreateUserState(aUserId)
.setLinkHandlingAllowed(allowed);
}
} else {
- pkgState.getOrCreateUserSelectionState(userId)
+ pkgState.getOrCreateUserState(userId)
.setLinkHandlingAllowed(allowed);
}
}
@@ -468,7 +460,7 @@
throw DomainVerificationUtils.throwPackageUnavailable(packageName);
}
- pkgState.getOrCreateUserSelectionState(userId)
+ pkgState.getOrCreateUserState(userId)
.setLinkHandlingAllowed(allowed);
}
}
@@ -476,14 +468,6 @@
mConnection.scheduleWriteSettings();
}
- @Override
- public void setDomainVerificationUserSelection(@NonNull UUID domainSetId,
- @NonNull Set<String> domains, boolean enabled)
- throws InvalidDomainSetException, NameNotFoundException {
- setDomainVerificationUserSelection(domainSetId, domains, enabled,
- mConnection.getCallingUserId());
- }
-
public void setDomainVerificationUserSelection(@NonNull UUID domainSetId,
@NonNull Set<String> domains, boolean enabled, @UserIdInt int userId)
throws InvalidDomainSetException, NameNotFoundException {
@@ -500,7 +484,8 @@
DomainVerificationPkgState pkgState = getAndValidateAttachedLocked(domainSetId, domains,
false /* forAutoVerify */, callingUid, userId);
- DomainVerificationUserState userState = pkgState.getOrCreateUserSelectionState(userId);
+ DomainVerificationInternalUserState userState =
+ pkgState.getOrCreateUserState(userId);
// Disable other packages if approving this one. Note that this check is only done for
// enabling. This allows an escape hatch in case multiple packages somehow get selected.
@@ -540,8 +525,8 @@
continue;
}
- DomainVerificationUserState approvedUserState =
- approvedPkgState.getUserSelectionState(userId);
+ DomainVerificationInternalUserState approvedUserState =
+ approvedPkgState.getUserState(userId);
if (approvedUserState == null) {
continue;
}
@@ -623,8 +608,8 @@
if (userId == UserHandle.USER_ALL) {
for (int aUserId : mConnection.getAllUserIds()) {
- DomainVerificationUserState userState =
- pkgState.getOrCreateUserSelectionState(aUserId);
+ DomainVerificationInternalUserState userState =
+ pkgState.getOrCreateUserState(aUserId);
if (enabled) {
userState.addHosts(domains);
} else {
@@ -632,7 +617,8 @@
}
}
} else {
- DomainVerificationUserState userState = pkgState.getOrCreateUserSelectionState(userId);
+ DomainVerificationInternalUserState userState =
+ pkgState.getOrCreateUserState(userId);
if (enabled) {
userState.addHosts(domains);
} else {
@@ -643,17 +629,9 @@
@Nullable
@Override
- public DomainVerificationUserSelection getDomainVerificationUserSelection(
- @NonNull String packageName) throws NameNotFoundException {
- return getDomainVerificationUserSelection(packageName,
- mConnection.getCallingUserId());
- }
-
- @Nullable
- @Override
- public DomainVerificationUserSelection getDomainVerificationUserSelection(
+ public DomainVerificationUserState getDomainVerificationUserState(
@NonNull String packageName, @UserIdInt int userId) throws NameNotFoundException {
- if (!mEnforcer.assertApprovedUserSelector(mConnection.getCallingUid(),
+ if (!mEnforcer.assertApprovedUserStateQuerent(mConnection.getCallingUid(),
mConnection.getCallingUserId(), packageName, userId)) {
throw DomainVerificationUtils.throwPackageUnavailable(packageName);
}
@@ -673,7 +651,7 @@
Map<String, Integer> domains = new ArrayMap<>(webDomainsSize);
ArrayMap<String, Integer> stateMap = pkgState.getStateMap();
- DomainVerificationUserState userState = pkgState.getUserSelectionState(userId);
+ DomainVerificationInternalUserState userState = pkgState.getUserState(userId);
Set<String> enabledHosts = userState == null ? emptySet() : userState.getEnabledHosts();
for (int index = 0; index < webDomainsSize; index++) {
@@ -682,11 +660,11 @@
int domainState;
if (state != null && DomainVerificationManager.isStateVerified(state)) {
- domainState = DomainVerificationUserSelection.DOMAIN_STATE_VERIFIED;
+ domainState = DomainVerificationUserState.DOMAIN_STATE_VERIFIED;
} else if (enabledHosts.contains(host)) {
- domainState = DomainVerificationUserSelection.DOMAIN_STATE_SELECTED;
+ domainState = DomainVerificationUserState.DOMAIN_STATE_SELECTED;
} else {
- domainState = DomainVerificationUserSelection.DOMAIN_STATE_NONE;
+ domainState = DomainVerificationUserState.DOMAIN_STATE_NONE;
}
domains.put(host, domainState);
@@ -694,17 +672,11 @@
boolean linkHandlingAllowed = userState == null || userState.isLinkHandlingAllowed();
- return new DomainVerificationUserSelection(pkgState.getId(), packageName,
+ return new DomainVerificationUserState(pkgState.getId(), packageName,
UserHandle.of(userId), linkHandlingAllowed, domains);
}
}
- @NonNull
- @Override
- public List<DomainOwner> getOwnersForDomain(@NonNull String domain) {
- return getOwnersForDomain(domain, mConnection.getCallingUserId());
- }
-
public List<DomainOwner> getOwnersForDomain(@NonNull String domain, @UserIdInt int userId) {
mEnforcer.assertOwnerQuerent(mConnection.getCallingUid(), mConnection.getCallingUserId(),
userId);
@@ -795,7 +767,7 @@
AndroidPackage newPkg = newPkgSetting.getPkg();
ArrayMap<String, Integer> newStateMap = new ArrayMap<>();
- SparseArray<DomainVerificationUserState> newUserStates = new SparseArray<>();
+ SparseArray<DomainVerificationInternalUserState> newUserStates = new SparseArray<>();
if (oldPkgState == null || oldPkg == null || newPkg == null) {
// Should be impossible, but to be safe, continue with a new blank state instead
@@ -838,21 +810,22 @@
}
}
- SparseArray<DomainVerificationUserState> oldUserStates =
- oldPkgState.getUserSelectionStates();
+ SparseArray<DomainVerificationInternalUserState> oldUserStates =
+ oldPkgState.getUserStates();
int oldUserStatesSize = oldUserStates.size();
if (oldUserStatesSize > 0) {
ArraySet<String> newWebDomains = mCollector.collectValidAutoVerifyDomains(newPkg);
for (int oldUserStatesIndex = 0; oldUserStatesIndex < oldUserStatesSize;
oldUserStatesIndex++) {
int userId = oldUserStates.keyAt(oldUserStatesIndex);
- DomainVerificationUserState oldUserState = oldUserStates.valueAt(
+ DomainVerificationInternalUserState oldUserState = oldUserStates.valueAt(
oldUserStatesIndex);
ArraySet<String> oldEnabledHosts = oldUserState.getEnabledHosts();
ArraySet<String> newEnabledHosts = new ArraySet<>(oldEnabledHosts);
newEnabledHosts.retainAll(newWebDomains);
- DomainVerificationUserState newUserState = new DomainVerificationUserState(
- userId, newEnabledHosts, oldUserState.isLinkHandlingAllowed());
+ DomainVerificationInternalUserState newUserState =
+ new DomainVerificationInternalUserState(userId, newEnabledHosts,
+ oldUserState.isLinkHandlingAllowed());
newUserStates.put(userId, newUserState);
}
}
@@ -926,7 +899,7 @@
webDomains = mCollector.collectAllWebDomains(pkg);
}
- pkgState.getOrCreateUserSelectionState(userId).addHosts(webDomains);
+ pkgState.getOrCreateUserState(userId).addHosts(webDomains);
}
}
@@ -1295,7 +1268,7 @@
}
@Override
- public void clearUserSelections(@Nullable List<String> packageNames, @UserIdInt int userId) {
+ public void clearUserStates(@Nullable List<String> packageNames, @UserIdInt int userId) {
mEnforcer.assertInternal(mConnection.getCallingUid());
synchronized (mLock) {
if (packageNames == null) {
@@ -1545,7 +1518,7 @@
return APPROVAL_LEVEL_NONE;
}
- DomainVerificationUserState userState = pkgState.getUserSelectionState(userId);
+ DomainVerificationInternalUserState userState = pkgState.getUserState(userId);
if (userState != null && !userState.isLinkHandlingAllowed()) {
if (DEBUG_APPROVAL) {
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java
index a8e937c..f3d1dbb 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java
@@ -29,9 +29,9 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
import com.android.server.pm.verify.domain.models.DomainVerificationStateMap;
-import com.android.server.pm.verify.domain.models.DomainVerificationUserState;
import org.xmlpull.v1.XmlPullParserException;
@@ -216,21 +216,22 @@
}
}
- SparseArray<DomainVerificationUserState> oldSelectionStates =
- oldState.getUserSelectionStates();
+ SparseArray<DomainVerificationInternalUserState> oldSelectionStates =
+ oldState.getUserStates();
- SparseArray<DomainVerificationUserState> newSelectionStates =
- newState.getUserSelectionStates();
+ SparseArray<DomainVerificationInternalUserState> newSelectionStates =
+ newState.getUserStates();
- DomainVerificationUserState newUserState = newSelectionStates.get(UserHandle.USER_SYSTEM);
+ DomainVerificationInternalUserState newUserState =
+ newSelectionStates.get(UserHandle.USER_SYSTEM);
if (newUserState != null) {
ArraySet<String> newEnabledHosts = newUserState.getEnabledHosts();
- DomainVerificationUserState oldUserState =
+ DomainVerificationInternalUserState oldUserState =
oldSelectionStates.get(UserHandle.USER_SYSTEM);
boolean linkHandlingAllowed = newUserState.isLinkHandlingAllowed();
if (oldUserState == null) {
- oldUserState = new DomainVerificationUserState(UserHandle.USER_SYSTEM,
+ oldUserState = new DomainVerificationInternalUserState(UserHandle.USER_SYSTEM,
newEnabledHosts, linkHandlingAllowed);
oldSelectionStates.put(UserHandle.USER_SYSTEM, oldUserState);
} else {
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationShell.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationShell.java
index d083d11..94767f5 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationShell.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationShell.java
@@ -24,7 +24,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.verify.domain.DomainVerificationManager;
import android.content.pm.verify.domain.DomainVerificationState;
-import android.content.pm.verify.domain.DomainVerificationUserSelection;
+import android.content.pm.verify.domain.DomainVerificationUserState;
import android.os.Binder;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -118,7 +118,7 @@
case "set-app-links":
return runSetAppLinks(commandHandler);
case "set-app-links-user-selection":
- return runSetAppLinksUserSelection(commandHandler);
+ return runSetAppLinksUserState(commandHandler);
case "set-app-links-allowed":
return runSetAppLinksAllowed(commandHandler);
}
@@ -193,7 +193,7 @@
}
// pm set-app-links-user-selection --user <USER_ID> [--package <PACKAGE>] <ENABLED> <DOMAINS>...
- private boolean runSetAppLinksUserSelection(@NonNull BasicShellCommandHandler commandHandler) {
+ private boolean runSetAppLinksUserState(@NonNull BasicShellCommandHandler commandHandler) {
Integer userId = null;
String packageName = null;
@@ -224,7 +224,7 @@
return false;
}
- userId = translateUserId(userId, "runSetAppLinksUserSelection");
+ userId = translateUserId(userId, "runSetAppLinksUserState");
String enabledString = commandHandler.getNextArgRequired();
@@ -326,7 +326,7 @@
}
if (userId != null) {
- mCallback.clearUserSelections(packageNames, userId);
+ mCallback.clearUserStates(packageNames, userId);
} else {
mCallback.clearDomainVerificationState(packageNames);
}
@@ -457,10 +457,10 @@
throws PackageManager.NameNotFoundException;
/**
- * @see DomainVerificationManager#getDomainVerificationUserSelection(String)
+ * @see DomainVerificationManager#getDomainVerificationUserState(String)
*/
@Nullable
- DomainVerificationUserSelection getDomainVerificationUserSelection(
+ DomainVerificationUserState getDomainVerificationUserState(
@NonNull String packageName, @UserIdInt int userId)
throws PackageManager.NameNotFoundException;
@@ -486,7 +486,7 @@
* Reset all the user selections for the given package names, or all package names if null
* is provided.
*/
- void clearUserSelections(@Nullable List<String> packageNames, @UserIdInt int userId);
+ void clearUserStates(@Nullable List<String> packageNames, @UserIdInt int userId);
/**
* Broadcast a verification request for the given package names, or all package names if
diff --git a/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java b/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationInternalUserState.java
similarity index 74%
rename from services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java
rename to services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationInternalUserState.java
index 8fbb33a..aa7407c 100644
--- a/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java
+++ b/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationInternalUserState.java
@@ -29,7 +29,7 @@
* when a web URL Intent is sent and the application is the highest priority for that domain.
*/
@DataClass(genSetters = true, genEqualsHashCode = true, genToString = true, genBuilder = false)
-public class DomainVerificationUserState {
+public class DomainVerificationInternalUserState {
@UserIdInt
private final int mUserId;
@@ -43,32 +43,32 @@
*/
private boolean mLinkHandlingAllowed = true;
- public DomainVerificationUserState(@UserIdInt int userId) {
+ public DomainVerificationInternalUserState(@UserIdInt int userId) {
mUserId = userId;
mEnabledHosts = new ArraySet<>();
}
- public DomainVerificationUserState addHosts(@NonNull ArraySet<String> newHosts) {
+ public DomainVerificationInternalUserState addHosts(@NonNull ArraySet<String> newHosts) {
mEnabledHosts.addAll(newHosts);
return this;
}
- public DomainVerificationUserState addHosts(@NonNull Set<String> newHosts) {
+ public DomainVerificationInternalUserState addHosts(@NonNull Set<String> newHosts) {
mEnabledHosts.addAll(newHosts);
return this;
}
- public DomainVerificationUserState removeHost(String host) {
+ public DomainVerificationInternalUserState removeHost(String host) {
mEnabledHosts.remove(host);
return this;
}
- public DomainVerificationUserState removeHosts(@NonNull ArraySet<String> newHosts) {
+ public DomainVerificationInternalUserState removeHosts(@NonNull ArraySet<String> newHosts) {
mEnabledHosts.removeAll(newHosts);
return this;
}
- public DomainVerificationUserState removeHosts(@NonNull Set<String> newHosts) {
+ public DomainVerificationInternalUserState removeHosts(@NonNull Set<String> newHosts) {
mEnabledHosts.removeAll(newHosts);
return this;
}
@@ -81,8 +81,7 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm
- // /verify/domain/models/DomainVerificationUserState.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationInternalUserState.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -90,7 +89,7 @@
/**
- * Creates a new DomainVerificationUserState.
+ * Creates a new DomainVerificationInternalUserState.
*
* @param enabledHosts
* List of domains which have been enabled by the user. *
@@ -98,7 +97,7 @@
* Whether to allow this package to automatically open links by auto verification.
*/
@DataClass.Generated.Member
- public DomainVerificationUserState(
+ public DomainVerificationInternalUserState(
@UserIdInt int userId,
@NonNull ArraySet<String> enabledHosts,
boolean linkHandlingAllowed) {
@@ -138,7 +137,7 @@
* Whether to allow this package to automatically open links by auto verification.
*/
@DataClass.Generated.Member
- public @NonNull DomainVerificationUserState setLinkHandlingAllowed( boolean value) {
+ public @NonNull DomainVerificationInternalUserState setLinkHandlingAllowed( boolean value) {
mLinkHandlingAllowed = value;
return this;
}
@@ -149,7 +148,7 @@
// You can override field toString logic by defining methods like:
// String fieldNameToString() { ... }
- return "DomainVerificationUserState { " +
+ return "DomainVerificationInternalUserState { " +
"userId = " + mUserId + ", " +
"enabledHosts = " + mEnabledHosts + ", " +
"linkHandlingAllowed = " + mLinkHandlingAllowed +
@@ -160,13 +159,13 @@
@DataClass.Generated.Member
public boolean equals(@android.annotation.Nullable Object o) {
// You can override field equality logic by defining either of the methods like:
- // boolean fieldNameEquals(DomainVerificationUserState other) { ... }
+ // boolean fieldNameEquals(DomainVerificationInternalUserState other) { ... }
// boolean fieldNameEquals(FieldType otherValue) { ... }
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
@SuppressWarnings("unchecked")
- DomainVerificationUserState that = (DomainVerificationUserState) o;
+ DomainVerificationInternalUserState that = (DomainVerificationInternalUserState) o;
//noinspection PointlessBooleanExpression
return true
&& mUserId == that.mUserId
@@ -188,10 +187,10 @@
}
@DataClass.Generated(
- time = 1612894390039L,
+ time = 1614714563905L,
codegenVersion = "1.0.22",
- sourceFile = "frameworks/base/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationUserState.java",
- inputSignatures = "private final @android.annotation.UserIdInt int mUserId\nprivate final @android.annotation.NonNull android.util.ArraySet<java.lang.String> mEnabledHosts\nprivate boolean mLinkHandlingAllowed\npublic com.android.server.pm.verify.domain.models.DomainVerificationUserState addHosts(android.util.ArraySet<java.lang.String>)\npublic com.android.server.pm.verify.domain.models.DomainVerificationUserState addHosts(java.util.Set<java.lang.String>)\npublic com.android.server.pm.verify.domain.models.DomainVerificationUserState removeHosts(android.util.ArraySet<java.lang.String>)\npublic com.android.server.pm.verify.domain.models.DomainVerificationUserState removeHosts(java.util.Set<java.lang.String>)\nclass DomainVerificationUserState extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genSetters=true, genEqualsHashCode=true, genToString=true, genBuilder=false)")
+ sourceFile = "frameworks/base/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationInternalUserState.java",
+ inputSignatures = "private final @android.annotation.UserIdInt int mUserId\nprivate final @android.annotation.NonNull android.util.ArraySet<java.lang.String> mEnabledHosts\nprivate boolean mLinkHandlingAllowed\npublic com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState addHosts(android.util.ArraySet<java.lang.String>)\npublic com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState addHosts(java.util.Set<java.lang.String>)\npublic com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState removeHost(java.lang.String)\npublic com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState removeHosts(android.util.ArraySet<java.lang.String>)\npublic com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState removeHosts(java.util.Set<java.lang.String>)\nclass DomainVerificationInternalUserState extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genSetters=true, genEqualsHashCode=true, genToString=true, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationPkgState.java b/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationPkgState.java
index 48099aa..a089a60 100644
--- a/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationPkgState.java
+++ b/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationPkgState.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.content.pm.verify.domain.DomainVerificationManager;
import android.content.pm.verify.domain.DomainVerificationState;
import android.util.ArrayMap;
import android.util.SparseArray;
@@ -44,9 +43,9 @@
/**
* Whether or not the package declares any autoVerify domains. This is separate from an empty
- * check on the map itself, because an empty map means no response recorded, not necessarily no
- * domains declared. When this is false, {@link #mStateMap} will be empty, but
- * {@link #mUserSelectionStates} may contain any domains the user has explicitly chosen to
+ * check on the map itself, because an empty map means no response recorded, not necessarily
+ * no domains declared. When this is false, {@link #mStateMap} will be empty, but
+ * {@link #mUserStates} may contain any domains the user has explicitly chosen to
* allow this package to open, which may or may not be marked autoVerify.
*/
private final boolean mHasAutoVerifyDomains;
@@ -62,7 +61,7 @@
private final ArrayMap<String, Integer> mStateMap;
@NonNull
- private final SparseArray<DomainVerificationUserState> mUserSelectionStates;
+ private final SparseArray<DomainVerificationInternalUserState> mUserStates;
public DomainVerificationPkgState(@NonNull String packageName, @NonNull UUID id,
boolean hasAutoVerifyDomains) {
@@ -70,16 +69,17 @@
}
@Nullable
- public DomainVerificationUserState getUserSelectionState(@UserIdInt int userId) {
- return mUserSelectionStates.get(userId);
+ public DomainVerificationInternalUserState getUserState(@UserIdInt int userId) {
+ return mUserStates.get(userId);
}
@Nullable
- public DomainVerificationUserState getOrCreateUserSelectionState(@UserIdInt int userId) {
- DomainVerificationUserState userState = mUserSelectionStates.get(userId);
+ public DomainVerificationInternalUserState getOrCreateUserState(
+ @UserIdInt int userId) {
+ DomainVerificationInternalUserState userState = mUserStates.get(userId);
if (userState == null) {
- userState = new DomainVerificationUserState(userId);
- mUserSelectionStates.put(userId, userState);
+ userState = new DomainVerificationInternalUserState(userId);
+ mUserStates.put(userId, userState);
}
return userState;
}
@@ -89,20 +89,20 @@
}
public void removeUser(@UserIdInt int userId) {
- mUserSelectionStates.remove(userId);
+ mUserStates.remove(userId);
}
public void removeAllUsers() {
- mUserSelectionStates.clear();
+ mUserStates.clear();
}
- private int userSelectionStatesHashCode() {
- return mUserSelectionStates.contentHashCode();
+ private int userStatesHashCode() {
+ return mUserStates.contentHashCode();
}
- private boolean userSelectionStatesEquals(
- @NonNull SparseArray<DomainVerificationUserState> other) {
- return mUserSelectionStates.contentEquals(other);
+ private boolean userStatesEquals(
+ @NonNull SparseArray<DomainVerificationInternalUserState> other) {
+ return mUserStates.contentEquals(other);
}
@@ -113,7 +113,7 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/domain/verify/models/DomainVerificationPkgState.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationPkgState.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -123,9 +123,15 @@
/**
* Creates a new DomainVerificationPkgState.
*
+ * @param hasAutoVerifyDomains
+ * Whether or not the package declares any autoVerify domains. This is separate from an empty
+ * check on the map itself, because an empty map means no response recorded, not necessarily
+ * no domains declared. When this is false, {@link #mStateMap} will be empty, but
+ * {@link #mUserStates} may contain any domains the user has explicitly chosen to
+ * allow this package to open, which may or may not be marked autoVerify.
* @param stateMap
* Map of domains to state integers. Only domains that are not set to the default value of
- * {@link DomainVerificationManager#STATE_NO_RESPONSE} are included.
+ * {@link DomainVerificationState#STATE_NO_RESPONSE} are included.
*
* TODO(b/159952358): Hide the state map entirely from the caller, to allow optimizations,
* such as storing no state when the package is marked as a linked app in SystemConfig.
@@ -136,7 +142,7 @@
@NonNull UUID id,
boolean hasAutoVerifyDomains,
@NonNull ArrayMap<String,Integer> stateMap,
- @NonNull SparseArray<DomainVerificationUserState> userSelectionStates) {
+ @NonNull SparseArray<DomainVerificationInternalUserState> userStates) {
this.mPackageName = packageName;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mPackageName);
@@ -147,9 +153,9 @@
this.mStateMap = stateMap;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mStateMap);
- this.mUserSelectionStates = userSelectionStates;
+ this.mUserStates = userStates;
com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mUserSelectionStates);
+ NonNull.class, null, mUserStates);
// onConstructed(); // You can define this method to get a callback
}
@@ -164,6 +170,13 @@
return mId;
}
+ /**
+ * Whether or not the package declares any autoVerify domains. This is separate from an empty
+ * check on the map itself, because an empty map means no response recorded, not necessarily
+ * no domains declared. When this is false, {@link #mStateMap} will be empty, but
+ * {@link #mUserStates} may contain any domains the user has explicitly chosen to
+ * allow this package to open, which may or may not be marked autoVerify.
+ */
@DataClass.Generated.Member
public boolean isHasAutoVerifyDomains() {
return mHasAutoVerifyDomains;
@@ -171,7 +184,7 @@
/**
* Map of domains to state integers. Only domains that are not set to the default value of
- * {@link DomainVerificationManager#STATE_NO_RESPONSE} are included.
+ * {@link DomainVerificationState#STATE_NO_RESPONSE} are included.
*
* TODO(b/159952358): Hide the state map entirely from the caller, to allow optimizations,
* such as storing no state when the package is marked as a linked app in SystemConfig.
@@ -182,8 +195,8 @@
}
@DataClass.Generated.Member
- public @NonNull SparseArray<DomainVerificationUserState> getUserSelectionStates() {
- return mUserSelectionStates;
+ public @NonNull SparseArray<DomainVerificationInternalUserState> getUserStates() {
+ return mUserStates;
}
@Override
@@ -197,7 +210,7 @@
"id = " + mId + ", " +
"hasAutoVerifyDomains = " + mHasAutoVerifyDomains + ", " +
"stateMap = " + mStateMap + ", " +
- "userSelectionStates = " + mUserSelectionStates +
+ "userStates = " + mUserStates +
" }";
}
@@ -218,7 +231,7 @@
&& Objects.equals(mId, that.mId)
&& mHasAutoVerifyDomains == that.mHasAutoVerifyDomains
&& Objects.equals(mStateMap, that.mStateMap)
- && userSelectionStatesEquals(that.mUserSelectionStates);
+ && userStatesEquals(that.mUserStates);
}
@Override
@@ -232,15 +245,15 @@
_hash = 31 * _hash + Objects.hashCode(mId);
_hash = 31 * _hash + Boolean.hashCode(mHasAutoVerifyDomains);
_hash = 31 * _hash + Objects.hashCode(mStateMap);
- _hash = 31 * _hash + userSelectionStatesHashCode();
+ _hash = 31 * _hash + userStatesHashCode();
return _hash;
}
@DataClass.Generated(
- time = 1608234185474L,
+ time = 1614818362549L,
codegenVersion = "1.0.22",
- sourceFile = "frameworks/base/services/core/java/com/android/server/pm/domain/verify/models/DomainVerificationPkgState.java",
- inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate @android.annotation.NonNull java.util.UUID mId\nprivate final boolean mHasAutoVerifyDomains\nprivate final @android.annotation.NonNull android.util.ArrayMap<java.lang.String,java.lang.Integer> mStateMap\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.verify.domain.models.DomainVerificationUserState> mUserSelectionStates\npublic @android.annotation.Nullable com.android.server.pm.verify.domain.models.DomainVerificationUserState getUserSelectionState(int)\npublic @android.annotation.Nullable com.android.server.pm.verify.domain.models.DomainVerificationUserState getOrCreateUserSelectionState(int)\npublic void setId(java.util.UUID)\npublic void removeUser(int)\npublic void removeAllUsers()\nprivate int userSelectionStatesHashCode()\nprivate boolean userSelectionStatesEquals(android.util.SparseArray<com.android.server.pm.verify.domain.models.DomainVerificationUserState>)\nclass DomainVerificationPkgState extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true)")
+ sourceFile = "frameworks/base/services/core/java/com/android/server/pm/verify/domain/models/DomainVerificationPkgState.java",
+ inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate @android.annotation.NonNull java.util.UUID mId\nprivate final boolean mHasAutoVerifyDomains\nprivate final @android.annotation.NonNull android.util.ArrayMap<java.lang.String,java.lang.Integer> mStateMap\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState> mUserStates\npublic @android.annotation.Nullable com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState getUserState(int)\npublic @android.annotation.Nullable com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState getOrCreateUserState(int)\npublic void setId(java.util.UUID)\npublic void removeUser(int)\npublic void removeAllUsers()\nprivate int userStatesHashCode()\nprivate boolean userStatesEquals(android.util.SparseArray<com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState>)\nclass DomainVerificationPkgState extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/policy/KeyCombinationManager.java b/services/core/java/com/android/server/policy/KeyCombinationManager.java
index 84ac124..7f55723 100644
--- a/services/core/java/com/android/server/policy/KeyCombinationManager.java
+++ b/services/core/java/com/android/server/policy/KeyCombinationManager.java
@@ -102,9 +102,11 @@
}
/**
- * Check if the key event could be triggered by combine key rule before dispatching to a window.
+ * Check if the key event could be intercepted by combination key rule before it is dispatched
+ * to a window.
+ * Return true if any active rule could be triggered by the key event, otherwise false.
*/
- void interceptKey(KeyEvent event, boolean interactive) {
+ boolean interceptKey(KeyEvent event, boolean interactive) {
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final int keyCode = event.getKeyCode();
final int count = mActiveRules.size();
@@ -117,9 +119,9 @@
// exceed time from first key down.
forAllRules(mActiveRules, (rule)-> rule.cancel());
mActiveRules.clear();
- return;
+ return false;
} else if (count == 0) { // has some key down but no active rule exist.
- return;
+ return false;
}
}
@@ -127,7 +129,7 @@
mDownTimes.put(keyCode, eventTime);
} else {
// ignore old key, maybe a repeat key.
- return;
+ return false;
}
if (mDownTimes.size() == 1) {
@@ -141,7 +143,7 @@
} else {
// Ignore if rule already triggered.
if (mTriggeredRule != null) {
- return;
+ return true;
}
// check if second key can trigger rule, or remove the non-match rule.
@@ -156,6 +158,7 @@
mActiveRules.clear();
if (mTriggeredRule != null) {
mActiveRules.add(mTriggeredRule);
+ return true;
}
}
} else {
@@ -168,6 +171,7 @@
}
}
}
+ return false;
}
/**
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index bce218f..047e3b3 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -73,6 +73,8 @@
import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_KEYCHORD_DELAY;
+import static com.android.server.policy.SingleKeyGestureDetector.KEY_LONGPRESS;
+import static com.android.server.policy.SingleKeyGestureDetector.KEY_VERYLONGPRESS;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
@@ -430,7 +432,6 @@
volatile boolean mPowerKeyHandled;
volatile boolean mBackKeyHandled;
volatile boolean mBeganFromNonInteractive;
- volatile int mPowerKeyPressCounter;
volatile boolean mEndCallKeyHandled;
volatile boolean mCameraGestureTriggeredDuringGoingToSleep;
volatile boolean mGoingToSleep;
@@ -471,7 +472,6 @@
boolean mHasSoftInput = false;
boolean mHapticTextHandleEnabled;
boolean mUseTvRouting;
- int mVeryLongPressTimeout;
boolean mAllowStartActivityForLongPressOnPowerDuringSetup;
MetricsLogger mLogger;
boolean mWakeOnDpadKeyPress;
@@ -567,14 +567,13 @@
private final com.android.internal.policy.LogDecelerateInterpolator mLogDecelerateInterpolator
= new LogDecelerateInterpolator(100, 0);
- private final MutableBoolean mTmpBoolean = new MutableBoolean(false);
-
private boolean mPerDisplayFocusEnabled = false;
private volatile int mTopFocusedDisplayId = INVALID_DISPLAY;
private int mPowerButtonSuppressionDelayMillis = POWER_BUTTON_SUPPRESSION_DELAY_DEFAULT_MILLIS;
private KeyCombinationManager mKeyCombinationManager;
+ private SingleKeyGestureDetector mSingleKeyGestureDetector;
private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4;
@@ -585,10 +584,7 @@
private static final int MSG_DISPATCH_SHOW_GLOBAL_ACTIONS = 10;
private static final int MSG_HIDE_BOOT_MESSAGE = 11;
private static final int MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK = 12;
- private static final int MSG_POWER_DELAYED_PRESS = 13;
- private static final int MSG_POWER_LONG_PRESS = 14;
private static final int MSG_SHOW_PICTURE_IN_PICTURE_MENU = 15;
- private static final int MSG_BACK_LONG_PRESS = 16;
private static final int MSG_ACCESSIBILITY_SHORTCUT = 17;
private static final int MSG_BUGREPORT_TV = 18;
private static final int MSG_ACCESSIBILITY_TV = 19;
@@ -596,8 +592,7 @@
private static final int MSG_SYSTEM_KEY_PRESS = 21;
private static final int MSG_HANDLE_ALL_APPS = 22;
private static final int MSG_LAUNCH_ASSIST = 23;
- private static final int MSG_POWER_VERY_LONG_PRESS = 25;
- private static final int MSG_RINGER_TOGGLE_CHORD = 26;
+ private static final int MSG_RINGER_TOGGLE_CHORD = 24;
private class PolicyHandler extends Handler {
@Override
@@ -638,22 +633,9 @@
case MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK:
launchVoiceAssistWithWakeLock();
break;
- case MSG_POWER_DELAYED_PRESS:
- powerPress((Long) msg.obj, msg.arg1 != 0, msg.arg2);
- finishPowerKeyPress();
- break;
- case MSG_POWER_LONG_PRESS:
- powerLongPress((Long) msg.obj /* eventTime */);
- break;
- case MSG_POWER_VERY_LONG_PRESS:
- powerVeryLongPress();
- break;
case MSG_SHOW_PICTURE_IN_PICTURE_MENU:
showPictureInPictureMenuInternal();
break;
- case MSG_BACK_LONG_PRESS:
- backLongPress();
- break;
case MSG_ACCESSIBILITY_SHORTCUT:
accessibilityShortcutActivated();
break;
@@ -764,13 +746,6 @@
}
};
- private Runnable mPossibleVeryLongPressReboot = new Runnable() {
- @Override
- public void run() {
- mActivityManagerInternal.prepareForPossibleShutdown();
- }
- };
-
private void handleRingerChordGesture() {
if (mRingerToggleChord == VOLUME_HUSH_OFF) {
return;
@@ -810,28 +785,13 @@
}
}
- private void interceptBackKeyDown() {
- mLogger.count("key_back_down", 1);
- // Reset back key state for long press
- mBackKeyHandled = false;
-
- if (hasLongPressOnBackBehavior()) {
- Message msg = mHandler.obtainMessage(MSG_BACK_LONG_PRESS);
- msg.setAsynchronous(true);
- mHandler.sendMessageDelayed(msg,
- ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
- }
- }
// returns true if the key was handled and should not be passed to the user
- private boolean interceptBackKeyUp(KeyEvent event) {
- mLogger.count("key_back_up", 1);
+ private boolean backKeyPress() {
+ mLogger.count("key_back_press", 1);
// Cache handled state
boolean handled = mBackKeyHandled;
- // Reset back long press state
- cancelPendingBackKeyAction();
-
if (mHasFeatureWatch) {
TelecomManager telecomManager = getTelecommService();
@@ -853,10 +813,9 @@
}
}
- if (mAutofillManagerInternal != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+ if (mAutofillManagerInternal != null) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_BACK_KEY_TO_AUTOFILL));
}
-
return handled;
}
@@ -866,11 +825,6 @@
mPowerKeyWakeLock.acquire();
}
- // Cancel multi-press detection timeout.
- if (mPowerKeyPressCounter != 0) {
- mHandler.removeMessages(MSG_POWER_DELAYED_PRESS);
- }
-
mWindowManagerFuncs.onPowerKeyDown(interactive);
// Stop ringing or end call if configured to do so when power is pressed.
@@ -892,71 +846,20 @@
final boolean handledByPowerManager = mPowerManagerInternal.interceptPowerKeyDown(event);
- GestureLauncherService gestureService = LocalServices.getService(
- GestureLauncherService.class);
- boolean gesturedServiceIntercepted = false;
- if (gestureService != null) {
- gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive,
- mTmpBoolean);
- if (mTmpBoolean.value && mRequestedOrGoingToSleep) {
- mCameraGestureTriggeredDuringGoingToSleep = true;
- }
- }
-
// Inform the StatusBar; but do not allow it to consume the event.
sendSystemKeyToStatusBarAsync(event.getKeyCode());
- schedulePossibleVeryLongPressReboot();
-
// If the power key has still not yet been handled, then detect short
// press, long press, or multi press and decide what to do.
- mPowerKeyHandled = hungUp || gesturedServiceIntercepted
+ mPowerKeyHandled = mPowerKeyHandled || hungUp
|| handledByPowerManager || mKeyCombinationManager.isPowerKeyIntercepted();
if (!mPowerKeyHandled) {
- if (interactive) {
- // When interactive, we're already awake.
- // Wait for a long press or for the button to be released to decide what to do.
- if (hasLongPressOnPowerBehavior()) {
- if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
- powerLongPress(event.getEventTime());
- } else {
- Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS,
- event.getEventTime());
- msg.setAsynchronous(true);
- mHandler.sendMessageDelayed(msg,
- ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
-
- if (hasVeryLongPressOnPowerBehavior()) {
- Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
- longMsg.setAsynchronous(true);
- mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
- }
- }
- }
- } else {
+ if (!interactive) {
wakeUpFromPowerKey(event.getDownTime());
-
if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
- if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
- powerLongPress(event.getEventTime());
- } else {
- Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS,
- event.getEventTime());
- msg.setAsynchronous(true);
- mHandler.sendMessageDelayed(msg,
- ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
-
- if (hasVeryLongPressOnPowerBehavior()) {
- Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS);
- longMsg.setAsynchronous(true);
- mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout);
- }
- }
-
mBeganFromNonInteractive = true;
} else {
final int maxCount = getMaxMultiPressPowerCount();
-
if (maxCount <= 1) {
mPowerKeyHandled = true;
} else {
@@ -964,68 +867,37 @@
}
}
}
+ } else {
+ // handled by another power key policy.
+ if (!mSingleKeyGestureDetector.isKeyIntercepted(KEYCODE_POWER)) {
+ mSingleKeyGestureDetector.reset();
+ }
}
}
private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
final boolean handled = canceled || mPowerKeyHandled;
- cancelPendingPowerKeyAction();
if (!handled) {
if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) == 0) {
// Abort possibly stuck animations only when power key up without long press case.
mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe);
}
-
- // Figure out how to handle the key now that it has been released.
- mPowerKeyPressCounter += 1;
-
- final int maxCount = getMaxMultiPressPowerCount();
- final long eventTime = event.getDownTime();
- if (mPowerKeyPressCounter < maxCount) {
- // This could be a multi-press. Wait a little bit longer to confirm.
- // Continue holding the wake lock.
- Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS,
- interactive ? 1 : 0, mPowerKeyPressCounter, eventTime);
- msg.setAsynchronous(true);
- mHandler.sendMessageDelayed(msg, ViewConfiguration.getMultiPressTimeout());
- return;
- }
-
- // No other actions. Handle it immediately.
- powerPress(eventTime, interactive, mPowerKeyPressCounter);
+ } else {
+ // handled by single key or another power key policy.
+ mSingleKeyGestureDetector.reset();
+ finishPowerKeyPress();
}
-
- // Done. Reset our state.
- finishPowerKeyPress();
}
private void finishPowerKeyPress() {
mBeganFromNonInteractive = false;
- mPowerKeyPressCounter = 0;
+ mPowerKeyHandled = false;
if (mPowerKeyWakeLock.isHeld()) {
mPowerKeyWakeLock.release();
}
}
- private void cancelPendingPowerKeyAction() {
- if (!mPowerKeyHandled) {
- mPowerKeyHandled = true;
- mHandler.removeMessages(MSG_POWER_LONG_PRESS);
- }
- if (hasVeryLongPressOnPowerBehavior()) {
- mHandler.removeMessages(MSG_POWER_VERY_LONG_PRESS);
- }
- cancelPossibleVeryLongPressReboot();
- }
-
- private void cancelPendingBackKeyAction() {
- if (!mBackKeyHandled) {
- mBackKeyHandled = true;
- mHandler.removeMessages(MSG_BACK_LONG_PRESS);
- }
- }
-
private void powerPress(long eventTime, boolean interactive, int count) {
if (mDefaultDisplayPolicy.isScreenOnEarly() && !mDefaultDisplayPolicy.isScreenOnFully()) {
Slog.i(TAG, "Suppressed redundant power key press while "
@@ -1176,6 +1048,7 @@
private void powerLongPress(long eventTime) {
final int behavior = getResolvedLongPressOnPowerBehavior();
+
switch (behavior) {
case LONG_PRESS_POWER_NOTHING:
break;
@@ -1183,7 +1056,7 @@
mPowerKeyHandled = true;
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
"Power - Long Press - Global Actions");
- showGlobalActionsInternal();
+ showGlobalActions();
break;
case LONG_PRESS_POWER_SHUT_OFF:
case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
@@ -1214,14 +1087,14 @@
private void powerVeryLongPress() {
switch (mVeryLongPressOnPowerBehavior) {
- case VERY_LONG_PRESS_POWER_NOTHING:
- break;
- case VERY_LONG_PRESS_POWER_GLOBAL_ACTIONS:
- mPowerKeyHandled = true;
- performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
- "Power - Very Long Press - Show Global Actions");
- showGlobalActionsInternal();
- break;
+ case VERY_LONG_PRESS_POWER_NOTHING:
+ break;
+ case VERY_LONG_PRESS_POWER_GLOBAL_ACTIONS:
+ mPowerKeyHandled = true;
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
+ "Power - Very Long Press - Show Global Actions");
+ showGlobalActions();
+ break;
}
}
@@ -1814,8 +1687,6 @@
com.android.internal.R.integer.config_triplePressOnPowerBehavior);
mShortPressOnSleepBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_shortPressOnSleepBehavior);
- mVeryLongPressTimeout = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_veryLongPressTimeout);
mAllowStartActivityForLongPressOnPowerDuringSetup = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_allowStartActivityForLongPressOnPowerInSetup);
@@ -1909,6 +1780,7 @@
}
});
initKeyCombinationRules();
+ initSingleKeyGestureRules();
}
private void initKeyCombinationRules() {
@@ -1921,7 +1793,7 @@
new TwoKeysCombinationRule(KEYCODE_VOLUME_DOWN, KEYCODE_POWER) {
@Override
void execute() {
- cancelPendingPowerKeyAction();
+ mPowerKeyHandled = true;
interceptScreenshotChord();
}
@Override
@@ -1956,7 +1828,7 @@
}
@Override
void execute() {
- cancelPendingPowerKeyAction();
+ mPowerKeyHandled = true;
interceptRingerToggleChord();
}
@Override
@@ -1970,7 +1842,7 @@
new TwoKeysCombinationRule(KEYCODE_BACK, KEYCODE_DPAD_DOWN) {
@Override
void execute() {
- cancelPendingBackKeyAction();
+ mBackKeyHandled = true;
interceptAccessibilityGestureTv();
}
@@ -1984,7 +1856,7 @@
new TwoKeysCombinationRule(KEYCODE_DPAD_CENTER, KEYCODE_BACK) {
@Override
void execute() {
- cancelPendingBackKeyAction();
+ mBackKeyHandled = true;
interceptBugreportGestureTv();
}
@@ -1997,6 +1869,84 @@
}
/**
+ * Rule for single power key gesture.
+ */
+ private final class PowerKeyRule extends SingleKeyGestureDetector.SingleKeyRule {
+ PowerKeyRule(int gestures) {
+ super(KEYCODE_POWER, gestures);
+ }
+
+ @Override
+ int getMaxMultiPressCount() {
+ return getMaxMultiPressPowerCount();
+ }
+
+ @Override
+ void onPress(long downTime) {
+ powerPress(downTime, true, 1 /*count*/);
+ finishPowerKeyPress();
+ }
+
+ @Override
+ void onLongPress(long eventTime) {
+ powerLongPress(eventTime);
+ }
+
+ @Override
+ void onVeryLongPress(long eventTime) {
+ mActivityManagerInternal.prepareForPossibleShutdown();
+ powerVeryLongPress();
+ }
+
+ @Override
+ void onMultiPress(long downTime, int count) {
+ powerPress(downTime, true, count);
+ finishPowerKeyPress();
+ }
+ }
+
+ /**
+ * Rule for single back key gesture.
+ */
+ private final class BackKeyRule extends SingleKeyGestureDetector.SingleKeyRule {
+ BackKeyRule(int gestures) {
+ super(KEYCODE_BACK, gestures);
+ }
+
+ @Override
+ int getMaxMultiPressCount() {
+ return 1;
+ }
+
+ @Override
+ void onPress(long downTime) {
+ mBackKeyHandled |= backKeyPress();
+ }
+
+ @Override
+ void onLongPress(long downTime) {
+ backLongPress();
+ }
+ }
+
+ private void initSingleKeyGestureRules() {
+ mSingleKeyGestureDetector = new SingleKeyGestureDetector(mContext);
+
+ int powerKeyGestures = 0;
+ if (hasVeryLongPressOnPowerBehavior()) {
+ powerKeyGestures |= KEY_VERYLONGPRESS;
+ }
+ if (hasLongPressOnPowerBehavior()) {
+ powerKeyGestures |= KEY_LONGPRESS;
+ }
+ mSingleKeyGestureDetector.addRule(new PowerKeyRule(powerKeyGestures));
+
+ if (hasLongPressOnBackBehavior()) {
+ mSingleKeyGestureDetector.addRule(new BackKeyRule(KEY_LONGPRESS));
+ }
+ }
+
+ /**
* Read values from config.xml that may be overridden depending on
* the configuration of the device.
* eg. Disable long press on home goes to recents on sw600dp.
@@ -3427,8 +3377,21 @@
return result;
}
+ // Alternate TV power to power key for Android TV device.
+ final HdmiControlManager hdmiControlManager = getHdmiControlManager();
+ if (keyCode == KeyEvent.KEYCODE_TV_POWER && mHasFeatureLeanback
+ && (hdmiControlManager == null || !hdmiControlManager.shouldHandleTvPowerKey())) {
+ event = KeyEvent.obtain(
+ event.getDownTime(), event.getEventTime(),
+ event.getAction(), KeyEvent.KEYCODE_POWER,
+ event.getRepeatCount(), event.getMetaState(),
+ event.getDeviceId(), event.getScanCode(),
+ event.getFlags(), event.getSource(), event.getDisplayId(), null);
+ return interceptKeyBeforeQueueing(event, policyFlags);
+ }
+
if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
- mKeyCombinationManager.interceptKey(event, interactive);
+ handleKeyGesture(event, interactive);
}
// Enable haptics if down and virtual key without multiple repetitions. If this is a hard
@@ -3443,12 +3406,13 @@
switch (keyCode) {
case KeyEvent.KEYCODE_BACK: {
if (down) {
- interceptBackKeyDown();
+ mBackKeyHandled = false;
} else {
- boolean handled = interceptBackKeyUp(event);
-
+ if (!hasLongPressOnBackBehavior()) {
+ mBackKeyHandled |= backKeyPress();
+ }
// Don't pass back press to app if we've already handled it via long press
- if (handled) {
+ if (mBackKeyHandled) {
result &= ~ACTION_PASS_TO_USER;
}
}
@@ -3560,33 +3524,17 @@
case KeyEvent.KEYCODE_TV_POWER: {
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
- HdmiControlManager hdmiControlManager = getHdmiControlManager();
- if (hdmiControlManager != null && hdmiControlManager.shouldHandleTvPowerKey()) {
- if (down) {
- hdmiControlManager.toggleAndFollowTvPower();
- }
- } else if (mHasFeatureLeanback) {
- KeyEvent fallbackEvent = KeyEvent.obtain(
- event.getDownTime(), event.getEventTime(),
- event.getAction(), KeyEvent.KEYCODE_POWER,
- event.getRepeatCount(), event.getMetaState(),
- event.getDeviceId(), event.getScanCode(),
- event.getFlags(), event.getSource(), event.getDisplayId(), null);
- if (down) {
- interceptPowerKeyDown(fallbackEvent, interactive);
- } else {
- interceptPowerKeyUp(fallbackEvent, interactive, canceled);
- }
+ if (down && hdmiControlManager != null) {
+ hdmiControlManager.toggleAndFollowTvPower();
}
- // Ignore this key for any device that is not connected to a TV via HDMI and
- // not an Android TV device.
break;
}
case KeyEvent.KEYCODE_POWER: {
EventLogTags.writeInterceptPower(
KeyEvent.actionToString(event.getAction()),
- mPowerKeyHandled ? 1 : 0, mPowerKeyPressCounter);
+ mPowerKeyHandled ? 1 : 0,
+ mSingleKeyGestureDetector.getKeyPressCounter(KeyEvent.KEYCODE_POWER));
// Any activity on the power button stops the accessibility shortcut
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
@@ -3767,6 +3715,43 @@
return result;
}
+ private void handleKeyGesture(KeyEvent event, boolean interactive) {
+ if (mKeyCombinationManager.interceptKey(event, interactive)) {
+ // handled by combo keys manager.
+ mSingleKeyGestureDetector.reset();
+ return;
+ }
+
+ if (event.getKeyCode() == KEYCODE_POWER && event.getAction() == KeyEvent.ACTION_DOWN) {
+ mPowerKeyHandled = handleCameraGesture(event, interactive);
+ if (mPowerKeyHandled) {
+ // handled by camera gesture.
+ mSingleKeyGestureDetector.reset();
+ return;
+ }
+ }
+
+ mSingleKeyGestureDetector.interceptKey(event);
+ }
+
+ // The camera gesture will be detected by GestureLauncherService.
+ private boolean handleCameraGesture(KeyEvent event, boolean interactive) {
+ // camera gesture.
+ GestureLauncherService gestureService = LocalServices.getService(
+ GestureLauncherService.class);
+ if (gestureService == null) {
+ return false;
+ }
+
+ final MutableBoolean outLaunched = new MutableBoolean(false);
+ final boolean gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event,
+ interactive, outLaunched);
+ if (outLaunched.value && mRequestedOrGoingToSleep) {
+ mCameraGestureTriggeredDuringGoingToSleep = true;
+ }
+ return gesturedServiceIntercepted;
+ }
+
/**
* Handle statusbar expansion events.
* @param event
@@ -4766,15 +4751,6 @@
}
}
- private void schedulePossibleVeryLongPressReboot() {
- mHandler.removeCallbacks(mPossibleVeryLongPressReboot);
- mHandler.postDelayed(mPossibleVeryLongPressReboot, mVeryLongPressTimeout);
- }
-
- private void cancelPossibleVeryLongPressReboot() {
- mHandler.removeCallbacks(mPossibleVeryLongPressReboot);
- }
-
// TODO (multidisplay): Support multiple displays in WindowManagerPolicy.
private void updateScreenOffSleepToken(boolean acquire) {
if (acquire) {
diff --git a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
new file mode 100644
index 0000000..cae2093
--- /dev/null
+++ b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2021 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.server.policy;
+
+import android.annotation.IntDef;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.ViewConfiguration;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+
+/**
+ * Detect single key gesture: press, long press, very long press and multi press.
+ *
+ * Call {@link #reset} if current {@link KeyEvent} has been handled by another policy
+ */
+
+public final class SingleKeyGestureDetector {
+ private static final String TAG = "SingleKeyGesture";
+ private static final boolean DEBUG = false;
+
+ private static final int MSG_KEY_LONG_PRESS = 0;
+ private static final int MSG_KEY_VERY_LONG_PRESS = 1;
+ private static final int MSG_KEY_DELAYED_PRESS = 2;
+
+ private final long mLongPressTimeout;
+ private final long mVeryLongPressTimeout;
+
+ private volatile int mKeyPressCounter;
+
+ private final ArrayList<SingleKeyRule> mRules = new ArrayList();
+ private SingleKeyRule mActiveRule = null;
+
+ // Key code of current key down event, reset when key up.
+ private int mDownKeyCode = KeyEvent.KEYCODE_UNKNOWN;
+ private volatile boolean mHandledByLongPress = false;
+ private final Handler mHandler;
+ private static final long MULTI_PRESS_TIMEOUT = ViewConfiguration.getMultiPressTimeout();
+
+
+ /** Supported gesture flags */
+ public static final int KEY_LONGPRESS = 1 << 1;
+ public static final int KEY_VERYLONGPRESS = 1 << 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "KEY_" }, value = {
+ KEY_LONGPRESS,
+ KEY_VERYLONGPRESS,
+ })
+ public @interface KeyGestureFlag {}
+
+ /**
+ * Rule definition for single keys gesture.
+ * E.g : define power key.
+ * <pre class="prettyprint">
+ * SingleKeyRule rule =
+ * new SingleKeyRule(KEYCODE_POWER, KEY_LONGPRESS|KEY_VERYLONGPRESS) {
+ * int getMaxMultiPressCount() { // maximum multi press count. }
+ * void onPress(long downTime) { // short press behavior. }
+ * void onLongPress(long eventTime) { // long press behavior. }
+ * void onVeryLongPress(long eventTime) { // very long press behavior. }
+ * void onMultiPress(long downTime, int count) { // multi press behavior. }
+ * };
+ * </pre>
+ */
+ abstract static class SingleKeyRule {
+ private final int mKeyCode;
+ private final int mSupportedGestures;
+
+ SingleKeyRule(int keyCode, @KeyGestureFlag int supportedGestures) {
+ mKeyCode = keyCode;
+ mSupportedGestures = supportedGestures;
+ }
+
+ /**
+ * True if the rule could intercept the key.
+ */
+ private boolean shouldInterceptKey(int keyCode) {
+ return keyCode == mKeyCode;
+ }
+
+ /**
+ * True if the rule support long press.
+ */
+ private boolean supportLongPress() {
+ return (mSupportedGestures & KEY_LONGPRESS) != 0;
+ }
+
+ /**
+ * True if the rule support very long press.
+ */
+ private boolean supportVeryLongPress() {
+ return (mSupportedGestures & KEY_VERYLONGPRESS) != 0;
+ }
+
+ /**
+ * Maximum count of multi presses.
+ * Return 1 will trigger onPress immediately when {@link KeyEvent.ACTION_UP}.
+ * Otherwise trigger onMultiPress immediately when reach max count when
+ * {@link KeyEvent.ACTION_DOWN}.
+ */
+ int getMaxMultiPressCount() {
+ return 1;
+ }
+
+ /**
+ * Called when short press has been detected.
+ */
+ abstract void onPress(long downTime);
+ /**
+ * Callback when multi press (>= 2) has been detected.
+ */
+ void onMultiPress(long downTime, int count) {}
+ /**
+ * Callback when long press has been detected.
+ */
+ void onLongPress(long eventTime) {}
+ /**
+ * Callback when very long press has been detected.
+ */
+ void onVeryLongPress(long eventTime) {}
+
+ @Override
+ public String toString() {
+ return "KeyCode = " + KeyEvent.keyCodeToString(mKeyCode)
+ + ", long press : " + supportLongPress()
+ + ", very Long press : " + supportVeryLongPress()
+ + ", max multi press count : " + getMaxMultiPressCount();
+ }
+ }
+
+ public SingleKeyGestureDetector(Context context) {
+ mLongPressTimeout = ViewConfiguration.get(context).getDeviceGlobalActionKeyTimeout();
+ mVeryLongPressTimeout = context.getResources().getInteger(
+ com.android.internal.R.integer.config_veryLongPressTimeout);
+ mHandler = new KeyHandler();
+ }
+
+ void addRule(SingleKeyRule rule) {
+ mRules.add(rule);
+ }
+
+ void interceptKey(KeyEvent event) {
+ if (event.getAction() == KeyEvent.ACTION_DOWN) {
+ interceptKeyDown(event);
+ } else {
+ interceptKeyUp(event);
+ }
+ }
+
+ private void interceptKeyDown(KeyEvent event) {
+ final int keyCode = event.getKeyCode();
+ // same key down.
+ if (mDownKeyCode == keyCode) {
+ if (mActiveRule != null && (event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0
+ && mActiveRule.supportLongPress() && !mHandledByLongPress) {
+ if (DEBUG) {
+ Log.i(TAG, "Long press key " + KeyEvent.keyCodeToString(keyCode));
+ }
+ mHandledByLongPress = true;
+ mHandler.removeMessages(MSG_KEY_LONG_PRESS);
+ mHandler.removeMessages(MSG_KEY_VERY_LONG_PRESS);
+ mActiveRule.onLongPress(event.getEventTime());
+ }
+ return;
+ }
+
+ // When a different key is pressed, stop processing gestures for the currently active key.
+ if (mDownKeyCode != KeyEvent.KEYCODE_UNKNOWN
+ || (mActiveRule != null && !mActiveRule.shouldInterceptKey(keyCode))) {
+ if (DEBUG) {
+ Log.i(TAG, "Press another key " + KeyEvent.keyCodeToString(keyCode));
+ }
+ reset();
+ }
+ mDownKeyCode = keyCode;
+
+ // Picks a new rule, return if no rule picked.
+ if (mActiveRule == null) {
+ final int count = mRules.size();
+ for (int index = 0; index < count; index++) {
+ final SingleKeyRule rule = mRules.get(index);
+ if (rule.shouldInterceptKey(keyCode)) {
+ if (DEBUG) {
+ Log.i(TAG, "Intercept key by rule " + rule);
+ }
+ mActiveRule = rule;
+ break;
+ }
+ }
+ }
+ if (mActiveRule == null) {
+ return;
+ }
+
+ final long eventTime = event.getEventTime();
+ if (mKeyPressCounter == 0) {
+ if (mActiveRule.supportLongPress()) {
+ final Message msg = mHandler.obtainMessage(MSG_KEY_LONG_PRESS, keyCode, 0,
+ eventTime);
+ msg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(msg, mLongPressTimeout);
+ }
+
+ if (mActiveRule.supportVeryLongPress()) {
+ final Message msg = mHandler.obtainMessage(MSG_KEY_VERY_LONG_PRESS, keyCode, 0,
+ eventTime);
+ msg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(msg, mVeryLongPressTimeout);
+ }
+ } else {
+ mHandler.removeMessages(MSG_KEY_LONG_PRESS);
+ mHandler.removeMessages(MSG_KEY_VERY_LONG_PRESS);
+ mHandler.removeMessages(MSG_KEY_DELAYED_PRESS);
+
+ // Trigger multi press immediately when reach max count.( > 1)
+ if (mKeyPressCounter == mActiveRule.getMaxMultiPressCount() - 1) {
+ if (DEBUG) {
+ Log.i(TAG, "Trigger multi press " + mActiveRule.toString() + " for it"
+ + " reach the max count " + mKeyPressCounter);
+ }
+ mActiveRule.onMultiPress(eventTime, mKeyPressCounter + 1);
+ mKeyPressCounter = 0;
+ }
+ }
+ }
+
+ private boolean interceptKeyUp(KeyEvent event) {
+ mHandler.removeMessages(MSG_KEY_LONG_PRESS);
+ mHandler.removeMessages(MSG_KEY_VERY_LONG_PRESS);
+ mDownKeyCode = KeyEvent.KEYCODE_UNKNOWN;
+ if (mActiveRule == null) {
+ return false;
+ }
+
+ if (mHandledByLongPress) {
+ mHandledByLongPress = false;
+ mKeyPressCounter = 0;
+ return true;
+ }
+
+ final long downTime = event.getDownTime();
+ if (event.getKeyCode() == mActiveRule.mKeyCode) {
+ // Directly trigger short press when max count is 1.
+ if (mActiveRule.getMaxMultiPressCount() == 1) {
+ if (DEBUG) {
+ Log.i(TAG, "press key " + KeyEvent.keyCodeToString(event.getKeyCode()));
+ }
+ mActiveRule.onPress(downTime);
+ return true;
+ }
+
+ // This could be a multi-press. Wait a little bit longer to confirm.
+ mKeyPressCounter++;
+ Message msg = mHandler.obtainMessage(MSG_KEY_DELAYED_PRESS, mActiveRule.mKeyCode,
+ mKeyPressCounter, downTime);
+ msg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(msg, MULTI_PRESS_TIMEOUT);
+ return true;
+ }
+ reset();
+ return false;
+ }
+
+ int getKeyPressCounter(int keyCode) {
+ if (mActiveRule != null && mActiveRule.mKeyCode == keyCode) {
+ return mKeyPressCounter;
+ } else {
+ return 0;
+ }
+ }
+
+ void reset() {
+ if (mActiveRule != null) {
+ if (mDownKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
+ mHandler.removeMessages(MSG_KEY_LONG_PRESS);
+ mHandler.removeMessages(MSG_KEY_VERY_LONG_PRESS);
+ }
+
+ if (mKeyPressCounter > 0) {
+ mHandler.removeMessages(MSG_KEY_DELAYED_PRESS);
+ mKeyPressCounter = 0;
+ }
+ mActiveRule = null;
+ }
+
+ mHandledByLongPress = false;
+ mDownKeyCode = KeyEvent.KEYCODE_UNKNOWN;
+ }
+
+ boolean isKeyIntercepted(int keyCode) {
+ if (mActiveRule != null && mActiveRule.shouldInterceptKey(keyCode)) {
+ return mHandledByLongPress;
+ }
+ return false;
+ }
+
+ private class KeyHandler extends Handler {
+ KeyHandler() {
+ super(Looper.getMainLooper());
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (mActiveRule == null) {
+ return;
+ }
+ final int keyCode = msg.arg1;
+ final long eventTime = (long) msg.obj;
+ switch(msg.what) {
+ case MSG_KEY_LONG_PRESS:
+ if (DEBUG) {
+ Log.i(TAG, "Detect long press " + KeyEvent.keyCodeToString(keyCode));
+ }
+ mHandledByLongPress = true;
+ mActiveRule.onLongPress(eventTime);
+ break;
+ case MSG_KEY_VERY_LONG_PRESS:
+ if (DEBUG) {
+ Log.i(TAG, "Detect very long press "
+ + KeyEvent.keyCodeToString(keyCode));
+ }
+ mHandledByLongPress = true;
+ mActiveRule.onVeryLongPress(eventTime);
+ break;
+ case MSG_KEY_DELAYED_PRESS:
+ if (DEBUG) {
+ Log.i(TAG, "Detect press " + KeyEvent.keyCodeToString(keyCode)
+ + ", count " + mKeyPressCounter);
+ }
+ if (mKeyPressCounter == 1) {
+ mActiveRule.onPress(eventTime);
+ } else {
+ mActiveRule.onMultiPress(eventTime, mKeyPressCounter);
+ }
+ mKeyPressCounter = 0;
+ break;
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index bc11709..29adde3 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -5073,7 +5073,7 @@
}
@Override // Binder call
- public void userActivity(long eventTime, int event, int flags) {
+ public void userActivity(int displayId, long eventTime, int event, int flags) {
final long now = mClock.uptimeMillis();
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER)
!= PackageManager.PERMISSION_GRANTED
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 6aa7c8a..7ed7a59 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -3759,13 +3759,15 @@
ConnectivityManager.NetworkCallback {
@Override
public void onAvailable(Network network) {
- FrameworkStatsLog.write(FrameworkStatsLog.CONNECTIVITY_STATE_CHANGED, network.netId,
+ FrameworkStatsLog.write(FrameworkStatsLog.CONNECTIVITY_STATE_CHANGED,
+ network.getNetId(),
FrameworkStatsLog.CONNECTIVITY_STATE_CHANGED__STATE__CONNECTED);
}
@Override
public void onLost(Network network) {
- FrameworkStatsLog.write(FrameworkStatsLog.CONNECTIVITY_STATE_CHANGED, network.netId,
+ FrameworkStatsLog.write(FrameworkStatsLog.CONNECTIVITY_STATE_CHANGED,
+ network.getNetId(),
FrameworkStatsLog.CONNECTIVITY_STATE_CHANGED__STATE__DISCONNECTED);
}
}
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index d2b05c0..a0e2286 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -42,8 +42,8 @@
import android.os.storage.StorageVolume;
import android.service.storage.ExternalStorageService;
import android.service.storage.IExternalStorageService;
-import android.util.ArraySet;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
@@ -53,11 +53,13 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
/**
* Controls the lifecycle of the {@link ActiveConnection} to an {@link ExternalStorageService}
@@ -72,15 +74,17 @@
private final Context mContext;
private final int mUserId;
private final StorageSessionController mSessionController;
+ private final StorageManagerInternal mSmInternal;
private final ActiveConnection mActiveConnection = new ActiveConnection();
- @GuardedBy("mLock") private final Map<String, Session> mSessions = new HashMap<>();
- @GuardedBy("mLock") private final Set<Integer> mUidsBlockedOnIo = new ArraySet<>();
+ @GuardedBy("mSessionsLock") private final Map<String, Session> mSessions = new HashMap<>();
+ @GuardedBy("mSessionsLock") private final SparseArray<Integer> mUidsBlockedOnIo = new SparseArray<>();
private final HandlerThread mHandlerThread;
public StorageUserConnection(Context context, int userId, StorageSessionController controller) {
mContext = Objects.requireNonNull(context);
mUserId = Preconditions.checkArgumentNonnegative(userId);
mSessionController = controller;
+ mSmInternal = LocalServices.getService(StorageManagerInternal.class);
mHandlerThread = new HandlerThread("StorageUserConnectionThread-" + mUserId);
mHandlerThread.start();
}
@@ -152,9 +156,13 @@
*/
public void notifyAnrDelayStarted(String packageName, int uid, int tid, int reason)
throws ExternalStorageServiceException {
+ List<String> primarySessionIds = mSmInternal.getPrimaryVolumeIds();
synchronized (mSessionsLock) {
for (String sessionId : mSessions.keySet()) {
- mActiveConnection.notifyAnrDelayStarted(packageName, uid, tid, reason);
+ if (primarySessionIds.contains(sessionId)) {
+ mActiveConnection.notifyAnrDelayStarted(packageName, uid, tid, reason);
+ return;
+ }
}
}
}
@@ -201,8 +209,7 @@
return;
}
}
- StorageManagerInternal sm = LocalServices.getService(StorageManagerInternal.class);
- sm.resetUser(mUserId);
+ mSmInternal.resetUser(mUserId);
}
/**
@@ -242,7 +249,8 @@
public void notifyAppIoBlocked(String volumeUuid, int uid, int tid,
@StorageManager.AppIoBlockedReason int reason) {
synchronized (mSessionsLock) {
- mUidsBlockedOnIo.add(uid);
+ int ioBlockedCounter = mUidsBlockedOnIo.get(uid, 0);
+ mUidsBlockedOnIo.put(uid, ++ioBlockedCounter);
}
}
@@ -255,7 +263,12 @@
public void notifyAppIoResumed(String volumeUuid, int uid, int tid,
@StorageManager.AppIoBlockedReason int reason) {
synchronized (mSessionsLock) {
- mUidsBlockedOnIo.remove(uid);
+ int ioBlockedCounter = mUidsBlockedOnIo.get(uid, 0);
+ if (ioBlockedCounter == 0) {
+ mUidsBlockedOnIo.remove(uid);
+ } else {
+ mUidsBlockedOnIo.put(uid, --ioBlockedCounter);
+ }
}
}
@@ -317,6 +330,23 @@
}
}
+ private void asyncBestEffort(Consumer<IExternalStorageService> consumer) {
+ synchronized (mLock) {
+ if (mRemoteFuture == null) {
+ Slog.w(TAG, "Dropping async request service is not bound");
+ return;
+ }
+
+ IExternalStorageService service = mRemoteFuture.getNow(null);
+ if (service == null) {
+ Slog.w(TAG, "Dropping async request service is not connected");
+ return;
+ }
+
+ consumer.accept(service);
+ }
+ }
+
private void waitForAsyncVoid(AsyncStorageServiceCall asyncCall) throws Exception {
CompletableFuture<Void> opFuture = new CompletableFuture<>();
RemoteCallback callback = new RemoteCallback(result -> setResult(result, opFuture));
@@ -401,13 +431,13 @@
public void notifyAnrDelayStarted(String packgeName, int uid, int tid, int reason)
throws ExternalStorageServiceException {
- try {
- waitForAsyncVoid((service, callback) ->
- service.notifyAnrDelayStarted(packgeName, uid, tid, reason, callback));
- } catch (Exception e) {
- throw new ExternalStorageServiceException("Failed to notify ANR delay started: "
- + packgeName, e);
- }
+ asyncBestEffort(service -> {
+ try {
+ service.notifyAnrDelayStarted(packgeName, uid, tid, reason);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to notify ANR delay started", e);
+ }
+ });
}
private void setResult(Bundle result, CompletableFuture<Void> future) {
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java b/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java
index 5772dea..e54b40e 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java
@@ -16,6 +16,8 @@
package com.android.server.uri;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Intent;
import android.content.pm.ProviderInfo;
import android.net.Uri;
@@ -58,6 +60,19 @@
void grantUriPermissionUncheckedFromIntent(
NeededUriGrants needed, UriPermissionOwner owner);
+ /**
+ * Creates a new stateful object to track uri permission grants. This is needed to maintain
+ * state when managing grants via {@link UriGrantsManagerService#grantUriPermissionFromOwner},
+ * {@link #revokeUriPermissionFromOwner}, etc.
+ *
+ * @param name A name for the object. This is only used for logcat/dumpsys logging, so there
+ * are no uniqueness or other requirements, but it is recommended to make the
+ * name sufficiently readable so that the relevant code area can be determined
+ * easily when this name shows up in a bug report.
+ * @return An opaque owner token for tracking uri permission grants.
+ * @see UriPermissionOwner
+ * @see UriGrantsManagerService
+ */
IBinder newUriPermissionOwner(String name);
/**
@@ -74,33 +89,39 @@
*/
void removeUriPermissionsForPackage(
String packageName, int userHandle, boolean persistable, boolean targetOnly);
+
/**
- * Remove any {@link UriPermission} associated with the owner whose values match the given
- * filtering parameters.
- *
- * @param token An opaque owner token as returned by {@link #newUriPermissionOwner(String)}.
- * @param uri This uri must NOT contain an embedded userId. {@code null} to apply to all Uris.
- * @param mode The modes (as a bitmask) to revoke.
- * @param userId The userId in which the uri is to be resolved.
+ * Like {@link #revokeUriPermissionFromOwner(IBinder, Uri, int, int, String, int)} but applies
+ * to all target packages and all target users.
*/
- void revokeUriPermissionFromOwner(IBinder token, Uri uri, int mode, int userId);
+ void revokeUriPermissionFromOwner(@NonNull IBinder token, @Nullable Uri uri, int mode,
+ int userId);
/**
* Remove any {@link UriPermission} associated with the owner whose values match the given
* filtering parameters.
*
* @param token An opaque owner token as returned by {@link #newUriPermissionOwner(String)}.
- * @param uri This uri must NOT contain an embedded userId. {@code null} to apply to all Uris.
- * @param mode The modes (as a bitmask) to revoke.
- * @param userId The userId in which the uri is to be resolved.
- * @param targetPkg Calling package name to match, or {@code null} to apply to all packages.
- * @param targetUserId Calling user to match, or {@link UserHandle#USER_ALL} to apply to all
- * users.
+ * @param uri The content uri for which the permission grant should be revoked. This uri
+ * must NOT contain an embedded userId; use
+ * {@link android.content.ContentProvider#getUriWithoutUserId(Uri)} if needed.
+ * This param may be {@code null} to revoke grants for all uris tracked by the
+ * provided owner token.
+ * @param mode The modes (as a bitmask) to revoke. See
+ * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}, etc.
+ * @param userId The userId in which the given uri is to be resolved. If the {@code uri}
+ * param is {@code null}, this param is ignored since permissions for all
+ * uris will be revoked.
+ * @param targetPkg Target package name to match (app that received the grant), or
+ * {@code null} to apply to all packages.
+ * @param targetUserId Target user to match (userId of the app that received the grant), or
+ * {@link UserHandle#USER_ALL} to apply to all users.
*/
- void revokeUriPermissionFromOwner(IBinder token, Uri uri, int mode, int userId,
- String targetPkg, int targetUserId);
+ void revokeUriPermissionFromOwner(@NonNull IBinder token, @Nullable Uri uri, int mode,
+ int userId, @Nullable String targetPkg, int targetUserId);
boolean checkAuthorityGrants(
int callingUid, ProviderInfo cpi, int userId, boolean checkUser);
+
void dump(PrintWriter pw, boolean dumpAll, String dumpPackage);
}
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index dcc1599..44545ed 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -33,17 +33,13 @@
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.myUid;
-import static com.android.internal.util.XmlUtils.readBooleanAttribute;
-import static com.android.internal.util.XmlUtils.readIntAttribute;
-import static com.android.internal.util.XmlUtils.readLongAttribute;
import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
-import static com.android.internal.util.XmlUtils.writeIntAttribute;
-import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.server.uri.UriGrantsManagerService.H.PERSIST_URI_GRANTS_MSG;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
@@ -82,7 +78,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.server.IoThread;
import com.android.server.LocalServices;
@@ -94,9 +89,7 @@
import libcore.io.IoUtils;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileInputStream;
@@ -104,7 +97,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
@@ -211,6 +203,21 @@
}
}
+ /**
+ * Grant uri permissions to the specified app.
+ *
+ * @param token An opaque owner token for tracking the permissions. See
+ * {@link UriGrantsManagerInternal#newUriPermissionOwner}.
+ * @param fromUid The uid of the grantor app that has permissions to the uri. Permissions
+ * will be granted on behalf of this app.
+ * @param targetPkg The package name of the grantor app that has permissions to the uri.
+ * Permissions will be granted on behalf of this app.
+ * @param uri The uri for which permissions should be granted. This uri must NOT contain an
+ * embedded userId; use {@link ContentProvider#getUriWithoutUserId(Uri)} if needed.
+ * @param modeFlags The modes to grant. See {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}, etc.
+ * @param sourceUserId The userId in which the uri is to be resolved.
+ * @param targetUserId The userId of the target app to receive the grant.
+ */
@Override
public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg,
Uri uri, final int modeFlags, int sourceUserId, int targetUserId) {
@@ -219,12 +226,11 @@
}
/**
- * @param uri This uri must NOT contain an embedded userId.
- * @param sourceUserId The userId in which the uri is to be resolved.
- * @param targetUserId The userId of the app that receives the grant.
+ * See {@link #grantUriPermissionFromOwner(IBinder, int, String, Uri, int, int, int)}.
*/
- private void grantUriPermissionFromOwnerUnlocked(IBinder token, int fromUid, String targetPkg,
- Uri uri, final int modeFlags, int sourceUserId, int targetUserId) {
+ private void grantUriPermissionFromOwnerUnlocked(@NonNull IBinder token, int fromUid,
+ @NonNull String targetPkg, @NonNull Uri uri, final int modeFlags,
+ int sourceUserId, int targetUserId) {
targetUserId = mAmInternal.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), targetUserId, false, ALLOW_FULL_ONLY,
"grantUriPermissionFromOwner", null);
diff --git a/services/core/java/com/android/server/vibrator/Vibration.java b/services/core/java/com/android/server/vibrator/Vibration.java
index 607da3c..e84ee672 100644
--- a/services/core/java/com/android/server/vibrator/Vibration.java
+++ b/services/core/java/com/android/server/vibrator/Vibration.java
@@ -120,7 +120,9 @@
if (newEffect.equals(mEffect)) {
return;
}
- mOriginalEffect = mEffect;
+ if (mOriginalEffect == null) {
+ mOriginalEffect = mEffect;
+ }
mEffect = newEffect;
}
diff --git a/services/core/java/com/android/server/vibrator/VibratorController.java b/services/core/java/com/android/server/vibrator/VibratorController.java
index 95f6059..eaba083 100644
--- a/services/core/java/com/android/server/vibrator/VibratorController.java
+++ b/services/core/java/com/android/server/vibrator/VibratorController.java
@@ -87,8 +87,8 @@
static native long vibratorPerformEffect(
long nativePtr, long effect, long strength, long vibrationId);
- static native void vibratorPerformComposedEffect(long nativePtr,
- VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId);
+ static native long vibratorPerformComposedEffect(
+ long nativePtr, VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId);
static native void vibratorSetExternalControl(long nativePtr, boolean enabled);
@@ -269,13 +269,9 @@
VibrationEffect.Composition.PrimitiveEffect[] primitives =
effect.getPrimitiveEffects().toArray(
new VibrationEffect.Composition.PrimitiveEffect[0]);
- mNativeWrapper.compose(primitives, vibrationId);
- notifyVibratorOnLocked();
- // Compose don't actually give us an estimated duration, so we just guess here.
- long duration = 0;
- for (VibrationEffect.Composition.PrimitiveEffect primitive : primitives) {
- // TODO(b/177807015): use exposed durations from IVibrator here instead
- duration += 20 + primitive.delay;
+ long duration = mNativeWrapper.compose(primitives, vibrationId);
+ if (duration > 0) {
+ notifyVibratorOnLocked();
}
return duration;
}
@@ -393,9 +389,9 @@
}
/** Turns vibrator on to perform one of the supported composed effects. */
- public void compose(
+ public long compose(
VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId) {
- VibratorController.vibratorPerformComposedEffect(mNativePtr, effect,
+ return VibratorController.vibratorPerformComposedEffect(mNativePtr, effect,
vibrationId);
}
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 90a763c..c9751bb 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -344,10 +344,11 @@
if (!isEffectValid(effect)) {
return;
}
- effect = fixupVibrationEffect(effect);
attrs = fixupVibrationAttributes(attrs);
Vibration vib = new Vibration(token, mNextVibrationId.getAndIncrement(), effect, attrs,
uid, opPkg, reason);
+ // Update with fixed up effect to keep the original effect in Vibration for debugging.
+ vib.updateEffect(fixupVibrationEffect(effect));
synchronized (mLock) {
Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(vib);
@@ -1138,6 +1139,9 @@
void dumpText(PrintWriter pw) {
pw.println("Vibrator Manager Service:");
synchronized (mLock) {
+ pw.println(" mVibrationSettings:");
+ pw.println(" " + mVibrationSettings);
+ pw.println();
pw.println(" mVibratorControllers:");
for (int i = 0; i < mVibrators.size(); i++) {
pw.println(" " + mVibrators.valueAt(i));
@@ -1146,14 +1150,15 @@
pw.println(" mCurrentVibration:");
pw.println(" " + (mCurrentVibration == null
? null : mCurrentVibration.getVibration().getDebugInfo()));
+ pw.println();
pw.println(" mNextVibration:");
pw.println(" " + (mNextVibration == null
? null : mNextVibration.getVibration().getDebugInfo()));
+ pw.println();
pw.println(" mCurrentExternalVibration:");
pw.println(" " + (mCurrentExternalVibration == null
? null : mCurrentExternalVibration.getDebugInfo()));
pw.println();
- pw.println(" mVibrationSettings=" + mVibrationSettings);
for (int i = 0; i < mPreviousVibrations.size(); i++) {
pw.println();
pw.print(" Previous vibrations for usage ");
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 5932388..298128a 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -211,9 +211,10 @@
import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND;
import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING;
import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_SOLID_COLOR;
-import static com.android.server.wm.WindowManagerService.MIN_TASK_LETTERBOX_ASPECT_RATIO;
+import static com.android.server.wm.WindowManagerService.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
+import static com.android.server.wm.WindowManagerService.letterboxBackgroundTypeToString;
import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY;
import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_BEFORE_ANIM;
@@ -580,9 +581,6 @@
private Task mLastParent;
- // Have we told the window clients to show themselves?
- private boolean mClientVisible;
-
boolean firstWindowDrawn;
/** Whether the visible window(s) of this activity is drawn. */
private boolean mReportedDrawn;
@@ -910,7 +908,7 @@
pw.print(Integer.toHexString(taskDescription.getStatusBarColor()));
pw.print(" navigationBarColor=");
pw.println(Integer.toHexString(taskDescription.getNavigationBarColor()));
- pw.print(" backgroundColorFloating=");
+ pw.print(prefix); pw.print(" backgroundColorFloating=");
pw.println(Integer.toHexString(
taskDescription.getBackgroundColorFloating()));
}
@@ -998,7 +996,7 @@
pw.print(prefix); pw.print("mOrientation=");
pw.println(ActivityInfo.screenOrientationToString(mOrientation));
pw.println(prefix + "mVisibleRequested=" + mVisibleRequested
- + " mVisible=" + mVisible + " mClientVisible=" + mClientVisible
+ + " mVisible=" + mVisible + " mClientVisible=" + isClientVisible()
+ ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "")
+ " reportedDrawn=" + mReportedDrawn + " reportedVisible=" + reportedVisible);
if (paused) {
@@ -1080,6 +1078,46 @@
pw.println(prefix + "configChanges=0x" + Integer.toHexString(info.configChanges));
}
}
+
+ dumpLetterboxInfo(pw, prefix);
+ }
+
+ private void dumpLetterboxInfo(PrintWriter pw, String prefix) {
+ final WindowState mainWin = findMainWindow();
+ if (mainWin == null) {
+ return;
+ }
+
+ boolean isLetterboxed = isLetterboxed(mainWin);
+ pw.println(prefix + "isLetterboxed=" + isLetterboxed);
+ if (!isLetterboxed) {
+ return;
+ }
+
+ pw.println(prefix + " letterboxReason=" + getLetterboxReasonString(mainWin));
+ pw.println(prefix + " letterboxBackgroundColor=" + Integer.toHexString(
+ getLetterboxBackgroundColor().toArgb()));
+ pw.println(prefix + " letterboxBackgroundType="
+ + letterboxBackgroundTypeToString(mWmService.getLetterboxBackgroundType()));
+ pw.println(prefix + " letterboxAspectRatio="
+ + computeAspectRatio(getBounds()));
+ }
+
+ /**
+ * Returns a string representing the reason for letterboxing. This method assumes the activity
+ * is letterboxed.
+ */
+ private String getLetterboxReasonString(WindowState mainWin) {
+ if (inSizeCompatMode()) {
+ return "SIZE_COMPAT_MODE";
+ }
+ if (isLetterboxedForFixedOrientationAndAspectRatio()) {
+ return "FIXED_ORIENTATION";
+ }
+ if (mainWin.isLetterboxedForDisplayCutout()) {
+ return "DISPLAY_CUTOUT";
+ }
+ return "UNKNOWN_REASON";
}
void setAppTimeTracker(AppTimeTracker att) {
@@ -1695,7 +1733,7 @@
keysPaused = false;
inHistory = false;
nowVisible = false;
- mClientVisible = true;
+ super.setClientVisible(true);
idle = false;
hasBeenLaunched = false;
mTaskSupervisor = supervisor;
@@ -3735,7 +3773,7 @@
setVisibleRequested(true);
mVisibleSetFromTransferredStartingWindow = true;
}
- setClientVisible(fromActivity.mClientVisible);
+ setClientVisible(fromActivity.isClientVisible());
if (fromActivity.isAnimating()) {
transferAnimation(fromActivity);
@@ -5836,18 +5874,15 @@
return mReportedDrawn;
}
- boolean isClientVisible() {
- return mClientVisible;
- }
-
+ @Override
void setClientVisible(boolean clientVisible) {
- if (mClientVisible == clientVisible || (!clientVisible && mDeferHidingClient)) {
- return;
- }
+ // TODO(shell-transitions): Remove mDeferHidingClient once everything is shell-transitions.
+ // pip activities should just remain in clientVisible.
+ if (!clientVisible && mDeferHidingClient) return;
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"setClientVisible: %s clientVisible=%b Callers=%s", this, clientVisible,
Debug.getCallers(5));
- mClientVisible = clientVisible;
+ super.setClientVisible(clientVisible);
sendAppVisibilityToClients();
}
@@ -6959,6 +6994,13 @@
float aspect = Math.max(parentWidth, parentHeight)
/ (float) Math.min(parentWidth, parentHeight);
+ // Override from config_fixedOrientationLetterboxAspectRatio or via ADB with
+ // set-fixed-orientation-letterbox-aspect-ratio.
+ final float letterboxAspectRatioOverride =
+ mWmService.getFixedOrientationLetterboxAspectRatio();
+ aspect = letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
+ ? letterboxAspectRatioOverride : aspect;
+
// Adjust the fixed orientation letterbox bounds to fit the app request aspect ratio in
// order to use the extra available space.
final float maxAspectRatio = info.maxAspectRatio;
@@ -6969,16 +7011,6 @@
aspect = minAspectRatio;
}
- // Override from config_letterboxAspectRatio or via ADB with set-letterbox-aspect-ratio.
- // TODO(b/175212232): Rename getTaskLetterboxAspectRatio and all related methods since fixed
- // orientation letterbox is on the activity level now.
- final float letterboxAspectRatioOverride = mWmService.getTaskLetterboxAspectRatio();
- // Activity min/max aspect ratio restrictions will be respected by the activity-level
- // letterboxing (size-compat mode). Therefore this override can control the maximum screen
- // area that can be occupied by the app in the letterbox mode.
- aspect = letterboxAspectRatioOverride > MIN_TASK_LETTERBOX_ASPECT_RATIO
- ? letterboxAspectRatioOverride : aspect;
-
// Store the current bounds to be able to revert to size compat mode values below if needed.
Rect mTmpFullBounds = new Rect(resolvedBounds);
if (forcedOrientation == ORIENTATION_LANDSCAPE) {
@@ -7391,8 +7423,7 @@
final int containingAppWidth = containingAppBounds.width();
final int containingAppHeight = containingAppBounds.height();
- final float containingRatio = Math.max(containingAppWidth, containingAppHeight)
- / (float) Math.min(containingAppWidth, containingAppHeight);
+ final float containingRatio = computeAspectRatio(containingAppBounds);
int activityWidth = containingAppWidth;
int activityHeight = containingAppHeight;
@@ -7456,6 +7487,18 @@
}
/**
+ * Returns the aspect ratio of the given {@code rect}.
+ */
+ private static float computeAspectRatio(Rect rect) {
+ final int width = rect.width();
+ final int height = rect.height();
+ if (width == 0 || height == 0) {
+ return 0;
+ }
+ return Math.max(width, height) / (float) Math.min(width, height);
+ }
+
+ /**
* @return {@code true} if this activity was reparented to another display but
* {@link #ensureActivityConfiguration} is not called.
*/
@@ -8134,7 +8177,7 @@
proto.write(TRANSLUCENT, !occludesParent());
proto.write(VISIBLE, mVisible);
proto.write(VISIBLE_REQUESTED, mVisibleRequested);
- proto.write(CLIENT_VISIBLE, mClientVisible);
+ proto.write(CLIENT_VISIBLE, isClientVisible());
proto.write(DEFER_HIDING_CLIENT, mDeferHidingClient);
proto.write(REPORTED_DRAWN, mReportedDrawn);
proto.write(REPORTED_VISIBLE, reportedVisible);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index bb0f1f0..db751e9 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -1504,7 +1504,13 @@
// Prevent recursion.
return;
}
- mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CLOSE, task);
+ if (task.isVisible()) {
+ mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CLOSE, task);
+ } else {
+ // Removing a non-visible task doesn't require a transition, but if there is one
+ // collecting, this should be a member just in case.
+ mService.getTransitionController().collect(task);
+ }
task.mInRemoveTask = true;
try {
task.performClearTask(reason);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 84bc853..119ffb7 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4823,7 +4823,7 @@
}
mNoAnimationNotifyOnTransitionFinished.clear();
- mWallpaperController.hideDeferredWallpapersIfNeeded();
+ mWallpaperController.hideDeferredWallpapersIfNeededLegacy();
onAppTransitionDone();
@@ -5262,13 +5262,6 @@
|| windowingMode == WINDOWING_MODE_MULTI_WINDOW);
}
- static boolean canReuseExistingTask(int windowingMode, int activityType) {
- // Existing Tasks can be reused if a new root task will be created anyway, or for the
- // Dream - because there can only ever be one DreamActivity.
- return alwaysCreateRootTask(windowingMode, activityType)
- || activityType == ACTIVITY_TYPE_DREAM;
- }
-
@Nullable
Task getFocusedRootTask() {
return getItemFromTaskDisplayAreas(TaskDisplayArea::getFocusedRootTask);
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index 1f7e152..316c20b 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -99,6 +99,9 @@
mTask.forAllActivities(a -> {
setActivityVisibilityState(a, starting, resumeTopActivity);
});
+ if (mTask.mAtmService.getTransitionController().getTransitionPlayer() != null) {
+ mTask.getDisplayContent().mWallpaperController.adjustWallpaperWindows();
+ }
}
private void setActivityVisibilityState(ActivityRecord r, ActivityRecord starting,
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 27ef147..28c5a6d9 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -410,15 +410,19 @@
return;
}
+ requestFocus(focusToken, focus.getName());
+ }
+
+ private void requestFocus(IBinder focusToken, String windowName) {
if (focusToken == mInputFocus) {
return;
}
mInputFocus = focusToken;
- mInputTransaction.setFocusedWindow(mInputFocus, focus.getName(), mDisplayId);
- EventLog.writeEvent(LOGTAG_INPUT_FOCUS, "Focus request " + focus,
+ mInputTransaction.setFocusedWindow(mInputFocus, windowName, mDisplayId);
+ EventLog.writeEvent(LOGTAG_INPUT_FOCUS, "Focus request " + windowName,
"reason=UpdateInputWindows");
- ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Focus requested for window=%s", focus);
+ ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Focus requested for window=%s", windowName);
}
void setFocusedAppLw(ActivityRecord newApp) {
@@ -470,6 +474,8 @@
boolean mInDrag;
+ private boolean mRecentsAnimationFocusOverride;
+
private void updateInputWindows(boolean inDrag) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateInputWindows");
@@ -485,10 +491,16 @@
mInDrag = inDrag;
resetInputConsumers(mInputTransaction);
-
+ mRecentsAnimationFocusOverride = false;
mDisplayContent.forAllWindows(this, true /* traverseTopToBottom */);
- updateInputFocusRequest();
+ if (mRecentsAnimationFocusOverride) {
+ requestFocus(mRecentsAnimationInputConsumer.mWindowHandle.token,
+ mRecentsAnimationInputConsumer.mName);
+ } else {
+ updateInputFocusRequest();
+ }
+
if (!mUpdateInputWindowsImmediately) {
mDisplayContent.getPendingTransaction().merge(mInputTransaction);
@@ -526,6 +538,7 @@
mRecentsAnimationInputConsumer.mWindowHandle)) {
mRecentsAnimationInputConsumer.show(mInputTransaction, w.mActivityRecord);
mAddRecentsAnimationInputConsumerHandle = false;
+ mRecentsAnimationFocusOverride = true;
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 5efbb09..194350d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -21,6 +21,7 @@
import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
@@ -3290,11 +3291,22 @@
@Override
boolean handlesOrientationChangeFromDescendant() {
- return super.handlesOrientationChangeFromDescendant()
- // Display won't rotate for the orientation request if the Task/TaskDisplayArea
- // can't specify orientation.
- && canSpecifyOrientation()
- && getDisplayArea().canSpecifyOrientation();
+ if (!super.handlesOrientationChangeFromDescendant()) {
+ return false;
+ }
+
+ // At task level, we want to check canSpecifyOrientation() based on the top activity type.
+ // Do this only on leaf Task, so that the result is not affecting by the sibling leaf Task.
+ // Otherwise, root Task will use the result from the top leaf Task, and all its child
+ // leaf Tasks will rely on that from super.handlesOrientationChangeFromDescendant().
+ if (!isLeafTask()) {
+ return true;
+ }
+
+ // Check for leaf Task.
+ // Display won't rotate for the orientation request if the Task/TaskDisplayArea
+ // can't specify orientation.
+ return canSpecifyOrientation() && getDisplayArea().canSpecifyOrientation();
}
void resize(boolean relayout, boolean forced) {
@@ -3625,7 +3637,6 @@
@Override
void resetSurfacePositionForAnimationLeash(SurfaceControl.Transaction t) {
- if (isOrganized()) return;
super.resetSurfacePositionForAnimationLeash(t);
}
@@ -7349,6 +7360,7 @@
return reuseOrCreateTask(info, intent, null /*voiceSession*/, null /*voiceInteractor*/,
toTop, null /*activity*/, null /*source*/, null /*options*/);
}
+
// TODO: Can be removed once we change callpoints creating root tasks to be creating tasks.
/** Either returns this current task to be re-used or creates a new child task. */
Task reuseOrCreateTask(ActivityInfo info, Intent intent, IVoiceInteractionSession voiceSession,
@@ -7356,7 +7368,7 @@
ActivityRecord source, ActivityOptions options) {
Task task;
- if (DisplayContent.canReuseExistingTask(getWindowingMode(), getActivityType())) {
+ if (canReuseAsLeafTask()) {
// This root task will only contain one task, so just return itself since all root
// tasks ara now tasks and all tasks are now root tasks.
task = reuseAsLeafTask(voiceSession, voiceInteractor, intent, info, activity);
@@ -7391,10 +7403,24 @@
return task;
}
+ /** Return {@code true} if this task can be reused as leaf task. */
+ private boolean canReuseAsLeafTask() {
+ // Cannot be reused as leaf task if this task is created by organizer or having child tasks.
+ if (mCreatedByOrganizer || !isLeafTask()) {
+ return false;
+ }
+
+ // Existing Tasks can be reused if a new root task will be created anyway, or for the
+ // Dream - because there can only ever be one DreamActivity.
+ final int windowingMode = getWindowingMode();
+ final int activityType = getActivityType();
+ return DisplayContent.alwaysCreateRootTask(windowingMode, activityType)
+ || activityType == ACTIVITY_TYPE_DREAM;
+ }
+
void addChild(WindowContainer child, final boolean toTop, boolean showForAllUsers) {
Task task = child.asTask();
try {
-
if (task != null) {
task.setForceShowForAllUsers(showForAllUsers);
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 98eb11f..aadb272 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -135,6 +135,11 @@
mSyncId = mSyncEngine.startSyncSet(this);
}
+ @VisibleForTesting
+ int getSyncId() {
+ return mSyncId;
+ }
+
/**
* Formally starts the transition. Participants can be collected before this is started,
* but this won't consider itself ready until started -- even if all the participants have
@@ -235,16 +240,18 @@
for (int i = mTargets.size() - 1; i >= 0; --i) {
final WindowContainer target = mTargets.valueAt(i);
if (target.getParent() != null) {
+ final SurfaceControl targetLeash = getLeashSurface(target);
+ final SurfaceControl origParent = getOrigParentSurface(target);
// Ensure surfaceControls are re-parented back into the hierarchy.
- t.reparent(target.getSurfaceControl(), target.getParent().getSurfaceControl());
- t.setLayer(target.getSurfaceControl(), target.getLastLayer());
+ t.reparent(targetLeash, origParent);
+ t.setLayer(targetLeash, target.getLastLayer());
// TODO(shell-transitions): Once all remotables have been moved, see if there is
// a more appropriate place to do the following. This may
// involve passing an SF transaction from shell on finish.
target.getRelativePosition(tmpPos);
- t.setPosition(target.getSurfaceControl(), tmpPos.x, tmpPos.y);
- t.setCornerRadius(target.getSurfaceControl(), 0);
- t.setShadowRadius(target.getSurfaceControl(), 0);
+ t.setPosition(targetLeash, tmpPos.x, tmpPos.y);
+ t.setCornerRadius(targetLeash, 0);
+ t.setShadowRadius(targetLeash, 0);
displays.add(target.getDisplayContent());
}
}
@@ -271,12 +278,17 @@
// Commit all going-invisible containers
for (int i = 0; i < mParticipants.size(); ++i) {
final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord();
- if (ar == null || ar.mVisibleRequested) {
- continue;
+ if (ar != null && !ar.isVisibleRequested()) {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ " Commit activity becoming invisible: %s", ar);
+ ar.commitVisibility(false /* visible */, false /* performLayout */);
}
- ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
- " Commit activity becoming invisible: %s", ar);
- ar.commitVisibility(false /* visible */, false /* performLayout */);
+ final WallpaperWindowToken wt = mParticipants.valueAt(i).asWallpaperToken();
+ if (wt != null && !wt.isVisibleRequested()) {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ " Commit wallpaper becoming invisible: %s", ar);
+ wt.commitVisibility(false /* visible */);
+ }
}
}
@@ -455,8 +467,7 @@
final int depth = getChildDepth(topTargets.valueAt(j), sibling);
if (depth < 0) continue;
if (depth == 0) {
- final int siblingMode = sibling.isVisibleRequested()
- ? TRANSIT_OPEN : TRANSIT_CLOSE;
+ final int siblingMode = changes.get(sibling).getTransitMode(sibling);
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
" sibling is a top target with mode %s",
TransitionInfo.modeToString(siblingMode));
@@ -638,6 +649,15 @@
}
}
+ /** Gets the leash surface for a window container */
+ private static SurfaceControl getLeashSurface(WindowContainer wc) {
+ return wc.getSurfaceControl();
+ }
+
+ private static SurfaceControl getOrigParentSurface(WindowContainer wc) {
+ return wc.getParent().getSurfaceControl();
+ }
+
/**
* Construct a TransitionInfo object from a set of targets and changes. Also populates the
* root surface.
@@ -713,7 +733,7 @@
final ChangeInfo info = changes.get(target);
final TransitionInfo.Change change = new TransitionInfo.Change(
target.mRemoteToken != null ? target.mRemoteToken.toWindowContainerToken()
- : null, target.getSurfaceControl());
+ : null, getLeashSurface(target));
// TODO(shell-transitions): Use leash for non-organized windows.
if (info.mParent != null) {
change.setParent(info.mParent.mRemoteToken.toWindowContainerToken());
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 5f46ffe..6338f39 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -69,7 +69,7 @@
* Creates a transition. It can immediately collect participants.
*/
@NonNull
- Transition createTransition(@WindowManager.TransitionOldType int type,
+ Transition createTransition(@WindowManager.TransitionType int type,
@WindowManager.TransitionFlags int flags) {
if (mTransitionPlayer == null) {
throw new IllegalStateException("Shell Transitions not enabled");
@@ -113,6 +113,14 @@
}
/**
+ * @return {@code true} if transition is actively collecting changes and `wc` is one of them.
+ * This is {@code false} once a transition is playing.
+ */
+ boolean isCollecting(@NonNull WindowContainer wc) {
+ return mCollectingTransition != null && mCollectingTransition.mParticipants.contains(wc);
+ }
+
+ /**
* @return {@code true} if transition is actively playing. This is not necessarily {@code true}
* during collection.
*/
@@ -128,9 +136,7 @@
/** @return {@code true} if wc is in a participant subtree */
boolean inTransition(@NonNull WindowContainer wc) {
- if (mCollectingTransition != null && mCollectingTransition.mParticipants.contains(wc)) {
- return true;
- }
+ if (isCollecting(wc)) return true;
for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {
for (WindowContainer p = wc; p != null; p = p.getParent()) {
if (mPlayingTransitions.get(i).mParticipants.contains(p)) {
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 1a3138d..7c5afa8 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -126,12 +126,18 @@
}
mFindResults.resetTopWallpaper = true;
- if (w.mActivityRecord != null && !w.mActivityRecord.isVisible()
- && !w.mActivityRecord.isAnimating(TRANSITION | PARENTS)) {
-
- // If this window's app token is hidden and not animating, it is of no interest to us.
- if (DEBUG_WALLPAPER) Slog.v(TAG, "Skipping hidden and not animating token: " + w);
- return false;
+ if (mService.mAtmService.getTransitionController().getTransitionPlayer() == null) {
+ if (w.mActivityRecord != null && !w.mActivityRecord.isVisible()
+ && !w.mActivityRecord.isAnimating(TRANSITION | PARENTS)) {
+ // If this window's app token is hidden and not animating, it is of no interest.
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Skipping hidden and not animating token: " + w);
+ return false;
+ }
+ } else {
+ if (w.mActivityRecord != null && !w.mActivityRecord.isVisibleRequested()) {
+ // An activity that is not going to remain visible shouldn't be the target.
+ return false;
+ }
}
if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": isOnScreen=" + w.isOnScreen()
+ " mDrawState=" + w.mWinAnimator.mDrawState);
@@ -227,7 +233,10 @@
}
boolean isWallpaperVisible() {
- return isWallpaperVisible(mWallpaperTarget);
+ for (int i = mWallpaperTokens.size() - 1; i >= 0; --i) {
+ if (mWallpaperTokens.get(i).isVisible()) return true;
+ }
+ return false;
}
/**
@@ -240,7 +249,7 @@
}
}
- private boolean isWallpaperVisible(WindowState wallpaperTarget) {
+ private boolean shouldWallpaperBeVisible(WindowState wallpaperTarget) {
if (DEBUG_WALLPAPER) {
Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + " prev="
+ mPrevWallpaperTarget);
@@ -255,18 +264,18 @@
}
void updateWallpaperVisibility() {
- final boolean visible = isWallpaperVisible(mWallpaperTarget);
+ final boolean visible = shouldWallpaperBeVisible(mWallpaperTarget);
for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
- token.updateWallpaperVisibility(visible);
+ token.setVisibility(visible);
}
}
- void hideDeferredWallpapersIfNeeded() {
- if (mDeferredHideWallpaper != null) {
- hideWallpapers(mDeferredHideWallpaper);
- mDeferredHideWallpaper = null;
+ void hideDeferredWallpapersIfNeededLegacy() {
+ for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
+ final WallpaperWindowToken token = mWallpaperTokens.get(i);
+ token.commitVisibility(false);
}
}
@@ -275,18 +284,9 @@
&& (mWallpaperTarget != winGoingAway || mPrevWallpaperTarget != null)) {
return;
}
- if (mWallpaperTarget != null
- && mWallpaperTarget.getDisplayContent().mAppTransition.isRunning()) {
- // Defer hiding the wallpaper when app transition is running until the animations
- // are done.
- mDeferredHideWallpaper = winGoingAway;
- return;
- }
-
- final boolean wasDeferred = (mDeferredHideWallpaper == winGoingAway);
for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
final WallpaperWindowToken token = mWallpaperTokens.get(i);
- token.hideWallpaperToken(wasDeferred, "hideWallpapers");
+ token.setVisibility(false);
if (DEBUG_WALLPAPER_LIGHT && token.isVisible()) {
Slog.d(TAG, "Hiding wallpaper " + token
+ " from " + winGoingAway + " target=" + mWallpaperTarget + " prev="
@@ -616,7 +616,7 @@
// The window is visible to the compositor...but is it visible to the user?
// That is what the wallpaper cares about.
- final boolean visible = mWallpaperTarget != null && isWallpaperVisible(mWallpaperTarget);
+ final boolean visible = mWallpaperTarget != null;
if (DEBUG_WALLPAPER) {
Slog.v(TAG, "Wallpaper visibility: " + visible + " at display "
+ mDisplayContent.getDisplayId());
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 43303d4..717775605 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -19,7 +19,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -34,6 +34,8 @@
import android.view.WindowManager;
import android.view.animation.Animation;
+import com.android.internal.protolog.common.ProtoLog;
+
import java.util.function.Consumer;
/**
@@ -43,6 +45,8 @@
private static final String TAG = TAG_WITH_CLASS_NAME ? "WallpaperWindowToken" : TAG_WM;
+ private boolean mVisibleRequested = false;
+
WallpaperWindowToken(WindowManagerService service, IBinder token, boolean explicit,
DisplayContent dc, boolean ownerCanManageAppTokens) {
this(service, token, explicit, dc, ownerCanManageAppTokens, null /* options */);
@@ -57,18 +61,16 @@
}
@Override
+ WallpaperWindowToken asWallpaperToken() {
+ return this;
+ }
+
+ @Override
void setExiting() {
super.setExiting();
mDisplayContent.mWallpaperController.removeWallpaperToken(this);
}
- void hideWallpaperToken(boolean wasDeferred, String reason) {
- for (int j = mChildren.size() - 1; j >= 0; j--) {
- final WindowState wallpaper = mChildren.get(j);
- wallpaper.hideWallpaperWindow(wasDeferred, reason);
- }
- }
-
void sendWindowWallpaperCommand(
String action, int x, int y, int z, Bundle extras, boolean sync) {
for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
@@ -93,24 +95,6 @@
}
}
- void updateWallpaperVisibility(boolean visible) {
- if (isVisible() != visible) {
- mWmService.mAtmService.getTransitionController().collect(this);
- // Need to do a layout to ensure the wallpaper now has the correct size.
- mDisplayContent.setLayoutNeeded();
- }
-
- final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
- for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
- final WindowState wallpaper = mChildren.get(wallpaperNdx);
- if (visible) {
- wallpaperController.updateWallpaperOffset(wallpaper, false /* sync */);
- }
-
- wallpaper.dispatchWallpaperVisibility(visible);
- }
- }
-
/**
* Starts {@param anim} on all children.
*/
@@ -122,16 +106,16 @@
}
void updateWallpaperWindows(boolean visible) {
-
if (isVisible() != visible) {
if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG,
"Wallpaper token " + token + " visible=" + visible);
- mWmService.mAtmService.getTransitionController().collect(this);
- // Need to do a layout to ensure the wallpaper now has the correct size.
- mDisplayContent.setLayoutNeeded();
+ setVisibility(visible);
+ }
+ final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
+ if (mWmService.mAtmService.getTransitionController().getTransitionPlayer() != null) {
+ return;
}
- final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
final WindowState wallpaperTarget = wallpaperController.getWallpaperTarget();
if (visible && wallpaperTarget != null) {
@@ -153,21 +137,54 @@
}
}
- for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
- final WindowState wallpaper = mChildren.get(wallpaperNdx);
+ setVisible(visible);
+ }
- if (visible) {
- wallpaperController.updateWallpaperOffset(wallpaper, false /* sync */);
+ private void setVisible(boolean visible) {
+ final boolean wasClientVisible = isClientVisible();
+ setClientVisible(visible);
+ if (visible && !wasClientVisible) {
+ for (int i = mChildren.size() - 1; i >= 0; i--) {
+ final WindowState wallpaper = mChildren.get(i);
+ wallpaper.requestUpdateWallpaperIfNeeded();
}
-
- // First, make sure the client has the current visibility state.
- wallpaper.dispatchWallpaperVisibility(visible);
-
- if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win "
- + wallpaper);
}
}
+ /**
+ * Sets the requested visibility of this token. The visibility may not be if this is part of a
+ * transition. In that situation, make sure to call {@link #commitVisibility} when done.
+ */
+ void setVisibility(boolean visible) {
+ // Before setting mVisibleRequested so we can track changes.
+ mWmService.mAtmService.getTransitionController().collect(this);
+
+ setVisibleRequested(visible);
+
+ // If in a transition, defer commits for activities that are going invisible
+ if (!visible && (mWmService.mAtmService.getTransitionController().inTransition()
+ || getDisplayContent().mAppTransition.isRunning())) {
+ return;
+ }
+
+ commitVisibility(visible);
+ }
+
+ /**
+ * Commits the visibility of this token. This will directly update the visibility without
+ * regard for other state (like being in a transition).
+ */
+ void commitVisibility(boolean visible) {
+ if (visible == isVisible()) return;
+
+ ProtoLog.v(WM_DEBUG_WINDOW_TRANSITIONS,
+ "commitVisibility: %s: visible=%b mVisibleRequested=%b", this,
+ isVisible(), mVisibleRequested);
+
+ setVisibleRequested(visible);
+ setVisible(visible);
+ }
+
@Override
void adjustWindowParams(WindowState win, WindowManager.LayoutParams attrs) {
if (attrs.height == ViewGroup.LayoutParams.MATCH_PARENT
@@ -186,9 +203,10 @@
}
boolean hasVisibleNotDrawnWallpaper() {
+ if (!isVisible()) return false;
for (int j = mChildren.size() - 1; j >= 0; --j) {
final WindowState wallpaper = mChildren.get(j);
- if (wallpaper.hasVisibleNotDrawnWallpaper()) {
+ if (!wallpaper.isDrawn() && wallpaper.isVisible()) {
return true;
}
}
@@ -210,6 +228,21 @@
return false;
}
+ void setVisibleRequested(boolean visible) {
+ if (mVisibleRequested == visible) return;
+ mVisibleRequested = visible;
+ setInsetsFrozen(!visible);
+ }
+
+ @Override
+ boolean isVisibleRequested() {
+ return mVisibleRequested;
+ }
+
+ @Override
+ boolean isVisible() {
+ return isClientVisible();
+ }
@Override
public String toString() {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 000889a..0c4ff2f 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -3060,6 +3060,11 @@
}
/** Cheap way of doing cast and instanceof. */
+ WallpaperWindowToken asWallpaperToken() {
+ return null;
+ }
+
+ /** Cheap way of doing cast and instanceof. */
DisplayArea asDisplayArea() {
return null;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 70b0f58..04a560b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -463,12 +463,12 @@
private static final int ANIMATION_COMPLETED_TIMEOUT_MS = 5000;
/**
- * Override of task letterbox aspect ratio that is set via ADB with
- * set-task-letterbox-aspect-ratio or via {@link
- * com.android.internal.R.dimen.config_taskLetterboxAspectRatio} will be ignored
+ * Override of aspect ratio for fixed orientation letterboxing that is set via ADB with
+ * set-fixed-orientation-letterbox-aspect-ratio or via {@link
+ * com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio} will be ignored
* if it is <= this value.
*/
- static final float MIN_TASK_LETTERBOX_ASPECT_RATIO = 1.0f;
+ static final float MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO = 1.0f;
@VisibleForTesting
WindowManagerConstants mConstants;
@@ -1003,9 +1003,9 @@
private boolean mAnimationsDisabled = false;
boolean mPointerLocationEnabled = false;
- // Aspect ratio of task level letterboxing, values <= MIN_TASK_LETTERBOX_ASPECT_RATIO will be
- // ignored.
- private volatile float mTaskLetterboxAspectRatio;
+ // Aspect ratio of letterbox for fixed orientation, values <=
+ // MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO will be ignored.
+ private volatile float mFixedOrientationLetterboxAspectRatio;
/** Enum for Letterbox background type. */
@Retention(RetentionPolicy.SOURCE)
@@ -1256,8 +1256,8 @@
mAssistantOnTopOfDream = context.getResources().getBoolean(
com.android.internal.R.bool.config_assistantOnTopOfDream);
- mTaskLetterboxAspectRatio = context.getResources().getFloat(
- com.android.internal.R.dimen.config_taskLetterboxAspectRatio);
+ mFixedOrientationLetterboxAspectRatio = context.getResources().getFloat(
+ com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio);
mLetterboxActivityCornersRadius = context.getResources().getInteger(
com.android.internal.R.integer.config_letterboxActivityCornersRadius);
mLetterboxBackgroundColor = Color.valueOf(context.getResources().getColor(
@@ -3853,29 +3853,29 @@
}
/**
- * Overrides the aspect ratio of task level letterboxing. If given value is <= {@link
- * #MIN_TASK_LETTERBOX_ASPECT_RATIO}, both it and a value of {@link
- * com.android.internal.R.dimen.config_taskLetterboxAspectRatio} will be ignored and
+ * Overrides the aspect ratio of letterbox for fixed orientation. If given value is <= {@link
+ * #MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO}, both it and a value of {@link
+ * com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio} will be ignored and
* the framework implementation will be used to determine the aspect ratio.
*/
- void setTaskLetterboxAspectRatio(float aspectRatio) {
- mTaskLetterboxAspectRatio = aspectRatio;
+ void setFixedOrientationLetterboxAspectRatio(float aspectRatio) {
+ mFixedOrientationLetterboxAspectRatio = aspectRatio;
}
/**
- * Resets the aspect ratio of task level letterboxing to {@link
- * com.android.internal.R.dimen.config_taskLetterboxAspectRatio}.
+ * Resets the aspect ratio of letterbox for fixed orientation to {@link
+ * com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio}.
*/
- void resetTaskLetterboxAspectRatio() {
- mTaskLetterboxAspectRatio = mContext.getResources().getFloat(
- com.android.internal.R.dimen.config_taskLetterboxAspectRatio);
+ void resetFixedOrientationLetterboxAspectRatio() {
+ mFixedOrientationLetterboxAspectRatio = mContext.getResources().getFloat(
+ com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio);
}
/**
- * Gets the aspect ratio of task level letterboxing.
+ * Gets the aspect ratio of letterbox for fixed orientation.
*/
- float getTaskLetterboxAspectRatio() {
- return mTaskLetterboxAspectRatio;
+ float getFixedOrientationLetterboxAspectRatio() {
+ return mFixedOrientationLetterboxAspectRatio;
}
/**
@@ -3971,6 +3971,21 @@
? backgroundType : LETTERBOX_BACKGROUND_SOLID_COLOR;
}
+ /** Returns a string representing the given {@link LetterboxBackgroundType}. */
+ static String letterboxBackgroundTypeToString(
+ @LetterboxBackgroundType int backgroundType) {
+ switch (backgroundType) {
+ case LETTERBOX_BACKGROUND_SOLID_COLOR:
+ return "LETTERBOX_BACKGROUND_SOLID_COLOR";
+ case LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND:
+ return "LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND";
+ case LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING:
+ return "LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING";
+ default:
+ return "unknown=" + backgroundType;
+ }
+ }
+
@Override
public void setIgnoreOrientationRequest(int displayId, boolean ignoreOrientationRequest) {
if (!checkCallingPermission(
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 645786c..a46a8d5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -117,10 +117,10 @@
return runGetIgnoreOrientationRequest(pw);
case "dump-visible-window-views":
return runDumpVisibleWindowViews(pw);
- case "set-task-letterbox-aspect-ratio":
- return runSetTaskLetterboxAspectRatio(pw);
- case "get-task-letterbox-aspect-ratio":
- return runGetTaskLetterboxAspectRatio(pw);
+ case "set-fixed-orientation-letterbox-aspect-ratio":
+ return runSetFixedOrientationLetterboxAspectRatio(pw);
+ case "get-fixed-orientation-letterbox-aspect-ratio":
+ return runGetFixedOrientationLetterboxAspectRatio(pw);
case "set-letterbox-activity-corners-radius":
return runSetLetterboxActivityCornersRadius(pw);
case "get-letterbox-activity-corners-radius":
@@ -531,12 +531,12 @@
return 0;
}
- private int runSetTaskLetterboxAspectRatio(PrintWriter pw) throws RemoteException {
+ private int runSetFixedOrientationLetterboxAspectRatio(PrintWriter pw) throws RemoteException {
final float aspectRatio;
try {
String arg = getNextArgRequired();
if ("reset".equals(arg)) {
- mInternal.resetTaskLetterboxAspectRatio();
+ mInternal.resetFixedOrientationLetterboxAspectRatio();
return 0;
}
aspectRatio = Float.parseFloat(arg);
@@ -549,13 +549,13 @@
return -1;
}
- mInternal.setTaskLetterboxAspectRatio(aspectRatio);
+ mInternal.setFixedOrientationLetterboxAspectRatio(aspectRatio);
return 0;
}
- private int runGetTaskLetterboxAspectRatio(PrintWriter pw) throws RemoteException {
- final float aspectRatio = mInternal.getTaskLetterboxAspectRatio();
- if (aspectRatio <= WindowManagerService.MIN_TASK_LETTERBOX_ASPECT_RATIO) {
+ private int runGetFixedOrientationLetterboxAspectRatio(PrintWriter pw) throws RemoteException {
+ final float aspectRatio = mInternal.getFixedOrientationLetterboxAspectRatio();
+ if (aspectRatio <= WindowManagerService.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO) {
pw.println("Letterbox aspect ratio is not set");
} else {
pw.println("Letterbox aspect ratio is " + aspectRatio);
@@ -692,8 +692,8 @@
// set-ignore-orientation-request
mInterface.setIgnoreOrientationRequest(displayId, false /* ignoreOrientationRequest */);
- // set-task-letterbox-aspect-ratio
- mInternal.resetTaskLetterboxAspectRatio();
+ // set-fixed-orientation-letterbox-aspect-ratio
+ mInternal.resetFixedOrientationLetterboxAspectRatio();
// set-letterbox-activity-corners-radius
mInternal.resetLetterboxActivityCornersRadius();
@@ -734,12 +734,12 @@
pw.println(" set-ignore-orientation-request [-d DISPLAY_ID] [true|1|false|0]");
pw.println(" get-ignore-orientation-request [-d DISPLAY_ID] ");
pw.println(" If app requested orientation should be ignored.");
- pw.println(" set-task-letterbox-aspect-ratio [reset|aspectRatio]");
- pw.println(" get-task-letterbox-aspect-ratio");
- pw.println(" Aspect ratio of task level letterboxing. If aspectRatio <= "
- + WindowManagerService.MIN_TASK_LETTERBOX_ASPECT_RATIO);
- pw.println(" both it and R.dimen.config_taskLetterboxAspectRatio will be ignored");
- pw.println(" and framework implementation will be used to determine aspect ratio.");
+ pw.println(" set-fixed-orientation-letterbox-aspect-ratio [reset|aspectRatio]");
+ pw.println(" get-fixed-orientation-letterbox-aspect-ratio");
+ pw.println(" Aspect ratio of letterbox for fixed orientation. If aspectRatio <= "
+ + WindowManagerService.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO);
+ pw.println(" both it and R.dimen.config_fixedOrientationLetterboxAspectRatio will be");
+ pw.println(" ignored and framework implementation will determine aspect ratio.");
pw.println(" set-letterbox-activity-corners-radius [reset|cornersRadius]");
pw.println(" get-letterbox-activity-corners-radius");
pw.println(" Corners radius for activities in the letterbox mode. If radius < 0,");
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index fec715e..1830c07 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -141,11 +141,9 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.WINDOW_STATE_BLAST_SYNC_TIMEOUT;
@@ -358,7 +356,6 @@
private boolean mForceHideNonSystemOverlayWindow;
boolean mAppFreezing;
boolean mHidden = true; // Used to determine if to show child windows.
- boolean mWallpaperVisible; // for wallpaper, what was last vis report?
private boolean mDragResizing;
private boolean mDragResizingChangeReported = true;
private int mResizeMode;
@@ -1715,7 +1712,11 @@
@Override
boolean isVisibleRequested() {
- return isVisible() && (mActivityRecord == null || mActivityRecord.isVisibleRequested());
+ if (mToken != null && (mActivityRecord != null || mToken.asWallpaperToken() != null)) {
+ // Currently only ActivityRecord and WallpaperToken support visibleRequested.
+ return isVisible() && mToken.isVisibleRequested();
+ }
+ return isVisible();
}
/**
@@ -1745,8 +1746,11 @@
* {@code false} otherwise.
*/
boolean wouldBeVisibleIfPolicyIgnored() {
- return mHasSurface && !isParentWindowHidden()
- && !mAnimatingExit && !mDestroying && (!mIsWallpaper || mWallpaperVisible);
+ if (!mHasSurface || isParentWindowHidden() || mAnimatingExit || mDestroying) {
+ return false;
+ }
+ final boolean isWallpaper = mToken != null && mToken.asWallpaperToken() != null;
+ return !isWallpaper || mToken.isVisible();
}
/**
@@ -1804,6 +1808,10 @@
return ((!isParentWindowHidden() && atoken.isVisible())
|| isAnimating(TRANSITION | PARENTS));
}
+ final WallpaperWindowToken wtoken = mToken.asWallpaperToken();
+ if (wtoken != null) {
+ return !isParentWindowHidden() && wtoken.isVisible();
+ }
return !isParentWindowHidden() || isAnimating(TRANSITION | PARENTS);
}
@@ -1943,8 +1951,9 @@
// When there is keyguard, wallpaper could be placed over the secure app
// window but invisible. We need to check wallpaper visibility explicitly
// to determine if it's occluding apps.
- return ((!mIsWallpaper && mAttrs.format == PixelFormat.OPAQUE)
- || (mIsWallpaper && mWallpaperVisible))
+ final boolean isWallpaper = mToken != null && mToken.asWallpaperToken() != null;
+ return ((!isWallpaper && mAttrs.format == PixelFormat.OPAQUE)
+ || (isWallpaper && mToken.isVisible()))
&& isDrawn() && !isAnimating(TRANSITION | PARENTS);
}
@@ -3224,7 +3233,11 @@
void sendAppVisibilityToClients() {
super.sendAppVisibilityToClients();
- final boolean clientVisible = mActivityRecord.isClientVisible();
+ if (mToken == null) return;
+
+ final boolean clientVisible = mToken.isClientVisible();
+ // TODO(shell-transitions): This is currently only applicable to app windows, BUT we
+ // want to extend the "starting" concept to other windows.
if (mAttrs.type == TYPE_APPLICATION_STARTING && !clientVisible) {
// Don't hide the starting window.
return;
@@ -3608,9 +3621,11 @@
if (mActivityRecord != null && mActivityRecord.isRelaunching()) {
return;
}
- // If the activity is invisible or going invisible, don't report either since it is going
- // away. This is likely during a transition so we want to preserve the original state.
- if (mActivityRecord != null && !mActivityRecord.isVisibleRequested()) {
+ // If this is an activity or wallpaper and is invisible or going invisible, don't report
+ // either since it is going away. This is likely during a transition so we want to preserve
+ // the original state.
+ if ((mActivityRecord != null || mToken.asWallpaperToken() != null)
+ && !mToken.isVisibleRequested()) {
return;
}
@@ -4024,8 +4039,7 @@
if (mIsImWindow || mIsWallpaper || mIsFloatingLayer) {
pw.println(prefix + "mIsImWindow=" + mIsImWindow
+ " mIsWallpaper=" + mIsWallpaper
- + " mIsFloatingLayer=" + mIsFloatingLayer
- + " mWallpaperVisible=" + mWallpaperVisible);
+ + " mIsFloatingLayer=" + mIsFloatingLayer);
}
if (dumpAll) {
pw.print(prefix); pw.print("mBaseLayer="); pw.print(mBaseLayer);
@@ -4839,61 +4853,6 @@
return getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
}
- void hideWallpaperWindow(boolean wasDeferred, String reason) {
- for (int j = mChildren.size() - 1; j >= 0; --j) {
- final WindowState c = mChildren.get(j);
- c.hideWallpaperWindow(wasDeferred, reason);
- }
- if (!mWinAnimator.mLastHidden || wasDeferred) {
- mWinAnimator.hide(getGlobalTransaction(), reason);
- getDisplayContent().mWallpaperController.mDeferredHideWallpaper = null;
- dispatchWallpaperVisibility(false);
- final DisplayContent displayContent = getDisplayContent();
- if (displayContent != null) {
- displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- if (DEBUG_LAYOUT_REPEATS) {
- mWmService.mWindowPlacerLocked.debugLayoutRepeats("hideWallpaperWindow " + this,
- displayContent.pendingLayoutChanges);
- }
- }
- }
- }
-
- /**
- * Check wallpaper window for visibility change and notify window if so.
- * @param visible Current visibility.
- */
- void dispatchWallpaperVisibility(final boolean visible) {
- final boolean hideAllowed =
- getDisplayContent().mWallpaperController.mDeferredHideWallpaper == null;
-
- // Only send notification if the visibility actually changed and we are not trying to hide
- // the wallpaper when we are deferring hiding of the wallpaper.
- if (mWallpaperVisible != visible && (hideAllowed || visible)) {
- mWallpaperVisible = visible;
- try {
- if (DEBUG_VISIBILITY || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
- "Updating vis of wallpaper " + this
- + ": " + visible + " from:\n" + Debug.getCallers(4, " "));
- mClient.dispatchAppVisibility(visible);
- } catch (RemoteException e) {
- }
- }
- }
-
- boolean hasVisibleNotDrawnWallpaper() {
- if (mWallpaperVisible && !isDrawn()) {
- return true;
- }
- for (int j = mChildren.size() - 1; j >= 0; --j) {
- final WindowState c = mChildren.get(j);
- if (c.hasVisibleNotDrawnWallpaper()) {
- return true;
- }
- }
- return false;
- }
-
void updateReportedVisibility(UpdateReportedVisibilityResults results) {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = mChildren.get(i);
@@ -5246,7 +5205,7 @@
mIsDimming = true;
final float dimAmount = (mAttrs.flags & FLAG_DIM_BEHIND) != 0 ? mAttrs.dimAmount : 0;
final int blurRadius = shouldDrawBlurBehind() ? mAttrs.getBlurBehindRadius() : 0;
- getDimmer().dimBelow(getSyncTransaction(), this, mAttrs.dimAmount, blurRadius);
+ getDimmer().dimBelow(getSyncTransaction(), this, dimAmount, blurRadius);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index ece256e..ebbebbb 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -57,7 +57,6 @@
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Rect;
-import android.graphics.Region;
import android.os.Debug;
import android.os.Trace;
import android.util.Slog;
@@ -575,10 +574,7 @@
setSurfaceBoundariesLocked(t);
- if (mIsWallpaper && !w.mWallpaperVisible) {
- // Wallpaper is no longer visible and there is no wp target => hide it.
- hide(t, "prepareSurfaceLocked");
- } else if (w.isParentWindowHidden() || !w.isOnScreen()) {
+ if (w.isParentWindowHidden() || !w.isOnScreen()) {
hide(t, "prepareSurfaceLocked");
mWallpaperControllerLocked.hideWallpapers(w);
@@ -631,9 +627,6 @@
if (showSurfaceRobustlyLocked(t)) {
mAnimator.requestRemovalOfReplacedWindows(w);
mLastHidden = false;
- if (mIsWallpaper) {
- w.dispatchWallpaperVisibility(true);
- }
final DisplayContent displayContent = w.getDisplayContent();
if (!displayContent.getLastHasContent()) {
// This draw means the difference between unique content and mirroring.
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 066cc1e..8867aa7 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -22,6 +22,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
@@ -112,6 +113,9 @@
*/
private final boolean mFromClientToken;
+ /** Have we told the window clients to show themselves? */
+ private boolean mClientVisible;
+
/**
* Used to fix the transform of the token to be rotated to a rotation different than it's
* display. The window frames and surfaces corresponding to this token will be layouted and
@@ -397,6 +401,21 @@
return builder;
}
+ boolean isClientVisible() {
+ return mClientVisible;
+ }
+
+ void setClientVisible(boolean clientVisible) {
+ if (mClientVisible == clientVisible) {
+ return;
+ }
+ ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+ "setClientVisible: %s clientVisible=%b Callers=%s", this, clientVisible,
+ Debug.getCallers(5));
+ mClientVisible = clientVisible;
+ sendAppVisibilityToClients();
+ }
+
boolean hasFixedRotationTransform() {
return mFixedRotationTransformState != null;
}
diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
index 7b78b8d..8efbaf5 100644
--- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
+++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
@@ -39,6 +39,8 @@
#include "dataloader.h"
+// #define VERBOSE_READ_LOGS
+
namespace android {
namespace {
@@ -631,28 +633,65 @@
};
void onPageReadsWithUid(dataloader::PageReadsWithUid pageReads) final {
+ if (!pageReads.size()) {
+ return;
+ }
+
auto trace = atrace_is_tag_enabled(ATRACE_TAG);
if (CC_LIKELY(!trace)) {
return;
}
TracedRead last = {};
+ auto lastSerialNo = mLastSerialNo;
for (auto&& read : pageReads) {
- if (read.id != last.fileId || read.uid != last.uid ||
- read.block != last.firstBlockIdx + last.count) {
- traceRead(last);
- last = TracedRead{
- .timestampUs = read.bootClockTsUs,
- .fileId = read.id,
- .uid = read.uid,
- .firstBlockIdx = (uint32_t)read.block,
- .count = 1,
- };
- } else {
- ++last.count;
+ const auto expectedSerialNo = lastSerialNo + last.count;
+#ifdef VERBOSE_READ_LOGS
+ {
+ FileIdx fileIdx = convertFileIdToFileIndex(read.id);
+
+ auto appId = multiuser_get_app_id(read.uid);
+ auto userId = multiuser_get_user_id(read.uid);
+ auto trace = android::base::
+ StringPrintf("verbose_page_read: serialNo=%lld (expected=%lld) index=%lld "
+ "file=%d appid=%d userid=%d",
+ static_cast<long long>(read.serialNo),
+ static_cast<long long>(expectedSerialNo),
+ static_cast<long long>(read.block), static_cast<int>(fileIdx),
+ static_cast<int>(appId), static_cast<int>(userId));
+
+ ATRACE_BEGIN(trace.c_str());
+ ATRACE_END();
}
+#endif // VERBOSE_READ_LOGS
+
+ if (read.serialNo == expectedSerialNo && read.id == last.fileId &&
+ read.uid == last.uid && read.block == last.firstBlockIdx + last.count) {
+ ++last.count;
+ continue;
+ }
+
+ // First, trace the reads.
+ traceRead(last);
+
+ // Second, report missing reads, if any.
+ if (read.serialNo != expectedSerialNo) {
+ const auto readsMissing = read.serialNo - expectedSerialNo;
+ traceMissingReads(readsMissing);
+ }
+
+ last = TracedRead{
+ .timestampUs = read.bootClockTsUs,
+ .fileId = read.id,
+ .uid = read.uid,
+ .firstBlockIdx = (uint32_t)read.block,
+ .count = 1,
+ };
+ lastSerialNo = read.serialNo;
}
+
traceRead(last);
+ mLastSerialNo = lastSerialNo + last.count;
}
void traceRead(const TracedRead& read) {
@@ -682,6 +721,13 @@
ATRACE_END();
}
+ void traceMissingReads(int64_t count) {
+ const auto trace = android::base::StringPrintf("missing_page_reads: count=%lld",
+ static_cast<long long>(count));
+ ATRACE_BEGIN(trace.c_str());
+ ATRACE_END();
+ }
+
void receiver(unique_fd inout, MetadataMode mode) {
std::vector<uint8_t> data;
std::vector<IncFsDataBlock> instructions;
@@ -828,6 +874,7 @@
std::atomic<bool> mStopReceiving = false;
std::atomic<bool> mReadLogsEnabled = false;
std::chrono::milliseconds mWaitOnEofInterval{WaitOnEofMinInterval};
+ int64_t mLastSerialNo{1};
/** Tracks which files have been requested */
std::unordered_set<FileIdx> mRequestedFiles;
};
diff --git a/services/core/jni/com_android_server_vibrator_VibratorController.cpp b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
index 89b931d..ef2d0ba 100644
--- a/services/core/jni/com_android_server_vibrator_VibratorController.cpp
+++ b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
@@ -238,12 +238,12 @@
return result.isOk() ? result.value().count() : -1;
}
-static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong ptr,
- jobjectArray composition, jlong vibrationId) {
+static jlong vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong ptr,
+ jobjectArray composition, jlong vibrationId) {
VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
if (wrapper == nullptr) {
ALOGE("vibratorPerformComposedEffect failed because native wrapper was not initialized");
- return;
+ return -1;
}
size_t size = env->GetArrayLength(composition);
std::vector<aidl::CompositeEffect> effects;
@@ -252,7 +252,8 @@
effects.push_back(effectFromJavaPrimitive(env, element));
}
auto callback = wrapper->createCallback(vibrationId);
- wrapper->hal()->performComposedEffect(effects, callback);
+ auto result = wrapper->hal()->performComposedEffect(effects, callback);
+ return result.isOk() ? result.value().count() : -1;
}
static jlong vibratorGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong ptr) {
@@ -296,7 +297,7 @@
{"vibratorSetAmplitude", "(JI)V", (void*)vibratorSetAmplitude},
{"vibratorPerformEffect", "(JJJJ)J", (void*)vibratorPerformEffect},
{"vibratorPerformComposedEffect",
- "(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;J)V",
+ "(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;J)J",
(void*)vibratorPerformComposedEffect},
{"vibratorGetSupportedEffects", "(J)[I", (void*)vibratorGetSupportedEffects},
{"vibratorGetSupportedPrimitives", "(J)[I", (void*)vibratorGetSupportedPrimitives},
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index ef7afc8..cdd5a92b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -143,4 +143,14 @@
public boolean canAdminGrantSensorsPermissionsForUser(int userId) {
return false;
}
+
+ @Override
+ public boolean setKeyGrantToWifiAuth(String callerPackage, String alias, boolean hasGrant) {
+ return false;
+ }
+
+ @Override
+ public boolean isKeyPairGrantedToWifiAuth(String callerPackage, String alias) {
+ return false;
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 28e9acf..79ae359 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1583,8 +1583,7 @@
}
public String[] getPersonalAppsForSuspension(int userId) {
- return new PersonalAppsSuspensionHelper(
- mContext.createContextAsUser(UserHandle.of(userId), 0 /* flags */))
+ return PersonalAppsSuspensionHelper.forUser(mContext, userId)
.getPersonalAppsForSuspension();
}
@@ -1599,6 +1598,10 @@
void setDevicePolicySafetyChecker(DevicePolicySafetyChecker safetyChecker) {
mSafetyChecker = safetyChecker;
}
+
+ void dumpPerUserData(IndentingPrintWriter pw, @UserIdInt int userId) {
+ PersonalAppsSuspensionHelper.forUser(mContext, userId).dump(pw);
+ }
}
/**
@@ -5458,6 +5461,42 @@
}
@Override
+ public boolean setKeyGrantToWifiAuth(String callerPackage, String alias, boolean hasGrant) {
+ Preconditions.checkStringNotEmpty(alias, "Alias to grant cannot be empty");
+
+ final CallerIdentity caller = getCallerIdentity(callerPackage);
+ Preconditions.checkCallAuthorization(canManageCertificates(caller));
+
+ return setKeyChainGrantInternal(alias, hasGrant, Process.WIFI_UID, caller.getUserHandle());
+ }
+
+ @Override
+ public boolean isKeyPairGrantedToWifiAuth(String callerPackage, String alias) {
+ Preconditions.checkStringNotEmpty(alias, "Alias to check cannot be empty");
+
+ final CallerIdentity caller = getCallerIdentity(callerPackage);
+ Preconditions.checkCallAuthorization(canManageCertificates(caller));
+
+ return mInjector.binderWithCleanCallingIdentity(() -> {
+ try (KeyChainConnection keyChainConnection =
+ KeyChain.bindAsUser(mContext, caller.getUserHandle())) {
+ final List<String> result = new ArrayList<>();
+ final int[] granteeUids = keyChainConnection.getService().getGrants(alias);
+
+ for (final int uid : granteeUids) {
+ if (uid == Process.WIFI_UID) {
+ return true;
+ }
+ }
+ return false;
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Querying grant to wifi auth. ", e);
+ return false;
+ }
+ });
+ }
+
+ @Override
public boolean setKeyGrantForApp(ComponentName who, String callerPackage, String alias,
String packageName, boolean hasGrant) {
Preconditions.checkStringNotEmpty(alias, "Alias to grant cannot be empty");
@@ -5479,19 +5518,21 @@
throw new IllegalStateException("Failure getting grantee uid", e);
}
+ return setKeyChainGrantInternal(alias, hasGrant, granteeUid, caller.getUserHandle());
+ }
+
+ private boolean setKeyChainGrantInternal(String alias, boolean hasGrant, int granteeUid,
+ UserHandle userHandle) {
final long id = mInjector.binderClearCallingIdentity();
try {
- final KeyChainConnection keyChainConnection =
- KeyChain.bindAsUser(mContext, caller.getUserHandle());
- try {
+ try (KeyChainConnection keyChainConnection =
+ KeyChain.bindAsUser(mContext, userHandle)) {
IKeyChainService keyChain = keyChainConnection.getService();
keyChain.setGrant(granteeUid, alias, hasGrant);
return true;
} catch (RemoteException e) {
Log.e(LOG_TAG, "Setting grant for package.", e);
- return false;
- } finally {
- keyChainConnection.close();
+ return false;
}
} catch (InterruptedException e) {
Log.w(LOG_TAG, "Interrupted while setting key grant", e);
@@ -9161,11 +9202,17 @@
}
}
- private void dumpDevicePolicyData(IndentingPrintWriter pw) {
+ private void dumpPerUserData(IndentingPrintWriter pw) {
int userCount = mUserData.size();
- for (int u = 0; u < userCount; u++) {
- DevicePolicyData policy = getUserData(mUserData.keyAt(u));
+ for (int userId = 0; userId < userCount; userId++) {
+ DevicePolicyData policy = getUserData(mUserData.keyAt(userId));
policy.dump(pw);
+ pw.println();
+
+ pw.increaseIndent();
+ mInjector.dumpPerUserData(pw, userId);
+ pw.decreaseIndent();
+ pw.println();
}
}
@@ -9183,7 +9230,7 @@
pw.println();
mDeviceAdminServiceController.dump(pw);
pw.println();
- dumpDevicePolicyData(pw);
+ dumpPerUserData(pw);
pw.println();
mConstants.dump(pw);
pw.println();
@@ -9229,20 +9276,30 @@
pw.increaseIndent();
dumpResources(pw, mContext, "cross_profile_apps", R.array.cross_profile_apps);
dumpResources(pw, mContext, "vendor_cross_profile_apps", R.array.vendor_cross_profile_apps);
+ dumpResources(pw, mContext, "config_packagesExemptFromSuspension",
+ R.array.config_packagesExemptFromSuspension);
pw.decreaseIndent();
pw.println();
}
static void dumpResources(IndentingPrintWriter pw, Context context, String resName, int resId) {
- String[] apps = context.getResources().getStringArray(resId);
- if (apps == null || apps.length == 0) {
- pw.printf("%s: empty\n", resName);
+ dumpApps(pw, resName, context.getResources().getStringArray(resId));
+ }
+
+ static void dumpApps(IndentingPrintWriter pw, String name, String[] apps) {
+ dumpApps(pw, name, Arrays.asList(apps));
+ }
+
+ static void dumpApps(IndentingPrintWriter pw, String name, List apps) {
+ if (apps == null || apps.isEmpty()) {
+ pw.printf("%s: empty\n", name);
return;
}
- pw.printf("%s: %d app%s\n", resName, apps.length, apps.length == 1 ? "" : "s");
+ int size = apps.size();
+ pw.printf("%s: %d app%s\n", name, size, size == 1 ? "" : "s");
pw.increaseIndent();
- for (int i = 0; i < apps.length; i++) {
- pw.printf("%d: %s\n", i, apps[i]);
+ for (int i = 0; i < size; i++) {
+ pw.printf("%d: %s\n", i, apps.get(i));
}
pw.decreaseIndent();
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
index c6871842..37dbfc1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PersonalAppsSuspensionHelper.java
@@ -20,6 +20,7 @@
import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -29,10 +30,12 @@
import android.content.pm.ResolveInfo;
import android.os.IBinder;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Telephony;
import android.text.TextUtils;
import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
@@ -49,7 +52,7 @@
/**
* Utility class to find what personal apps should be suspended to limit personal device use.
*/
-public class PersonalAppsSuspensionHelper {
+public final class PersonalAppsSuspensionHelper {
private static final String LOG_TAG = DevicePolicyManagerService.LOG_TAG;
// Flags to get all packages even if the user is still locked.
@@ -60,9 +63,17 @@
private final PackageManager mPackageManager;
/**
+ * Factory method
+ */
+ public static PersonalAppsSuspensionHelper forUser(Context context, @UserIdInt int userId) {
+ return new PersonalAppsSuspensionHelper(context.createContextAsUser(UserHandle.of(userId),
+ /* flags= */ 0));
+ }
+
+ /**
* @param context Context for the user whose apps should to be suspended.
*/
- public PersonalAppsSuspensionHelper(Context context) {
+ private PersonalAppsSuspensionHelper(Context context) {
mContext = context;
mPackageManager = context.getPackageManager();
}
@@ -181,4 +192,21 @@
iBinder == null ? null : IAccessibilityManager.Stub.asInterface(iBinder);
return new AccessibilityManager(mContext, service, userId);
}
+
+ void dump(IndentingPrintWriter pw) {
+ pw.println("PersonalAppsSuspensionHelper");
+ pw.increaseIndent();
+
+ DevicePolicyManagerService.dumpApps(pw, "critical packages", getCriticalPackages());
+ DevicePolicyManagerService.dumpApps(pw, "launcher packages", getSystemLauncherPackages());
+ DevicePolicyManagerService.dumpApps(pw, "accessibility services",
+ getAccessibilityServices());
+ DevicePolicyManagerService.dumpApps(pw, "input method packages", getInputMethodPackages());
+ pw.printf("SMS package: %s\n", Telephony.Sms.getDefaultSmsPackage(mContext));
+ pw.printf("Settings package: %s\n", getSettingsPackageName());
+ DevicePolicyManagerService.dumpApps(pw, "Packages subject to suspension",
+ getPersonalAppsForSuspension());
+
+ pw.decreaseIndent();
+ }
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a3d3353..5fbf1c4 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -53,7 +53,6 @@
import android.hardware.display.DisplayManagerInternal;
import android.net.ConnectivityManager;
import android.net.ConnectivityModuleConnector;
-import android.net.IConnectivityManager;
import android.net.NetworkStackClient;
import android.os.BaseBundle;
import android.os.Binder;
@@ -1307,7 +1306,6 @@
VcnManagementService vcnManagement = null;
NetworkStatsService networkStats = null;
NetworkPolicyManagerService networkPolicy = null;
- IConnectivityManager connectivity = null;
NsdService serviceDiscovery = null;
WindowManagerService wm = null;
SerialService serial = null;
@@ -1882,10 +1880,7 @@
// services to initialize.
mSystemServiceManager.startServiceFromJar(CONNECTIVITY_SERVICE_INITIALIZER_CLASS,
CONNECTIVITY_SERVICE_APEX_PATH);
- connectivity = IConnectivityManager.Stub.asInterface(
- ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
- // TODO: Use ConnectivityManager instead of ConnectivityService.
- networkPolicy.bindConnectivityManager(connectivity);
+ networkPolicy.bindConnectivityManager();
t.traceEnd();
t.traceBegin("StartVpnManagerService");
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCoreApiTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCoreApiTest.kt
index 9447f39..8ef9239 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCoreApiTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCoreApiTest.kt
@@ -19,7 +19,7 @@
import android.content.pm.verify.domain.DomainSet
import android.content.pm.verify.domain.DomainVerificationInfo
import android.content.pm.verify.domain.DomainVerificationRequest
-import android.content.pm.verify.domain.DomainVerificationUserSelection
+import android.content.pm.verify.domain.DomainVerificationUserState
import android.os.Parcel
import android.os.Parcelable
import android.os.UserHandle
@@ -28,7 +28,6 @@
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import java.util.UUID
-import kotlin.random.Random
@RunWith(Parameterized::class)
class DomainVerificationCoreApiTest {
@@ -92,9 +91,9 @@
}
),
Parameter(
- testName = "DomainVerificationUserSelection",
+ testName = "DomainVerificationUserState",
initial = {
- DomainVerificationUserSelection(
+ DomainVerificationUserState(
UUID.fromString("703f6d34-6241-4cfd-8176-2e1d23355811"),
"com.test.pkg",
UserHandle.of(10),
@@ -103,22 +102,22 @@
.associate { it.value to (it.index % 3) }
)
},
- unparcel = { DomainVerificationUserSelection.CREATOR.createFromParcel(it) },
+ unparcel = { DomainVerificationUserState.CREATOR.createFromParcel(it) },
assertion = { first, second ->
- assertAll<DomainVerificationUserSelection, UUID>(first, second,
+ assertAll<DomainVerificationUserState, UUID>(first, second,
{ it.identifier }, { it.component1() }, IS_EQUAL_TO
)
- assertAll<DomainVerificationUserSelection, String>(first, second,
+ assertAll<DomainVerificationUserState, String>(first, second,
{ it.packageName }, { it.component2() }, IS_EQUAL_TO
)
- assertAll<DomainVerificationUserSelection, UserHandle>(first, second,
+ assertAll<DomainVerificationUserState, UserHandle>(first, second,
{ it.user }, { it.component3() }, IS_EQUAL_TO
)
- assertAll<DomainVerificationUserSelection, Boolean>(
+ assertAll<DomainVerificationUserState, Boolean>(
first, second, { it.isLinkHandlingAllowed },
{ it.component4() }, IS_EQUAL_TO
)
- assertAll<DomainVerificationUserSelection, Map<String, Int>>(
+ assertAll<DomainVerificationUserState, Map<String, Int>>(
first, second, { it.hostToStateMap },
{ it.component5() }, IS_MAP_EQUAL_TO
)
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
index 89394837..53f0ca2 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
@@ -155,6 +155,15 @@
assertApprovedVerifier(it.callingUid, it.proxy)
},
enforcer(
+ Type.SELECTION_QUERENT,
+ "approvedUserStateQuerent"
+ ) {
+ assertApprovedUserStateQuerent(
+ it.callingUid, it.callingUserId,
+ it.targetPackageName, it.userId
+ )
+ },
+ enforcer(
Type.SELECTOR,
"approvedUserSelector"
) {
@@ -170,7 +179,7 @@
ArraySet(setOf("example.com"))
)
},
- service(Type.INTERNAL, "setUserSelectionInternal") {
+ service(Type.INTERNAL, "setUserStateInternal") {
setDomainVerificationUserSelectionInternal(
it.userId,
it.targetPackageName,
@@ -184,11 +193,11 @@
service(Type.INTERNAL, "clearState") {
clearDomainVerificationState(listOf(it.targetPackageName))
},
- service(Type.INTERNAL, "clearUserSelections") {
- clearUserSelections(listOf(it.targetPackageName), it.userId)
+ service(Type.INTERNAL, "clearUserStates") {
+ clearUserStates(listOf(it.targetPackageName), it.userId)
},
- service(Type.VERIFIER, "getPackageNames") {
- validVerificationPackageNames
+ service(Type.VERIFIER, "queryValidPackageNames") {
+ queryValidVerificationPackageNames()
},
service(Type.QUERENT, "getInfo") {
getDomainVerificationInfo(it.targetPackageName)
@@ -208,26 +217,13 @@
DomainVerificationManager.STATE_SUCCESS
)
},
- service(Type.SELECTOR, "setLinkHandlingAllowed") {
- setDomainVerificationLinkHandlingAllowed(it.targetPackageName, true)
- },
service(Type.SELECTOR_USER, "setLinkHandlingAllowedUserId") {
setDomainVerificationLinkHandlingAllowed(it.targetPackageName, true, it.userId)
},
- service(Type.SELECTOR, "getUserSelection") {
- getDomainVerificationUserSelection(it.targetPackageName)
+ service(Type.SELECTION_QUERENT, "getUserStateUserId") {
+ getDomainVerificationUserState(it.targetPackageName, it.userId)
},
- service(Type.SELECTOR_USER, "getUserSelectionUserId") {
- getDomainVerificationUserSelection(it.targetPackageName, it.userId)
- },
- service(Type.SELECTOR, "setUserSelection") {
- setDomainVerificationUserSelection(
- it.targetDomainSetId,
- setOf("example.com"),
- true
- )
- },
- service(Type.SELECTOR_USER, "setUserSelectionUserId") {
+ service(Type.SELECTOR_USER, "setUserStateUserId") {
setDomainVerificationUserSelection(
it.targetDomainSetId,
setOf("example.com"),
@@ -244,10 +240,6 @@
service(Type.LEGACY_QUERENT, "getLegacyUserState") {
getLegacyState(it.targetPackageName, it.userId)
},
- service(Type.OWNER_QUERENT, "getOwnersForDomain") {
- // Re-use package name, since the result itself isn't relevant
- getOwnersForDomain(it.targetPackageName)
- },
service(Type.OWNER_QUERENT_USER, "getOwnersForDomainUserId") {
// Re-use package name, since the result itself isn't relevant
getOwnersForDomain(it.targetPackageName, it.userId)
@@ -362,6 +354,7 @@
Type.INTERNAL -> internal()
Type.QUERENT -> approvedQuerent()
Type.VERIFIER -> approvedVerifier()
+ Type.SELECTION_QUERENT -> approvedUserStateQuerent(verifyCrossUser = true)
Type.SELECTOR -> approvedUserSelector(verifyCrossUser = false)
Type.SELECTOR_USER -> approvedUserSelector(verifyCrossUser = true)
Type.LEGACY_QUERENT -> legacyQuerent()
@@ -371,7 +364,7 @@
}.run { /*exhaust*/ }
}
- fun internal() {
+ private fun internal() {
val context: Context = mockThrowOnUnmocked()
val target = params.construct(context)
@@ -385,13 +378,13 @@
}
}
- fun approvedQuerent() {
- val allowUserSelection = AtomicBoolean(false)
+ private fun approvedQuerent() {
+ val allowUserState = AtomicBoolean(false)
val allowPreferredApps = AtomicBoolean(false)
val allowQueryAll = AtomicBoolean(false)
val context: Context = mockThrowOnUnmocked {
initPermission(
- allowUserSelection,
+ allowUserState,
android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION
)
initPermission(
@@ -418,7 +411,7 @@
assertFails { runMethod(target, NON_VERIFIER_UID) }
- allowUserSelection.set(true)
+ allowUserState.set(true)
assertFails { runMethod(target, NON_VERIFIER_UID) }
@@ -427,7 +420,7 @@
runMethod(target, NON_VERIFIER_UID)
}
- fun approvedVerifier() {
+ private fun approvedVerifier() {
val allowDomainVerificationAgent = AtomicBoolean(false)
val allowIntentVerificationAgent = AtomicBoolean(false)
val allowQueryAll = AtomicBoolean(false)
@@ -469,12 +462,61 @@
assertFails { runMethod(target, NON_VERIFIER_UID) }
}
- fun approvedUserSelector(verifyCrossUser: Boolean) {
- val allowUserSelection = AtomicBoolean(false)
+ private fun approvedUserStateQuerent(verifyCrossUser: Boolean) {
val allowInteractAcrossUsers = AtomicBoolean(false)
val context: Context = mockThrowOnUnmocked {
initPermission(
- allowUserSelection,
+ allowInteractAcrossUsers,
+ android.Manifest.permission.INTERACT_ACROSS_USERS
+ )
+ }
+ val target = params.construct(context)
+
+ fun runTestCases(callingUserId: Int, targetUserId: Int, throws: Boolean) {
+ // User selector makes no distinction by UID
+ val allUids = INTERNAL_UIDS + VERIFIER_UID + NON_VERIFIER_UID
+ if (throws) {
+ allUids.forEach {
+ assertFails {
+ runMethod(target, it, visible = true, callingUserId, targetUserId)
+ }
+ }
+ } else {
+ allUids.forEach {
+ runMethod(target, it, visible = true, callingUserId, targetUserId)
+ }
+ }
+
+ // User selector doesn't use QUERY_ALL, so the invisible package should always fail
+ allUids.forEach {
+ assertFails {
+ runMethod(target, it, visible = false, callingUserId, targetUserId)
+ }
+ }
+ }
+
+ val callingUserId = 0
+ val notCallingUserId = 1
+
+ runTestCases(callingUserId, callingUserId, throws = false)
+ if (verifyCrossUser) {
+ runTestCases(callingUserId, notCallingUserId, throws = true)
+ }
+
+ allowInteractAcrossUsers.set(true)
+
+ runTestCases(callingUserId, callingUserId, throws = false)
+ if (verifyCrossUser) {
+ runTestCases(callingUserId, notCallingUserId, throws = false)
+ }
+ }
+
+ private fun approvedUserSelector(verifyCrossUser: Boolean) {
+ val allowUserState = AtomicBoolean(false)
+ val allowInteractAcrossUsers = AtomicBoolean(false)
+ val context: Context = mockThrowOnUnmocked {
+ initPermission(
+ allowUserState,
android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION
)
initPermission(
@@ -515,7 +557,7 @@
runTestCases(callingUserId, notCallingUserId, throws = true)
}
- allowUserSelection.set(true)
+ allowUserState.set(true)
runTestCases(callingUserId, callingUserId, throws = false)
if (verifyCrossUser) {
@@ -641,7 +683,7 @@
private fun ownerQuerent(verifyCrossUser: Boolean) {
val allowQueryAll = AtomicBoolean(false)
- val allowUserSelection = AtomicBoolean(false)
+ val allowUserState = AtomicBoolean(false)
val allowInteractAcrossUsers = AtomicBoolean(false)
val context: Context = mockThrowOnUnmocked {
initPermission(
@@ -649,7 +691,7 @@
android.Manifest.permission.QUERY_ALL_PACKAGES
)
initPermission(
- allowUserSelection,
+ allowUserState,
android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION
)
initPermission(
@@ -690,7 +732,7 @@
runTestCases(callingUserId, notCallingUserId, throws = true)
}
- allowUserSelection.set(true)
+ allowUserState.set(true)
runTestCases(callingUserId, callingUserId, throws = false)
if (verifyCrossUser) {
@@ -769,6 +811,9 @@
// INTERNAL || domain verification agent
VERIFIER,
+ // No permissions, allows all apps to view domain state for visible packages
+ SELECTION_QUERENT,
+
// Holding the user setting permission
SELECTOR,
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationModelExtensions.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationModelExtensions.kt
index 439048c..8c31c65 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationModelExtensions.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationModelExtensions.kt
@@ -18,7 +18,7 @@
import android.content.pm.verify.domain.DomainVerificationRequest
import android.content.pm.verify.domain.DomainVerificationInfo
-import android.content.pm.verify.domain.DomainVerificationUserSelection
+import android.content.pm.verify.domain.DomainVerificationUserState
import com.android.server.pm.verify.domain.DomainVerificationPersistence
operator fun <F> android.util.Pair<F, *>.component1() = first
@@ -30,11 +30,11 @@
operator fun DomainVerificationInfo.component2() = packageName
operator fun DomainVerificationInfo.component3() = hostToStateMap
-operator fun DomainVerificationUserSelection.component1() = identifier
-operator fun DomainVerificationUserSelection.component2() = packageName
-operator fun DomainVerificationUserSelection.component3() = user
-operator fun DomainVerificationUserSelection.component4() = isLinkHandlingAllowed
-operator fun DomainVerificationUserSelection.component5() = hostToStateMap
+operator fun DomainVerificationUserState.component1() = identifier
+operator fun DomainVerificationUserState.component2() = packageName
+operator fun DomainVerificationUserState.component3() = user
+operator fun DomainVerificationUserState.component4() = isLinkHandlingAllowed
+operator fun DomainVerificationUserState.component5() = hostToStateMap
operator fun DomainVerificationPersistence.ReadResult.component1() = active
operator fun DomainVerificationPersistence.ReadResult.component2() = restored
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPersistenceTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPersistenceTest.kt
index a92ab9e..6597577 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPersistenceTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPersistenceTest.kt
@@ -22,14 +22,15 @@
import android.util.TypedXmlSerializer
import android.util.Xml
import com.android.server.pm.verify.domain.DomainVerificationPersistence
+import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState
import com.android.server.pm.verify.domain.models.DomainVerificationPkgState
import com.android.server.pm.verify.domain.models.DomainVerificationStateMap
-import com.android.server.pm.verify.domain.models.DomainVerificationUserState
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
+import org.xmlpull.v1.XmlPullParser
import java.io.File
import java.nio.charset.StandardCharsets
import java.util.UUID
@@ -41,21 +42,41 @@
internal fun File.writeXml(block: (serializer: TypedXmlSerializer) -> Unit) = apply {
outputStream().use {
- // Explicitly use string based XML so it can printed in the test failure output
- Xml.newFastSerializer()
+ // This must use the binary serializer the mirror the production behavior, as
+ // there are slight differences with the string based one.
+ Xml.newBinarySerializer()
.apply {
setOutput(it, StandardCharsets.UTF_8.name())
startDocument(null, true)
setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true)
+ // Write a wrapping tag to ensure the domain verification settings didn't
+ // close out the document, allowing other settings to be written
+ startTag(null, "wrapper-tag")
}
.apply(block)
+ .apply {
+ startTag(null, "trailing-tag")
+ endTag(null, "trailing-tag")
+ endTag(null, "wrapper-tag")
+ }
.endDocument()
}
}
internal fun <T> File.readXml(block: (parser: TypedXmlPullParser) -> T) =
inputStream().use {
- block(Xml.resolvePullParser(it))
+ val parser = Xml.resolvePullParser(it)
+ assertThat(parser.nextTag()).isEqualTo(XmlPullParser.START_TAG)
+ assertThat(parser.name).isEqualTo("wrapper-tag")
+ assertThat(parser.nextTag()).isEqualTo(XmlPullParser.START_TAG)
+ block(parser).also {
+ assertThat(parser.nextTag()).isEqualTo(XmlPullParser.START_TAG)
+ assertThat(parser.name).isEqualTo("trailing-tag")
+ assertThat(parser.nextTag()).isEqualTo(XmlPullParser.END_TAG)
+ assertThat(parser.name).isEqualTo("trailing-tag")
+ assertThat(parser.nextTag()).isEqualTo(XmlPullParser.END_TAG)
+ assertThat(parser.name).isEqualTo("wrapper-tag")
+ }
}
}
@@ -102,14 +123,14 @@
// A domain without a written state falls back to default
stateMap["missing-state.com"] = DomainVerificationManager.STATE_NO_RESPONSE
- userSelectionStates[1] = DomainVerificationUserState(1).apply {
+ userStates[1] = DomainVerificationInternalUserState(1).apply {
addHosts(setOf("example-user1.com", "example-user1.org"))
isLinkHandlingAllowed = true
}
}
val stateOne = mockEmptyPkgState(1).apply {
// It's valid to have a user selection without any autoVerify domains
- userSelectionStates[1] = DomainVerificationUserState(1).apply {
+ userStates[1] = DomainVerificationInternalUserState(1).apply {
addHosts(setOf("example-user1.com", "example-user1.org"))
isLinkHandlingAllowed = false
}
@@ -214,7 +235,7 @@
private fun mockPkgState(id: Int) = mockEmptyPkgState(id).apply {
stateMap["$packageName.com"] = id
- userSelectionStates[id] = DomainVerificationUserState(id).apply {
+ userStates[id] = DomainVerificationInternalUserState(id).apply {
addHosts(setOf("$packageName-user.com"))
isLinkHandlingAllowed = true
}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
index 010eacf..0d8f275 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
@@ -122,8 +122,8 @@
service("clearState") {
clearDomainVerificationState(listOf(TEST_PKG))
},
- service("clearUserSelections") {
- clearUserSelections(listOf(TEST_PKG), TEST_USER_ID)
+ service("clearUserStates") {
+ clearUserStates(listOf(TEST_PKG), TEST_USER_ID)
},
service("setStatus") {
setDomainVerificationStatus(
@@ -147,19 +147,13 @@
DomainVerificationManager.STATE_SUCCESS
)
},
- service("setLinkHandlingAllowed") {
- setDomainVerificationLinkHandlingAllowed(TEST_PKG, true)
- },
service("setLinkHandlingAllowedUserId") {
setDomainVerificationLinkHandlingAllowed(TEST_PKG, true, TEST_USER_ID)
},
service("setLinkHandlingAllowedInternal") {
setDomainVerificationLinkHandlingAllowedInternal(TEST_PKG, true, TEST_USER_ID)
},
- service("setUserSelection") {
- setDomainVerificationUserSelection(TEST_UUID, setOf("example.com"), true)
- },
- service("setUserSelectionUserId") {
+ service("setUserStateUserId") {
setDomainVerificationUserSelection(
TEST_UUID,
setOf("example.com"),
@@ -167,7 +161,7 @@
TEST_USER_ID
)
},
- service("setUserSelectionInternal") {
+ service("setUserStateInternal") {
setDomainVerificationUserSelectionInternal(
TEST_USER_ID,
TEST_PKG,
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerUserSelectionOverrideTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
similarity index 82%
rename from services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerUserSelectionOverrideTest.kt
rename to services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
index 48056a2..0576125 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerUserSelectionOverrideTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
@@ -16,18 +16,16 @@
package com.android.server.pm.test.verify.domain
-import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.parsing.component.ParsedActivity
import android.content.pm.parsing.component.ParsedIntentInfo
import android.content.pm.verify.domain.DomainVerificationManager
-import android.content.pm.verify.domain.DomainVerificationUserSelection
+import android.content.pm.verify.domain.DomainVerificationUserState
import android.os.Build
import android.os.PatternMatcher
import android.os.Process
import android.util.ArraySet
-import androidx.test.InstrumentationRegistry
import com.android.server.pm.PackageSetting
import com.android.server.pm.parsing.pkg.AndroidPackage
import com.android.server.pm.verify.domain.DomainVerificationService
@@ -41,7 +39,7 @@
import org.mockito.ArgumentMatchers.anyString
import java.util.UUID
-class DomainVerificationManagerUserSelectionOverrideTest {
+class DomainVerificationUserStateOverrideTest {
companion object {
private const val PKG_ONE = "com.test.one"
@@ -50,17 +48,19 @@
private val UUID_TWO = UUID.fromString("a3389c16-7f9f-4e86-85e3-500d1249c74c")
private val DOMAIN_ONE =
- DomainVerificationManagerUserSelectionOverrideTest::class.java.packageName
+ DomainVerificationUserStateOverrideTest::class.java.packageName
- private const val STATE_NONE = DomainVerificationUserSelection.DOMAIN_STATE_NONE
- private const val STATE_SELECTED = DomainVerificationUserSelection.DOMAIN_STATE_SELECTED
- private const val STATE_VERIFIED = DomainVerificationUserSelection.DOMAIN_STATE_VERIFIED
+ private const val STATE_NONE = DomainVerificationUserState.DOMAIN_STATE_NONE
+ private const val STATE_SELECTED = DomainVerificationUserState.DOMAIN_STATE_SELECTED
+ private const val STATE_VERIFIED = DomainVerificationUserState.DOMAIN_STATE_VERIFIED
+
+ private const val USER_ID = 0
}
private val pkg1 = mockPkgSetting(PKG_ONE, UUID_ONE)
private val pkg2 = mockPkgSetting(PKG_TWO, UUID_TWO)
- fun makeManager(): DomainVerificationManager =
+ fun makeService() =
DomainVerificationService(mockThrowOnUnmocked {
// Assume the test has every permission necessary
whenever(enforcePermission(anyString(), anyInt(), anyInt(), anyString()))
@@ -88,7 +88,7 @@
addPackage(pkg2)
// Starting state for all tests is to have domain 1 enabled for the first package
- setDomainVerificationUserSelection(UUID_ONE, setOf(DOMAIN_ONE), true)
+ setDomainVerificationUserSelection(UUID_ONE, setOf(DOMAIN_ONE), true, USER_ID)
assertThat(stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_SELECTED)
}
@@ -138,37 +138,37 @@
@Test
fun anotherPackageTakeoverSuccess() {
- val manager = makeManager()
+ val service = makeService()
// Attempt override by package 2
- manager.setDomainVerificationUserSelection(UUID_TWO, setOf(DOMAIN_ONE), true)
+ service.setDomainVerificationUserSelection(UUID_TWO, setOf(DOMAIN_ONE), true, USER_ID)
// 1 loses approval
- assertThat(manager.stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_NONE)
+ assertThat(service.stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_NONE)
// 2 gains approval
- assertThat(manager.stateFor(PKG_TWO, DOMAIN_ONE)).isEqualTo(STATE_SELECTED)
+ assertThat(service.stateFor(PKG_TWO, DOMAIN_ONE)).isEqualTo(STATE_SELECTED)
// 2 is the only owner
- assertThat(manager.getOwnersForDomain(DOMAIN_ONE).map { it.packageName })
+ assertThat(service.getOwnersForDomain(DOMAIN_ONE, USER_ID).map { it.packageName })
.containsExactly(PKG_TWO)
}
@Test(expected = IllegalArgumentException::class)
fun anotherPackageTakeoverFailure() {
- val manager = makeManager()
+ val service = makeService()
// Verify 1 to give it a higher approval level
- manager.setDomainVerificationStatus(UUID_ONE, setOf(DOMAIN_ONE),
+ service.setDomainVerificationStatus(UUID_ONE, setOf(DOMAIN_ONE),
DomainVerificationManager.STATE_SUCCESS)
- assertThat(manager.stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_VERIFIED)
- assertThat(manager.getOwnersForDomain(DOMAIN_ONE).map { it.packageName })
+ assertThat(service.stateFor(PKG_ONE, DOMAIN_ONE)).isEqualTo(STATE_VERIFIED)
+ assertThat(service.getOwnersForDomain(DOMAIN_ONE, USER_ID).map { it.packageName })
.containsExactly(PKG_ONE)
// Attempt override by package 2
- manager.setDomainVerificationUserSelection(UUID_TWO, setOf(DOMAIN_ONE), true)
+ service.setDomainVerificationUserSelection(UUID_TWO, setOf(DOMAIN_ONE), true, USER_ID)
}
- private fun DomainVerificationManager.stateFor(pkgName: String, host: String) =
- getDomainVerificationUserSelection(pkgName)!!.hostToStateMap[host]
+ private fun DomainVerificationService.stateFor(pkgName: String, host: String) =
+ getDomainVerificationUserState(pkgName, USER_ID)!!.hostToStateMap[host]
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index f7f5928..3870b02 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -641,6 +641,6 @@
private static JobStatus createJobStatus(JobInfo.Builder job, int uid,
long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
return new JobStatus(job.build(), uid, null, -1, 0, null,
- earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0, 0, null, 0);
+ earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0, 0, null, 0, 0);
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
index 91b3cb7..7925b69 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -685,7 +685,7 @@
final JobInfo job = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).build();
return new JobStatus(job, 0, null, -1, 0, null, earliestRunTimeElapsedMillis,
- latestRunTimeElapsedMillis, 0, 0, null, 0);
+ latestRunTimeElapsedMillis, 0, 0, null, 0, 0);
}
private static JobStatus createJobStatus(JobInfo job) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/usage/UserUsageStatsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/usage/UserUsageStatsServiceTest.java
new file mode 100644
index 0000000..d786a5d
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/usage/UserUsageStatsServiceTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2021 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.server.usage;
+
+import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED;
+import static android.app.usage.UsageEvents.Event.APP_COMPONENT_USED;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mockitoSession;
+
+import android.app.usage.UsageEvents;
+import android.app.usage.UsageEvents.Event;
+import android.content.Context;
+import android.os.SystemClock;
+import android.text.format.DateUtils;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.usage.UserUsageStatsService.StatsUpdatedListener;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.io.File;
+import java.util.HashMap;
+
+@RunWith(AndroidJUnit4.class)
+public class UserUsageStatsServiceTest {
+ private static final int TEST_USER_ID = 0;
+ private static final String TEST_PACKAGE_NAME = "test.package";
+ private static final long TIME_INTERVAL_MILLIS = DateUtils.DAY_IN_MILLIS;
+
+ private UserUsageStatsService mService;
+ private MockitoSession mMockitoSession;
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private StatsUpdatedListener mStatsUpdatedListener;
+
+ @Before
+ public void setUp() {
+ mMockitoSession = mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+
+ File dir = new File(InstrumentationRegistry.getContext().getCacheDir(), "test");
+ mService = new UserUsageStatsService(mContext, TEST_USER_ID, dir, mStatsUpdatedListener);
+
+ HashMap<String, Long> installedPkgs = new HashMap<>();
+ installedPkgs.put(TEST_PACKAGE_NAME, System.currentTimeMillis());
+
+ mService.init(System.currentTimeMillis(), installedPkgs);
+ }
+
+ @After
+ public void tearDown() {
+ if (mMockitoSession != null) {
+ mMockitoSession.finishMocking();
+ }
+ }
+
+ @Test
+ public void testReportEvent_eventAppearsInQueries() {
+ Event event = new Event(ACTIVITY_RESUMED, SystemClock.elapsedRealtime());
+ event.mPackage = TEST_PACKAGE_NAME;
+ mService.reportEvent(event);
+
+ long now = System.currentTimeMillis();
+ long startTime = now - TIME_INTERVAL_MILLIS;
+ UsageEvents events = mService.queryEventsForPackage(
+ startTime, now, TEST_PACKAGE_NAME, false /* includeTaskRoot */);
+
+ boolean hasTestEvent = false;
+ while (events != null && events.hasNextEvent()) {
+ Event outEvent = new Event();
+ events.getNextEvent(outEvent);
+ if (outEvent.mEventType == ACTIVITY_RESUMED) {
+ hasTestEvent = true;
+ }
+ }
+ assertTrue(hasTestEvent);
+ }
+
+ @Test
+ public void testReportEvent_packageUsedEventNotTracked() {
+ Event event = new Event(APP_COMPONENT_USED, SystemClock.elapsedRealtime());
+ event.mPackage = TEST_PACKAGE_NAME;
+ mService.reportEvent(event);
+
+ long now = System.currentTimeMillis();
+ long startTime = now - TIME_INTERVAL_MILLIS;
+ UsageEvents events = mService.queryEventsForPackage(
+ startTime, now, TEST_PACKAGE_NAME, false /* includeTaskRoot */);
+
+ boolean hasTestEvent = false;
+ while (events != null && events.hasNextEvent()) {
+ Event outEvent = new Event();
+ events.getNextEvent(outEvent);
+ if (outEvent.mEventType == APP_COMPONENT_USED) {
+ hasTestEvent = true;
+ }
+ }
+ assertFalse(hasTestEvent);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/BootReceiverTest.java b/services/tests/servicestests/src/com/android/server/BootReceiverTest.java
new file mode 100644
index 0000000..489e2f7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/BootReceiverTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2021 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.server;
+
+import android.test.AndroidTestCase;
+
+/**
+ * Tests for {@link com.android.server.BootReceiver}
+ */
+public class BootReceiverTest extends AndroidTestCase {
+ public void testLogLinePotentiallySensitive() throws Exception {
+ /*
+ * Strings to be dropped from the log as potentially sensitive: register dumps, process
+ * names, hardware info.
+ */
+ final String[] becomeNull = {
+ "CPU: 4 PID: 120 Comm: kunit_try_catch Tainted: G W 5.8.0-rc6+ #7",
+ "Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1 04/01/2014",
+ "[ 0.083207] RSP: 0000:ffffffff8fe07ca8 EFLAGS: 00010046 ORIG_RAX: 0000000000000000",
+ "[ 0.084709] RAX: 0000000000000000 RBX: ffffffffff240000 RCX: ffffffff815fcf01",
+ "[ 0.086109] RDX: dffffc0000000000 RSI: 0000000000000001 RDI: ffffffffff240004",
+ "[ 0.087509] RBP: ffffffff8fe07d60 R08: fffffbfff1fc0f21 R09: fffffbfff1fc0f21",
+ "[ 0.088911] R10: ffffffff8fe07907 R11: fffffbfff1fc0f20 R12: ffffffff8fe07d38",
+ "R13: 0000000000000001 R14: 0000000000000001 R15: ffffffff8fe07e80",
+ "x29: ffff00003ce07150 x28: ffff80001aa29cc0",
+ "x1 : 0000000000000000 x0 : ffff00000f628000",
+ };
+
+ /* Strings to be left unchanged, including non-sensitive registers and parts of reports. */
+ final String[] leftAsIs = {
+ "FS: 0000000000000000(0000) GS:ffffffff92409000(0000) knlGS:0000000000000000",
+ "[ 69.2366] [ T6006]c7 6006 =======================================================",
+ "[ 69.245688] [ T6006] BUG: KFENCE: out-of-bounds in kfence_handle_page_fault",
+ "[ 69.257816] [ T6006]c7 6006 Out-of-bounds access at 0xffffffca75c45000 ",
+ "[ 69.273536] [ T6006]c7 6006 __do_kernel_fault+0xa8/0x11c",
+ "pc : __mutex_lock+0x428/0x99c ",
+ "sp : ffff00003ce07150",
+ "Call trace:",
+ "",
+ };
+
+ final String[][] stripped = {
+ { "Detected corrupted memory at 0xffffffffb6797ff9 [ 0xac . . . . . . ]:",
+ "Detected corrupted memory at 0xffffffffb6797ff9" },
+ };
+ for (int i = 0; i < becomeNull.length; i++) {
+ assertEquals(BootReceiver.stripSensitiveData(becomeNull[i]), null);
+ }
+
+ for (int i = 0; i < leftAsIs.length; i++) {
+ assertEquals(BootReceiver.stripSensitiveData(leftAsIs[i]), leftAsIs[i]);
+ }
+
+ for (int i = 0; i < stripped.length; i++) {
+ assertEquals(BootReceiver.stripSensitiveData(stripped[i][0]), stripped[i][1]);
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
index f897d5c..d6c11a5 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
@@ -495,7 +495,8 @@
mServiceConnection.performAccessibilityAction(PIP_WINDOWID, ROOT_NODE_ID,
ACTION_ACCESSIBILITY_FOCUS, null, INTERACTION_ID, mMockCallback, TID);
- verify(mMockIPowerManager).userActivity(anyLong(), anyInt(), anyInt());
+ verify(mMockIPowerManager).userActivity(eq(Display.DEFAULT_DISPLAY), anyLong(), anyInt(),
+ anyInt());
verify(mMockIA11yInteractionConnection).performAccessibilityAction(eq(ROOT_NODE_ID),
eq(ACTION_ACCESSIBILITY_FOCUS), any(), eq(INTERACTION_ID), eq(mMockCallback),
anyInt(), eq(PID), eq(TID));
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java
new file mode 100644
index 0000000..170f561
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInteractionControllerNodeRequestsTest.java
@@ -0,0 +1,581 @@
+/*
+ * Copyright (C) 2021 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.server.accessibility;
+
+
+import static android.view.accessibility.AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
+import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS;
+import static android.view.accessibility.AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS;
+import static android.view.accessibility.AccessibilityNodeInfo.ROOT_NODE_ID;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.os.RemoteException;
+import android.view.AccessibilityInteractionController;
+import android.view.View;
+import android.view.ViewRootImpl;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityNodeIdManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeProvider;
+import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests that verify expected node and prefetched node results when finding a view by node id. We
+ * send some requests to the controller via View methods to control message timing.
+ */
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityInteractionControllerNodeRequestsTest {
+ private AccessibilityInteractionController mAccessibilityInteractionController;
+ @Mock
+ private IAccessibilityInteractionConnectionCallback mMockClientCallback1;
+ @Mock
+ private IAccessibilityInteractionConnectionCallback mMockClientCallback2;
+
+ @Captor
+ private ArgumentCaptor<AccessibilityNodeInfo> mFindInfoCaptor;
+ @Captor private ArgumentCaptor<List<AccessibilityNodeInfo>> mPrefetchInfoListCaptor;
+
+ private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ private static final int MOCK_CLIENT_1_THREAD_AND_PROCESS_ID = 1;
+ private static final int MOCK_CLIENT_2_THREAD_AND_PROCESS_ID = 2;
+
+ private static final String FRAME_LAYOUT_DESCRIPTION = "frameLayout";
+ private static final String TEXT_VIEW_1_DESCRIPTION = "textView1";
+ private static final String TEXT_VIEW_2_DESCRIPTION = "textView2";
+
+ private TestFrameLayout mFrameLayout;
+ private TestTextView mTextView1;
+ private TestTextView2 mTextView2;
+
+ private boolean mSendClient1RequestForTextAfterTextPrefetched;
+ private boolean mSendClient2RequestForTextAfterTextPrefetched;
+ private boolean mSendRequestForTextAndIncludeUnImportantViews;
+ private int mMockClient1InteractionId;
+ private int mMockClient2InteractionId;
+
+ @Before
+ public void setUp() throws Throwable {
+ MockitoAnnotations.initMocks(this);
+
+ mInstrumentation.runOnMainSync(() -> {
+ final Context context = mInstrumentation.getTargetContext();
+ final ViewRootImpl viewRootImpl = new ViewRootImpl(context, context.getDisplay());
+
+ mFrameLayout = new TestFrameLayout(context);
+ mTextView1 = new TestTextView(context);
+ mTextView2 = new TestTextView2(context);
+
+ mFrameLayout.addView(mTextView1);
+ mFrameLayout.addView(mTextView2);
+
+ // The controller retrieves views through this manager, and registration happens on
+ // when attached to a window, which we don't have. We can simply reference FrameLayout
+ // with ROOT_NODE_ID
+ AccessibilityNodeIdManager.getInstance().registerViewWithId(
+ mTextView1, mTextView1.getAccessibilityViewId());
+ AccessibilityNodeIdManager.getInstance().registerViewWithId(
+ mTextView2, mTextView2.getAccessibilityViewId());
+
+ try {
+ viewRootImpl.setView(mFrameLayout, new WindowManager.LayoutParams(), null);
+
+ } catch (WindowManager.BadTokenException e) {
+ // activity isn't running, we will ignore BadTokenException.
+ }
+
+ mAccessibilityInteractionController =
+ new AccessibilityInteractionController(viewRootImpl);
+ });
+
+ }
+
+ @After
+ public void tearDown() throws Throwable {
+ AccessibilityNodeIdManager.getInstance().unregisterViewWithId(
+ mTextView1.getAccessibilityViewId());
+ AccessibilityNodeIdManager.getInstance().unregisterViewWithId(
+ mTextView2.getAccessibilityViewId());
+ }
+
+ /**
+ * Tests a basic request for the root node with prefetch flag
+ * {@link AccessibilityNodeInfo#FLAG_PREFETCH_DESCENDANTS}
+ *
+ * @throws RemoteException
+ */
+ @Test
+ public void testFindRootView_withOneClient_shouldReturnRootNodeAndPrefetchDescendants()
+ throws RemoteException {
+ // Request for our FrameLayout
+ sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1,
+ mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS);
+ mInstrumentation.waitForIdleSync();
+
+ // Verify we get FrameLayout
+ verify(mMockClientCallback1).setFindAccessibilityNodeInfoResult(
+ mFindInfoCaptor.capture(), eq(mMockClient1InteractionId));
+ AccessibilityNodeInfo infoSentToService = mFindInfoCaptor.getValue();
+ assertEquals(FRAME_LAYOUT_DESCRIPTION, infoSentToService.getContentDescription());
+
+ verify(mMockClientCallback1).setPrefetchAccessibilityNodeInfoResult(
+ mPrefetchInfoListCaptor.capture(), eq(mMockClient1InteractionId));
+ // The descendants are our two TextViews
+ List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue();
+ assertEquals(2, prefetchedNodes.size());
+ assertEquals(TEXT_VIEW_1_DESCRIPTION, prefetchedNodes.get(0).getContentDescription());
+ assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNodes.get(1).getContentDescription());
+
+ }
+
+ /**
+ * Tests a basic request for TestTextView1's node with prefetch flag
+ * {@link AccessibilityNodeInfo#FLAG_PREFETCH_SIBLINGS}
+ *
+ * @throws RemoteException
+ */
+ @Test
+ public void testFindTextView_withOneClient_shouldReturnNodeAndPrefetchedSiblings()
+ throws RemoteException {
+ // Request for TextView1
+ sendNodeRequestToController(AccessibilityNodeInfo.makeNodeId(
+ mTextView1.getAccessibilityViewId(), AccessibilityNodeProvider.HOST_VIEW_ID),
+ mMockClientCallback1, mMockClient1InteractionId, FLAG_PREFETCH_SIBLINGS);
+ mInstrumentation.waitForIdleSync();
+
+ // Verify we get TextView1
+ verify(mMockClientCallback1).setFindAccessibilityNodeInfoResult(
+ mFindInfoCaptor.capture(), eq(mMockClient1InteractionId));
+ AccessibilityNodeInfo infoSentToService = mFindInfoCaptor.getValue();
+ assertEquals(TEXT_VIEW_1_DESCRIPTION, infoSentToService.getContentDescription());
+
+ // Verify the prefetched sibling of TextView1 is TextView2
+ verify(mMockClientCallback1).setPrefetchAccessibilityNodeInfoResult(
+ mPrefetchInfoListCaptor.capture(), eq(mMockClient1InteractionId));
+ // TextView2 is the prefetched sibling
+ List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue();
+ assertEquals(1, prefetchedNodes.size());
+ assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNodes.get(0).getContentDescription());
+ }
+
+ /**
+ * Tests a series of controller requests to prevent prefetching.
+ * Request 1: Client 1 requests the root node
+ * Request 2: When the root node is initialized in
+ * {@link TestFrameLayout#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)},
+ * Client 2 requests TestTextView1's node
+ *
+ * Request 2 on the queue prevents prefetching for Request 1.
+ *
+ * @throws RemoteException
+ */
+ @Test
+ public void testFindRootAndTextNodes_withTwoClients_shouldPreventClient1Prefetch()
+ throws RemoteException {
+ mFrameLayout.setAccessibilityDelegate(new View.AccessibilityDelegate() {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ final long nodeId = AccessibilityNodeInfo.makeNodeId(
+ mTextView1.getAccessibilityViewId(),
+ AccessibilityNodeProvider.HOST_VIEW_ID);
+
+ // Enqueue a request when this node is found from a different service for
+ // TextView1
+ sendNodeRequestToController(nodeId, mMockClientCallback2,
+ mMockClient2InteractionId, FLAG_PREFETCH_SIBLINGS);
+ }
+ });
+ // Client 1 request for FrameLayout
+ sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1,
+ mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS);
+
+ mInstrumentation.waitForIdleSync();
+
+ // Verify client 1 gets FrameLayout
+ verify(mMockClientCallback1).setFindAccessibilityNodeInfoResult(
+ mFindInfoCaptor.capture(), eq(mMockClient1InteractionId));
+ AccessibilityNodeInfo infoSentToService = mFindInfoCaptor.getValue();
+ assertEquals(FRAME_LAYOUT_DESCRIPTION, infoSentToService.getContentDescription());
+
+ // The second request is put in the queue in the FrameLayout's onInitializeA11yNodeInfo,
+ // meaning prefetching is interrupted and does not even begin for the first request
+ verify(mMockClientCallback1, never())
+ .setPrefetchAccessibilityNodeInfoResult(anyList(), anyInt());
+
+ // Verify client 2 gets TextView1
+ verify(mMockClientCallback2).setFindAccessibilityNodeInfoResult(
+ mFindInfoCaptor.capture(), eq(mMockClient2InteractionId));
+ infoSentToService = mFindInfoCaptor.getValue();
+ assertEquals(TEXT_VIEW_1_DESCRIPTION, infoSentToService.getContentDescription());
+
+ // Verify the prefetched sibling of TextView1 is TextView2 (FLAG_PREFETCH_SIBLINGS)
+ verify(mMockClientCallback2).setPrefetchAccessibilityNodeInfoResult(
+ mPrefetchInfoListCaptor.capture(), eq(mMockClient2InteractionId));
+ List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue();
+ assertEquals(1, prefetchedNodes.size());
+ assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNodes.get(0).getContentDescription());
+ }
+
+ /**
+ * Tests a series of controller same-service requests to interrupt prefetching and satisfy a
+ * pending node request.
+ * Request 1: Request the root node
+ * Request 2: When TextTextView1's node is initialized as part of Request 1's prefetching,
+ * request TestTextView1's node
+ *
+ * Request 1 prefetches TestTextView1's node, is interrupted by a pending request, and checks
+ * if its prefetched nodes satisfy any pending requests. It satisfies Request 2's request for
+ * TestTextView1's node. Request 2 is fulfilled, so it is removed from queue and does not
+ * prefetch.
+ *
+ * @throws RemoteException
+ */
+ @Test
+ public void testFindRootAndTextNode_withOneClient_shouldInterruptPrefetchAndSatisfyPendingMsg()
+ throws RemoteException {
+ mSendClient1RequestForTextAfterTextPrefetched = true;
+
+ mTextView1.setAccessibilityDelegate(new View.AccessibilityDelegate(){
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ info.setContentDescription(TEXT_VIEW_1_DESCRIPTION);
+ final long nodeId = AccessibilityNodeInfo.makeNodeId(
+ mTextView1.getAccessibilityViewId(),
+ AccessibilityNodeProvider.HOST_VIEW_ID);
+
+ if (mSendClient1RequestForTextAfterTextPrefetched) {
+ // Prevent a loop when processing second request
+ mSendClient1RequestForTextAfterTextPrefetched = false;
+ // TextView1 is prefetched here after the FrameLayout is found. Now enqueue a
+ // same-client request for TextView1
+ sendNodeRequestToController(nodeId, mMockClientCallback1,
+ ++mMockClient1InteractionId, FLAG_PREFETCH_SIBLINGS);
+
+ }
+ }
+ });
+ // Client 1 requests FrameLayout
+ sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1,
+ mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS);
+
+ // Flush out all messages
+ mInstrumentation.waitForIdleSync();
+
+ // When TextView1 is prefetched for FrameLayout, we put a message on the queue in
+ // TextView1's onInitializeA11yNodeInfo that requests for TextView1. The service thus get
+ // two node results for FrameLayout and TextView1.
+ verify(mMockClientCallback1, times(2))
+ .setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(), anyInt());
+
+ List<AccessibilityNodeInfo> foundNodes = mFindInfoCaptor.getAllValues();
+ assertEquals(FRAME_LAYOUT_DESCRIPTION, foundNodes.get(0).getContentDescription());
+ assertEquals(TEXT_VIEW_1_DESCRIPTION, foundNodes.get(1).getContentDescription());
+
+ // The controller will look at FrameLayout's prefetched nodes and find matching nodes in
+ // pending requests. The prefetched TextView1 matches the second request. The second
+ // request was removed from queue and prefetching for this request never occurred.
+ verify(mMockClientCallback1, times(1))
+ .setPrefetchAccessibilityNodeInfoResult(mPrefetchInfoListCaptor.capture(),
+ eq(mMockClient1InteractionId - 1));
+ List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue();
+ assertEquals(1, prefetchedNodes.size());
+ assertEquals(TEXT_VIEW_1_DESCRIPTION, prefetchedNodes.get(0).getContentDescription());
+ }
+
+ /**
+ * Like above, but tests a series of controller requests from different services to interrupt
+ * prefetching and satisfy a pending node request.
+ *
+ * @throws RemoteException
+ */
+ @Test
+ public void testFindRootAndTextNode_withTwoClients_shouldInterruptPrefetchAndSatisfyPendingMsg()
+ throws RemoteException {
+ mSendClient2RequestForTextAfterTextPrefetched = true;
+ mTextView1.setAccessibilityDelegate(new View.AccessibilityDelegate(){
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ info.setContentDescription(TEXT_VIEW_1_DESCRIPTION);
+ final long nodeId = AccessibilityNodeInfo.makeNodeId(
+ mTextView1.getAccessibilityViewId(),
+ AccessibilityNodeProvider.HOST_VIEW_ID);
+
+ if (mSendClient2RequestForTextAfterTextPrefetched) {
+ mSendClient2RequestForTextAfterTextPrefetched = false;
+ // TextView1 is prefetched here. Now enqueue client 2's request for
+ // TextView1
+ sendNodeRequestToController(nodeId, mMockClientCallback2,
+ mMockClient2InteractionId, FLAG_PREFETCH_SIBLINGS);
+ }
+ }
+ });
+ // Client 1 requests FrameLayout
+ sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1,
+ mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS);
+
+ mInstrumentation.waitForIdleSync();
+
+ // Verify client 1 gets FrameLayout
+ verify(mMockClientCallback1, times(1))
+ .setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(), anyInt());
+ assertEquals(FRAME_LAYOUT_DESCRIPTION,
+ mFindInfoCaptor.getValue().getContentDescription());
+
+ // Verify client 1 has prefetched nodes
+ verify(mMockClientCallback1, times(1))
+ .setPrefetchAccessibilityNodeInfoResult(mPrefetchInfoListCaptor.capture(),
+ eq(mMockClient1InteractionId));
+
+ // Verify client 1's only prefetched node is TextView1
+ List<AccessibilityNodeInfo> prefetchedNodes = mPrefetchInfoListCaptor.getValue();
+ assertEquals(1, prefetchedNodes.size());
+ assertEquals(TEXT_VIEW_1_DESCRIPTION, prefetchedNodes.get(0).getContentDescription());
+
+ // Verify client 2 gets TextView1
+ verify(mMockClientCallback2, times(1))
+ .setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(), anyInt());
+
+ assertEquals(TEXT_VIEW_1_DESCRIPTION, mFindInfoCaptor.getValue().getContentDescription());
+
+ // The second request was removed from queue and prefetching for this client request never
+ // occurred as it was satisfied.
+ verify(mMockClientCallback2, never())
+ .setPrefetchAccessibilityNodeInfoResult(anyList(), anyInt());
+
+ }
+
+ @Test
+ public void testFindNodeById_withTwoDifferentPrefetchFlags_shouldNotSatisfyPendingRequest()
+ throws RemoteException {
+ mSendRequestForTextAndIncludeUnImportantViews = true;
+ mTextView1.setAccessibilityDelegate(new View.AccessibilityDelegate(){
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ info.setContentDescription(TEXT_VIEW_1_DESCRIPTION);
+ final long nodeId = AccessibilityNodeInfo.makeNodeId(
+ mTextView1.getAccessibilityViewId(),
+ AccessibilityNodeProvider.HOST_VIEW_ID);
+
+ if (mSendRequestForTextAndIncludeUnImportantViews) {
+ mSendRequestForTextAndIncludeUnImportantViews = false;
+ // TextView1 is prefetched here for client 1. Now enqueue a request from a
+ // different client that holds different fetch flags for TextView1
+ sendNodeRequestToController(nodeId, mMockClientCallback2,
+ mMockClient2InteractionId,
+ FLAG_PREFETCH_SIBLINGS | FLAG_INCLUDE_NOT_IMPORTANT_VIEWS);
+ }
+ }
+ });
+
+ // Mockito does not make copies of objects when called. It holds references, so
+ // the captor would point to client 2's results after all requests are processed. Verify
+ // prefetched node immediately
+ doAnswer(invocation -> {
+ List<AccessibilityNodeInfo> prefetched = invocation.getArgument(0);
+ assertEquals(TEXT_VIEW_1_DESCRIPTION, prefetched.get(0).getContentDescription());
+ return null;
+ }).when(mMockClientCallback1).setPrefetchAccessibilityNodeInfoResult(anyList(),
+ eq(mMockClient1InteractionId));
+
+ // Client 1 requests FrameLayout
+ sendNodeRequestToController(ROOT_NODE_ID, mMockClientCallback1,
+ mMockClient1InteractionId, FLAG_PREFETCH_DESCENDANTS);
+
+ mInstrumentation.waitForIdleSync();
+
+ // Verify client 1 gets FrameLayout
+ verify(mMockClientCallback1, times(1))
+ .setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(),
+ eq(mMockClient1InteractionId));
+
+ assertEquals(FRAME_LAYOUT_DESCRIPTION,
+ mFindInfoCaptor.getValue().getContentDescription());
+
+ // Verify client 1 has prefetched results. The only prefetched node is TextView1
+ // (from above doAnswer)
+ verify(mMockClientCallback1, times(1))
+ .setPrefetchAccessibilityNodeInfoResult(mPrefetchInfoListCaptor.capture(),
+ eq(mMockClient1InteractionId));
+
+ // Verify client 2 gets TextView1
+ verify(mMockClientCallback2, times(1))
+ .setFindAccessibilityNodeInfoResult(mFindInfoCaptor.capture(),
+ eq(mMockClient2InteractionId));
+ assertEquals(TEXT_VIEW_1_DESCRIPTION,
+ mFindInfoCaptor.getValue().getContentDescription());
+ // Verify client 2 has TextView2 as a prefetched node
+ verify(mMockClientCallback2, times(1))
+ .setPrefetchAccessibilityNodeInfoResult(mPrefetchInfoListCaptor.capture(),
+ eq(mMockClient2InteractionId));
+ List<AccessibilityNodeInfo> prefetchedNode = mPrefetchInfoListCaptor.getValue();
+ assertEquals(1, prefetchedNode.size());
+ assertEquals(TEXT_VIEW_2_DESCRIPTION, prefetchedNode.get(0).getContentDescription());
+ }
+
+ private void sendNodeRequestToController(long requestedNodeId,
+ IAccessibilityInteractionConnectionCallback callback, int interactionId,
+ int prefetchFlags) {
+ final int processAndThreadId = callback == mMockClientCallback1
+ ? MOCK_CLIENT_1_THREAD_AND_PROCESS_ID
+ : MOCK_CLIENT_2_THREAD_AND_PROCESS_ID;
+
+ mAccessibilityInteractionController.findAccessibilityNodeInfoByAccessibilityIdClientThread(
+ requestedNodeId,
+ null, interactionId,
+ callback, prefetchFlags,
+ processAndThreadId,
+ processAndThreadId, null, null);
+
+ }
+
+ private class TestFrameLayout extends FrameLayout {
+
+ TestFrameLayout(Context context) {
+ super(context);
+ }
+
+ @Override
+ public int getWindowVisibility() {
+ // We aren't attached to a window so let's pretend
+ return VISIBLE;
+ }
+
+ @Override
+ public boolean isShown() {
+ // Controller check
+ return true;
+ }
+
+ @Override
+ public int getAccessibilityViewId() {
+ // static id doesn't reset after tests so return the same one
+ return 0;
+ }
+
+ @Override
+ public void addChildrenForAccessibility(ArrayList<View> outChildren) {
+ // ViewGroup#addChildrenForAccessbility sorting logic will switch these two
+ outChildren.add(mTextView1);
+ outChildren.add(mTextView2);
+ }
+
+ @Override
+ public boolean includeForAccessibility() {
+ return true;
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+ info.setContentDescription(FRAME_LAYOUT_DESCRIPTION);
+ }
+ }
+
+ private class TestTextView extends TextView {
+ TestTextView(Context context) {
+ super(context);
+ }
+
+ @Override
+ public int getWindowVisibility() {
+ return VISIBLE;
+ }
+
+ @Override
+ public boolean isShown() {
+ return true;
+ }
+
+ @Override
+ public int getAccessibilityViewId() {
+ return 1;
+ }
+
+ @Override
+ public boolean includeForAccessibility() {
+ return true;
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+ info.setContentDescription(TEXT_VIEW_1_DESCRIPTION);
+ }
+ }
+
+ private class TestTextView2 extends TextView {
+ TestTextView2(Context context) {
+ super(context);
+ }
+
+ @Override
+ public int getWindowVisibility() {
+ return VISIBLE;
+ }
+
+ @Override
+ public boolean isShown() {
+ return true;
+ }
+
+ @Override
+ public int getAccessibilityViewId() {
+ return 2;
+ }
+
+ @Override
+ public boolean includeForAccessibility() {
+ return true;
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+ info.setContentDescription(TEXT_VIEW_2_DESCRIPTION);
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java b/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java
index 85b8fcb..ebb73e8 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/KeyEventDispatcherTest.java
@@ -39,6 +39,7 @@
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.view.Display;
import android.view.KeyEvent;
import androidx.test.InstrumentationRegistry;
@@ -172,8 +173,8 @@
mFilter1SequenceCaptor.getValue());
assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
- verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
- eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
+ verify(mMockPowerManagerService, times(1)).userActivity(eq(Display.DEFAULT_DISPLAY),
+ anyLong(), eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
assertFalse(isTimeoutPending(mMessageCapturingHandler));
}
@@ -204,8 +205,8 @@
mFilter2SequenceCaptor.getValue());
assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
- verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
- eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
+ verify(mMockPowerManagerService, times(1)).userActivity(eq(Display.DEFAULT_DISPLAY),
+ anyLong(), eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
assertFalse(isTimeoutPending(mMessageCapturingHandler));
}
@@ -221,8 +222,8 @@
mFilter2SequenceCaptor.getValue());
assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
- verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
- eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
+ verify(mMockPowerManagerService, times(1)).userActivity(eq(Display.DEFAULT_DISPLAY),
+ anyLong(), eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
assertFalse(isTimeoutPending(mMessageCapturingHandler));
}
@@ -238,8 +239,8 @@
mFilter2SequenceCaptor.getValue());
assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
- verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
- eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
+ verify(mMockPowerManagerService, times(1)).userActivity(eq(Display.DEFAULT_DISPLAY),
+ anyLong(), eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
assertFalse(isTimeoutPending(mMessageCapturingHandler));
}
@@ -308,8 +309,8 @@
mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0));
assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
- verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
- eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
+ verify(mMockPowerManagerService, times(1)).userActivity(eq(Display.DEFAULT_DISPLAY),
+ anyLong(), eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
}
@Test
@@ -357,8 +358,8 @@
mKeyEventDispatcher.handleMessage(getTimedMessage(mMessageCapturingHandler, 0));
assertFalse(mInputEventsHandler.hasMessages(SEND_FRAMEWORK_KEY_EVENT));
- verify(mMockPowerManagerService, times(1)).userActivity(anyLong(),
- eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
+ verify(mMockPowerManagerService, times(1)).userActivity(eq(Display.DEFAULT_DISPLAY),
+ anyLong(), eq(PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY), eq(0));
}
/*
diff --git a/services/tests/servicestests/src/com/android/server/app/GameManagerServiceSettingsTests.java b/services/tests/servicestests/src/com/android/server/app/GameManagerServiceSettingsTests.java
index 6d4189e..5be05d8 100644
--- a/services/tests/servicestests/src/com/android/server/app/GameManagerServiceSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/app/GameManagerServiceSettingsTests.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertThat;
import android.content.Context;
+import android.platform.test.annotations.Presubmit;
import android.util.AtomicFile;
import android.util.Log;
@@ -37,6 +38,7 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
+@Presubmit
public class GameManagerServiceSettingsTests {
private static final String TAG = "GameServiceSettingsTests";
diff --git a/services/tests/servicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/servicestests/src/com/android/server/app/GameManagerServiceTests.java
index d039a9d..3d0895d 100644
--- a/services/tests/servicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -17,12 +17,14 @@
package com.android.server.app;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
import android.Manifest;
import android.app.GameManager;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.PackageManager;
+import android.platform.test.annotations.Presubmit;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -38,11 +40,11 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
+@Presubmit
public class GameManagerServiceTests {
private static final String TAG = "GameServiceTests";
- private static final String PACKAGE_NAME_0 = "com.android.app0";
- private static final String PACKAGE_NAME_1 = "com.android.app1";
+ private static final String PACKAGE_NAME_INVALID = "com.android.app";
private static final int USER_ID_1 = 1001;
private static final int USER_ID_2 = 1002;
@@ -62,6 +64,7 @@
*
* <p>Passing null reverts to default behavior, which does a real permission check on the
* test package.
+ *
* @param granted One of {@link PackageManager#PERMISSION_GRANTED} or
* {@link PackageManager#PERMISSION_DENIED}.
*/
@@ -103,9 +106,12 @@
@Mock
private MockContext mMockContext;
+ private String mPackageName;
+
@Before
public void setUp() throws Exception {
mMockContext = new MockContext(InstrumentationRegistry.getContext());
+ mPackageName = mMockContext.getPackageName();
}
private void mockModifyGameModeGranted() {
@@ -129,7 +135,7 @@
mockModifyGameModeGranted();
assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
- gameManagerService.getGameMode(PACKAGE_NAME_0, USER_ID_1));
+ gameManagerService.getGameMode(mPackageName, USER_ID_1));
}
/**
@@ -142,9 +148,9 @@
mockModifyGameModeGranted();
- gameManagerService.setGameMode(PACKAGE_NAME_1, GameManager.GAME_MODE_STANDARD, USER_ID_2);
+ gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD, USER_ID_2);
assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
- gameManagerService.getGameMode(PACKAGE_NAME_1, USER_ID_2));
+ gameManagerService.getGameMode(mPackageName, USER_ID_2));
}
/**
@@ -152,40 +158,41 @@
*/
@Test
public void testGameMode() {
- GameManagerService gameManagerService = new GameManagerService(mMockContext);
+ GameManagerService gameManagerService = new GameManagerService(mMockContext);
gameManagerService.onUserStarting(USER_ID_1);
mockModifyGameModeGranted();
assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
- gameManagerService.getGameMode(PACKAGE_NAME_1, USER_ID_1));
- gameManagerService.setGameMode(PACKAGE_NAME_1, GameManager.GAME_MODE_STANDARD, USER_ID_1);
+ gameManagerService.getGameMode(mPackageName, USER_ID_1));
+ gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD, USER_ID_1);
assertEquals(GameManager.GAME_MODE_STANDARD,
- gameManagerService.getGameMode(PACKAGE_NAME_1, USER_ID_1));
- gameManagerService.setGameMode(PACKAGE_NAME_1, GameManager.GAME_MODE_PERFORMANCE,
+ gameManagerService.getGameMode(mPackageName, USER_ID_1));
+ gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE,
USER_ID_1);
assertEquals(GameManager.GAME_MODE_PERFORMANCE,
- gameManagerService.getGameMode(PACKAGE_NAME_1, USER_ID_1));
+ gameManagerService.getGameMode(mPackageName, USER_ID_1));
}
/**
* Test permission.MANAGE_GAME_MODE is checked
*/
@Test
- public void testGetGameModePermissionDenied() {
- GameManagerService gameManagerService = new GameManagerService(mMockContext);
+ public void testGetGameModeInvalidPackageName() {
+ GameManagerService gameManagerService = new GameManagerService(mMockContext);
gameManagerService.onUserStarting(USER_ID_1);
- // Update the game mode so we can read back something valid.
- mockModifyGameModeGranted();
- gameManagerService.setGameMode(PACKAGE_NAME_1, GameManager.GAME_MODE_STANDARD, USER_ID_1);
- assertEquals(GameManager.GAME_MODE_STANDARD,
- gameManagerService.getGameMode(PACKAGE_NAME_1, USER_ID_1));
+ try {
+ assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
+ gameManagerService.getGameMode(PACKAGE_NAME_INVALID,
+ USER_ID_1));
- // Deny permission.MANAGE_GAME_MODE and verify we get back GameManager.GAME_MODE_UNSUPPORTED
- mockModifyGameModeDenied();
- assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
- gameManagerService.getGameMode(PACKAGE_NAME_1, USER_ID_1));
+ fail("GameManagerService failed to generate SecurityException when "
+ + "permission.MANAGE_GAME_MODE is not granted.");
+ } catch (SecurityException ignored) {
+ }
+
+ // The test should throw an exception, so the test is passing if we get here.
}
/**
@@ -193,22 +200,30 @@
*/
@Test
public void testSetGameModePermissionDenied() {
- GameManagerService gameManagerService = new GameManagerService(mMockContext);
+ GameManagerService gameManagerService = new GameManagerService(mMockContext);
gameManagerService.onUserStarting(USER_ID_1);
// Update the game mode so we can read back something valid.
mockModifyGameModeGranted();
- gameManagerService.setGameMode(PACKAGE_NAME_1, GameManager.GAME_MODE_STANDARD, USER_ID_1);
+ gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD, USER_ID_1);
assertEquals(GameManager.GAME_MODE_STANDARD,
- gameManagerService.getGameMode(PACKAGE_NAME_1, USER_ID_1));
+ gameManagerService.getGameMode(mPackageName, USER_ID_1));
// Deny permission.MANAGE_GAME_MODE and verify the game mode is not updated.
mockModifyGameModeDenied();
- gameManagerService.setGameMode(PACKAGE_NAME_1, GameManager.GAME_MODE_PERFORMANCE,
- USER_ID_1);
+ try {
+ gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE,
+ USER_ID_1);
+ fail("GameManagerService failed to generate SecurityException when "
+ + "permission.MANAGE_GAME_MODE is denied.");
+ } catch (SecurityException ignored) {
+ }
+
+ // The test should throw an exception, so the test is passing if we get here.
mockModifyGameModeGranted();
+ // Verify that the Game Mode value wasn't updated.
assertEquals(GameManager.GAME_MODE_STANDARD,
- gameManagerService.getGameMode(PACKAGE_NAME_1, USER_ID_1));
+ gameManagerService.getGameMode(mPackageName, USER_ID_1));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
index 97daea3..0b1c120 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
@@ -67,7 +67,6 @@
.setPropertyName(propertyKeyString)
.addSnippetMatches(
SnippetMatchProto.newBuilder()
- .setValuesIndex(0)
.setExactMatchPosition(29)
.setExactMatchBytes(3)
.setWindowPosition(26)
@@ -174,7 +173,6 @@
.setPropertyName("sender.name")
.addSnippetMatches(
SnippetMatchProto.newBuilder()
- .setValuesIndex(0)
.setExactMatchPosition(0)
.setExactMatchBytes(4)
.setWindowPosition(0)
@@ -186,7 +184,6 @@
.setPropertyName("sender.email")
.addSnippetMatches(
SnippetMatchProto.newBuilder()
- .setValuesIndex(0)
.setExactMatchPosition(0)
.setExactMatchBytes(20)
.setWindowPosition(0)
diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
index deaeb46..8b35af8 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
@@ -276,7 +276,7 @@
0 /* sourceUserId */, 0, "someTag",
invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis,
0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */,
- persistedExecutionTimesUTC, 0 /* innerFlagg */);
+ persistedExecutionTimesUTC, 0 /* innerFlag */, 0 /* dynamicConstraints */);
mTaskStoreUnderTest.add(js);
waitForPendingIo();
diff --git a/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
index 7d9ab37..dd9ae65 100644
--- a/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
@@ -19,6 +19,7 @@
import static com.android.server.job.JobConcurrencyManager.NUM_WORK_TYPES;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER;
+import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER_IMPORTANT;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_EJ;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_FGS;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE;
@@ -29,6 +30,7 @@
import static com.google.common.truth.Truth.assertWithMessage;
import android.annotation.NonNull;
+import android.util.Log;
import android.util.Pair;
import android.util.SparseIntArray;
@@ -52,11 +54,11 @@
@RunWith(AndroidJUnit4.class)
@MediumTest
public class WorkCountTrackerTest {
- private static final String TAG = "WorkerCountTrackerTest";
+ private static final String TAG = "WorkCountTrackerTest";
private static final double[] EQUAL_PROBABILITY_CDF =
buildWorkTypeCdf(1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES,
- 1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES);
+ 1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES);
private Random mRandom;
private WorkCountTracker mWorkCountTracker;
@@ -69,12 +71,15 @@
@NonNull
private static double[] buildWorkTypeCdf(
- double pTop, double pFgs, double pEj, double pBg, double pBgUser) {
- return buildCdf(pTop, pFgs, pEj, pBg, pBgUser);
+ double pTop, double pFgs, double pEj, double pBg, double pBgUserImp, double pBgUser) {
+ return buildCdf(pTop, pFgs, pEj, pBg, pBgUserImp, pBgUser);
}
@NonNull
private static double[] buildCdf(double... probs) {
+ if (probs.length == 0) {
+ throw new IllegalArgumentException("Must supply at least one probability");
+ }
double[] cdf = new double[probs.length];
double sum = 0;
@@ -84,7 +89,9 @@
}
if (Double.compare(1, sum) != 0) {
- throw new IllegalArgumentException("probabilities don't sum to one: " + sum);
+ Log.e(TAG, "probabilities don't sum to one: " + sum);
+ // 1.0/6 doesn't work well in code :/
+ cdf[cdf.length - 1] = 1;
}
return cdf;
}
@@ -111,6 +118,8 @@
case 3:
return WORK_TYPE_BG;
case 4:
+ return WORK_TYPE_BGUSER_IMPORTANT;
+ case 5:
return WORK_TYPE_BGUSER;
default:
throw new IllegalStateException("Unknown work type");
@@ -312,7 +321,7 @@
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final List<Pair<Integer, Integer>> minLimits = List.of();
final double probStop = 0.5;
- final double[] cdf = buildWorkTypeCdf(0.5, 0, 0, 0.5, 0);
+ final double[] cdf = buildWorkTypeCdf(0.5, 0, 0, 0.5, 0, 0);
final double[] numTypesCdf = buildCdf(.5, .3, .15, .05);
final double probStart = 0.5;
@@ -330,7 +339,7 @@
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
final double probStop = 0.5;
- final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 0, 1.0 / 3, 1.0 / 3);
+ final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 0, 1.0 / 3, 0, 1.0 / 3);
final double[] numTypesCdf = buildCdf(.75, .2, .05);
final double probStart = 0.5;
@@ -348,7 +357,7 @@
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final List<Pair<Integer, Integer>> minLimits = List.of();
final double probStop = 0.5;
- final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 0, 1.0 / 3, 1.0 / 3);
+ final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 0, 1.0 / 3, 0, 1.0 / 3);
final double[] numTypesCdf = buildCdf(.05, .95);
final double probStart = 0.5;
@@ -366,7 +375,7 @@
List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
final double probStop = 0.5;
- final double[] cdf = buildWorkTypeCdf(0.1, 0, 0, 0.8, .1);
+ final double[] cdf = buildWorkTypeCdf(0.1, 0, 0, 0.8, 0.02, .08);
final double[] numTypesCdf = buildCdf(.5, .3, .15, .05);
final double probStart = 0.5;
@@ -384,7 +393,7 @@
List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
final double probStop = 0.5;
- final double[] cdf = buildWorkTypeCdf(0.85, 0.05, 0, 0.1, 0);
+ final double[] cdf = buildWorkTypeCdf(0.85, 0.05, 0, 0.1, 0, 0);
final double[] numTypesCdf = buildCdf(1);
final double probStart = 0.5;
@@ -402,7 +411,7 @@
List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
final double probStop = 0.4;
- final double[] cdf = buildWorkTypeCdf(0.1, 0, 0, 0.1, .8);
+ final double[] cdf = buildWorkTypeCdf(0.1, 0, 0, 0.1, 0.05, .75);
final double[] numTypesCdf = buildCdf(0.5, 0.5);
final double probStart = 0.5;
@@ -421,7 +430,7 @@
final List<Pair<Integer, Integer>> minLimits =
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final double probStop = 0.4;
- final double[] cdf = buildWorkTypeCdf(0.8, 0.1, 0, 0.05, 0.05);
+ final double[] cdf = buildWorkTypeCdf(0.8, 0.1, 0, 0.05, 0, 0.05);
final double[] numTypesCdf = buildCdf(1);
final double probStart = 0.5;
@@ -440,7 +449,7 @@
final List<Pair<Integer, Integer>> minLimits =
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final double probStop = 0.5;
- final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.5, 0.5);
+ final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.5, 0, 0.5);
final double[] numTypesCdf = buildCdf(1);
final double probStart = 0.5;
@@ -459,7 +468,7 @@
final List<Pair<Integer, Integer>> minLimits =
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final double probStop = 0.5;
- final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.1, 0.9);
+ final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.1, 0, 0.9);
final double[] numTypesCdf = buildCdf(0.9, 0.1);
final double probStart = 0.5;
@@ -478,7 +487,7 @@
final List<Pair<Integer, Integer>> minLimits =
List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final double probStop = 0.5;
- final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.9, 0.1);
+ final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.9, 0, 0.1);
final double[] numTypesCdf = buildCdf(1);
final double probStart = 0.5;
@@ -496,7 +505,7 @@
final List<Pair<Integer, Integer>> minLimits =
List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2));
final double probStop = 0.4;
- final double[] cdf = buildWorkTypeCdf(0.5, 0, 0.5, 0, 0);
+ final double[] cdf = buildWorkTypeCdf(0.5, 0, 0.5, 0, 0, 0);
final double[] numTypesCdf = buildCdf(0.1, 0.7, 0.2);
final double probStart = 0.5;
@@ -519,7 +528,7 @@
final List<Pair<Integer, Integer>> minLimits =
List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 1));
final double probStop = 0.13;
- final double[] numTypesCdf = buildCdf(0, 0.05, 0.1, 0.8, 0.05);
+ final double[] numTypesCdf = buildCdf(0, 0.05, 0.1, 0.7, 0.1, 0.05);
final double probStart = 0.87;
checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
@@ -536,7 +545,7 @@
List.of(Pair.create(WORK_TYPE_EJ, 5), Pair.create(WORK_TYPE_BG, 4));
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
final double probStop = 0.4;
- final double[] cdf = buildWorkTypeCdf(.1, 0, 0.5, 0.35, 0.05);
+ final double[] cdf = buildWorkTypeCdf(.1, 0, 0.5, 0.35, 0, 0.05);
final double[] numTypesCdf = buildCdf(1);
final double probStart = 0.5;
@@ -556,7 +565,28 @@
final List<Pair<Integer, Integer>> minLimits =
List.of(Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2));
final double probStop = 0.4;
- final double[] cdf = buildWorkTypeCdf(0.01, 0.09, 0.4, 0.1, 0.4);
+ final double[] cdf = buildWorkTypeCdf(0.01, 0.09, 0.4, 0.1, 0, 0.4);
+ final double[] numTypesCdf = buildCdf(0.7, 0.3);
+ final double probStart = 0.5;
+
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ cdf, numTypesCdf, probStop);
+ }
+
+ @Test
+ public void testRandom16() {
+ final Jobs jobs = new Jobs();
+
+ final int numTests = 5000;
+ final int totalMax = 7;
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_EJ, 5), Pair.create(WORK_TYPE_BG, 4),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1),
+ Pair.create(WORK_TYPE_BGUSER, 1));
+ final List<Pair<Integer, Integer>> minLimits =
+ List.of(Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2));
+ final double probStop = 0.4;
+ final double[] cdf = buildWorkTypeCdf(0.01, 0.09, 0.25, 0.05, 0.3, 0.3);
final double[] numTypesCdf = buildCdf(0.7, 0.3);
final double probStart = 0.5;
@@ -748,6 +778,7 @@
/* resPen */ List.of(
Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 2)));
+ Log.d(TAG, "START***#*#*#*#*#*#**#*");
// Test multi-types
checkSimple(6,
/* min */ List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2)),
@@ -764,7 +795,10 @@
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 2),
Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2)),
/* resPen */ List.of(
- Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 1)));
+ // Not checking BG count because the test starts jobs in random order
+ // and if it tries to start 4 BG jobs (2 will run as EJ from EJ|BG), but
+ // the resulting pending will be 3 BG instead of 4 BG.
+ Pair.create(WORK_TYPE_BGUSER, 1)));
}
/** Tests that the counter updates properly when jobs are stopped. */
diff --git a/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java b/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java
index cc18317..a5fedef 100644
--- a/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java
@@ -17,6 +17,7 @@
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER;
+import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER_IMPORTANT;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_EJ;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_FGS;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_TOP;
@@ -49,11 +50,13 @@
private static final String KEY_MAX_FGS = "concurrency_max_fgs_test";
private static final String KEY_MAX_EJ = "concurrency_max_ej_test";
private static final String KEY_MAX_BG = "concurrency_max_bg_test";
+ private static final String KEY_MAX_BGUSER_IMPORTANT = "concurrency_max_bguser_important_test";
private static final String KEY_MAX_BGUSER = "concurrency_max_bguser_test";
private static final String KEY_MIN_TOP = "concurrency_min_top_test";
private static final String KEY_MIN_FGS = "concurrency_min_fgs_test";
private static final String KEY_MIN_EJ = "concurrency_min_ej_test";
private static final String KEY_MIN_BG = "concurrency_min_bg_test";
+ private static final String KEY_MIN_BGUSER_IMPORTANT = "concurrency_min_bguser_important_test";
private static final String KEY_MIN_BGUSER = "concurrency_min_bguser_test";
@After
@@ -68,11 +71,15 @@
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_FGS, null, false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_EJ, null, false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BG, null, false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_MAX_BGUSER_IMPORTANT, null, false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BGUSER, null, false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_TOP, null, false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_FGS, null, false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_EJ, null, false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BG, null, false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_MIN_BGUSER_IMPORTANT, null, false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BGUSER, null, false);
}
@@ -316,19 +323,23 @@
.setInt(KEY_MIN_EJ, 3)
.setInt(KEY_MAX_BG, 13)
.setInt(KEY_MIN_BG, 4)
- .setInt(KEY_MAX_BGUSER, 12)
- .setInt(KEY_MIN_BGUSER, 5)
+ .setInt(KEY_MAX_BGUSER_IMPORTANT, 12)
+ .setInt(KEY_MIN_BGUSER_IMPORTANT, 5)
+ .setInt(KEY_MAX_BGUSER, 11)
+ .setInt(KEY_MIN_BGUSER, 6)
.build(),
/*default*/ 9,
/* min */ List.of(Pair.create(WORK_TYPE_BG, 9)),
/* max */ List.of(Pair.create(WORK_TYPE_BG, 9)),
/*expected*/ true, 16,
/* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_FGS, 2),
- Pair.create(WORK_TYPE_EJ, 3),
- Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 5)),
+ Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 4),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 5),
+ Pair.create(WORK_TYPE_BGUSER, 6)),
/* max */
List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_FGS, 15),
- Pair.create(WORK_TYPE_EJ, 14),
- Pair.create(WORK_TYPE_BG, 13), Pair.create(WORK_TYPE_BGUSER, 12)));
+ Pair.create(WORK_TYPE_EJ, 14), Pair.create(WORK_TYPE_BG, 13),
+ Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 12),
+ Pair.create(WORK_TYPE_BGUSER, 11)));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index a896f1b..b51f4df 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -44,6 +44,7 @@
import android.content.pm.UserInfo;
import android.hardware.rebootescrow.IRebootEscrow;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.os.UserManager;
@@ -62,6 +63,7 @@
import org.mockito.ArgumentCaptor;
import java.io.File;
+import java.io.IOException;
import java.util.ArrayList;
import javax.crypto.SecretKey;
@@ -181,6 +183,18 @@
}
@Override
+ public int getLoadEscrowDataRetryLimit() {
+ // Try two times
+ return 2;
+ }
+
+ @Override
+ public int getLoadEscrowDataRetryIntervalSeconds() {
+ // Retry in 1 seconds
+ return 1;
+ }
+
+ @Override
public void reportMetric(boolean success) {
mInjected.reportMetric(success);
}
@@ -448,6 +462,46 @@
}
@Test
+ public void loadRebootEscrowDataIfAvailable_ServerBased_RetrySuccess() throws Exception {
+ setServerBasedRebootEscrowProvider();
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertTrue(mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture());
+
+ when(mServiceConnection.unwrap(any(), anyLong()))
+ .thenThrow(new IOException())
+ .thenAnswer(invocation -> invocation.getArgument(0));
+
+ HandlerThread thread = new HandlerThread("RebootEscrowManagerTest");
+ thread.start();
+ mService.loadRebootEscrowDataIfAvailable(new Handler(thread.getLooper()));
+ // Sleep 5s for the retry to complete
+ Thread.sleep(5 * 1000);
+ verify(mServiceConnection, times(2)).unwrap(any(), anyLong());
+ assertTrue(metricsSuccessCaptor.getValue());
+ verify(mKeyStoreManager).clearKeyStoreEncryptionKey();
+ }
+
+ @Test
public void loadRebootEscrowDataIfAvailable_TooManyBootsInBetween_NoMetrics() throws Exception {
when(mInjected.getBootCount()).thenReturn(0);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 2d6605a..c0a38b8 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -239,8 +239,8 @@
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
assertTrue(mService.hasPendingEscrowToken(PRIMARY_USER_ID));
- mService.verifyCredential(password, PRIMARY_USER_ID, 0 /* flags */)
- .getResponseCode();
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
+ password, PRIMARY_USER_ID, 0 /* flags */).getResponseCode());
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
assertFalse(mService.hasPendingEscrowToken(PRIMARY_USER_ID));
@@ -268,8 +268,8 @@
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
- mService.verifyCredential(password, PRIMARY_USER_ID, 0 /* flags */)
- .getResponseCode();
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
+ password, PRIMARY_USER_ID, 0 /* flags */).getResponseCode());
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mLocalService.setLockCredentialWithToken(nonePassword(), handle, token, PRIMARY_USER_ID);
@@ -294,8 +294,8 @@
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
- mService.verifyCredential(password, PRIMARY_USER_ID, 0 /* flags */)
- .getResponseCode();
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
+ password, PRIMARY_USER_ID, 0 /* flags */).getResponseCode());
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mService.setLockCredential(pattern, password, PRIMARY_USER_ID);
@@ -369,6 +369,36 @@
}
@Test
+ public void testActivateMultipleEscrowTokens() throws Exception {
+ byte[] token0 = "some-high-entropy-secure-token-0".getBytes();
+ byte[] token1 = "some-high-entropy-secure-token-1".getBytes();
+ byte[] token2 = "some-high-entropy-secure-token-2".getBytes();
+
+ LockscreenCredential password = newPassword("password");
+ LockscreenCredential pattern = newPattern("123654");
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
+
+ long handle0 = mLocalService.addEscrowToken(token0, PRIMARY_USER_ID, null);
+ long handle1 = mLocalService.addEscrowToken(token1, PRIMARY_USER_ID, null);
+ long handle2 = mLocalService.addEscrowToken(token2, PRIMARY_USER_ID, null);
+
+ // Activate token
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
+ password, PRIMARY_USER_ID, 0 /* flags */).getResponseCode());
+
+ // Verify tokens work
+ assertTrue(mLocalService.isEscrowTokenActive(handle0, PRIMARY_USER_ID));
+ assertTrue(mLocalService.setLockCredentialWithToken(
+ pattern, handle0, token0, PRIMARY_USER_ID));
+ assertTrue(mLocalService.isEscrowTokenActive(handle1, PRIMARY_USER_ID));
+ assertTrue(mLocalService.setLockCredentialWithToken(
+ pattern, handle1, token1, PRIMARY_USER_ID));
+ assertTrue(mLocalService.isEscrowTokenActive(handle2, PRIMARY_USER_ID));
+ assertTrue(mLocalService.setLockCredentialWithToken(
+ pattern, handle2, token2, PRIMARY_USER_ID));
+ }
+
+ @Test
public void testSetLockCredentialWithTokenFailsWithoutLockScreen() throws Exception {
LockscreenCredential password = newPassword("password");
LockscreenCredential pattern = newPattern("123654");
@@ -494,8 +524,8 @@
reset(mDevicePolicyManager);
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
- mService.verifyCredential(password, PRIMARY_USER_ID, 0 /* flags */)
- .getResponseCode();
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
+ password, PRIMARY_USER_ID, 0 /* flags */).getResponseCode());
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mService.onCleanupUser(PRIMARY_USER_ID);
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 13c3919..fb01ff6 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -108,14 +108,13 @@
import android.content.pm.Signature;
import android.content.pm.UserInfo;
import android.net.ConnectivityManager;
-import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkPolicyListener;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkPolicy;
-import android.net.NetworkState;
+import android.net.NetworkStateSnapshot;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
@@ -242,8 +241,7 @@
private @Mock IActivityManager mActivityManager;
private @Mock INetworkManagementService mNetworkManager;
- private @Mock IConnectivityManager mConnManager;
- private @Mock ConnectivityManager mConnectivityManager;
+ private @Mock ConnectivityManager mConnManager;
private @Mock NotificationManager mNotifManager;
private @Mock PackageManager mPackageManager;
private @Mock IPackageManager mIpm;
@@ -361,7 +359,7 @@
case Context.NOTIFICATION_SERVICE:
return mNotifManager;
case Context.CONNECTIVITY_SERVICE:
- return mConnectivityManager;
+ return mConnManager;
case Context.USER_SERVICE:
return mUserManager;
default:
@@ -390,7 +388,7 @@
mFutureIntent = newRestrictBackgroundChangedFuture();
mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager,
mNetworkManager, mIpm, mClock, mPolicyDir, true);
- mService.bindConnectivityManager(mConnManager);
+ mService.bindConnectivityManager();
mPolicyListener = new NetworkPolicyListenerAnswer(mService);
// Sets some common expectations.
@@ -429,7 +427,7 @@
when(mUserManager.getUsers()).thenReturn(buildUserInfoList());
when(mNetworkManager.isBandwidthControlEnabled()).thenReturn(true);
when(mNetworkManager.setDataSaverModeEnabled(anyBoolean())).thenReturn(true);
- doNothing().when(mConnectivityManager)
+ doNothing().when(mConnManager)
.registerNetworkCallback(any(), mNetworkCallbackCaptor.capture());
// Create the expected carrier config
@@ -1072,7 +1070,7 @@
@FlakyTest
@Test
public void testNetworkPolicyAppliedCycleLastMonth() throws Exception {
- NetworkState[] state = null;
+ List<NetworkStateSnapshot> snapshots = null;
NetworkStats stats = null;
final int CYCLE_DAY = 15;
@@ -1084,8 +1082,8 @@
// first, pretend that wifi network comes online. no policy active,
// which means we shouldn't push limit to interface.
- state = new NetworkState[] { buildWifi() };
- when(mConnManager.getAllNetworkState()).thenReturn(state);
+ snapshots = List.of(buildWifi());
+ when(mConnManager.getAllNetworkStateSnapshot()).thenReturn(snapshots);
mPolicyListener.expect().onMeteredIfacesChanged(any());
mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
@@ -1093,7 +1091,7 @@
// now change cycle to be on 15th, and test in early march, to verify we
// pick cycle day in previous month.
- when(mConnManager.getAllNetworkState()).thenReturn(state);
+ when(mConnManager.getAllNetworkStateSnapshot()).thenReturn(snapshots);
// pretend that 512 bytes total have happened
stats = new NetworkStats(getElapsedRealtime(), 1)
@@ -1339,7 +1337,7 @@
@Test
public void testMeteredNetworkWithoutLimit() throws Exception {
- NetworkState[] state = null;
+ List<NetworkStateSnapshot> snapshots = null;
NetworkStats stats = null;
final long TIME_FEB_15 = 1171497600000L;
@@ -1349,12 +1347,12 @@
setCurrentTimeMillis(TIME_MAR_10);
// bring up wifi network with metered policy
- state = new NetworkState[] { buildWifi() };
+ snapshots = List.of(buildWifi());
stats = new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, 0L, 0L, 0L, 0L);
{
- when(mConnManager.getAllNetworkState()).thenReturn(state);
+ when(mConnManager.getAllNetworkStateSnapshot()).thenReturn(snapshots);
when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
currentTimeMillis())).thenReturn(stats.getTotalBytes());
@@ -1477,7 +1475,8 @@
}
private PersistableBundle setupUpdateMobilePolicyCycleTests() throws RemoteException {
- when(mConnManager.getAllNetworkState()).thenReturn(new NetworkState[0]);
+ when(mConnManager.getAllNetworkStateSnapshot())
+ .thenReturn(new ArrayList<NetworkStateSnapshot>());
setupTelephonySubscriptionManagers(FAKE_SUB_ID, FAKE_SUBSCRIBER_ID);
@@ -1489,7 +1488,8 @@
@Test
public void testUpdateMobilePolicyCycleWithNullConfig() throws RemoteException {
- when(mConnManager.getAllNetworkState()).thenReturn(new NetworkState[0]);
+ when(mConnManager.getAllNetworkStateSnapshot())
+ .thenReturn(new ArrayList<NetworkStateSnapshot>());
setupTelephonySubscriptionManagers(FAKE_SUB_ID, FAKE_SUBSCRIBER_ID);
@@ -1720,7 +1720,7 @@
reset(mTelephonyManager, mNetworkManager, mNotifManager);
expectMobileDefaults();
- expectNetworkState(true /* roaming */);
+ expectNetworkStateSnapshot(true /* roaming */);
mService.updateNetworks();
@@ -1749,7 +1749,7 @@
// Capabilities change to roaming
final ConnectivityManager.NetworkCallback callback = mNetworkCallbackCaptor.getValue();
assertNotNull(callback);
- expectNetworkState(true /* roaming */);
+ expectNetworkStateSnapshot(true /* roaming */);
callback.onCapabilitiesChanged(
new Network(TEST_NET_ID),
buildNetworkCapabilities(TEST_SUB_ID, true /* roaming */));
@@ -2035,14 +2035,14 @@
mService.setNetworkPolicies(policies);
}
- private static NetworkState buildWifi() {
+ private static NetworkStateSnapshot buildWifi() {
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(TEST_IFACE);
final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
networkCapabilities.addTransportType(TRANSPORT_WIFI);
networkCapabilities.setSSID(TEST_SSID);
- return new NetworkState(TYPE_WIFI, prop, networkCapabilities, new Network(TEST_NET_ID),
- null);
+ return new NetworkStateSnapshot(new Network(TEST_NET_ID), networkCapabilities, prop,
+ null /*subscriberId*/, TYPE_WIFI);
}
private void expectHasInternetPermission(int uid, boolean hasIt) throws Exception {
@@ -2059,15 +2059,14 @@
PackageManager.PERMISSION_DENIED);
}
- private void expectNetworkState(boolean roaming) throws Exception {
+ private void expectNetworkStateSnapshot(boolean roaming) throws Exception {
when(mCarrierConfigManager.getConfigForSubId(eq(TEST_SUB_ID)))
.thenReturn(mCarrierConfig);
- when(mConnManager.getAllNetworkState()).thenReturn(new NetworkState[] {
- new NetworkState(TYPE_MOBILE,
- buildLinkProperties(TEST_IFACE),
- buildNetworkCapabilities(TEST_SUB_ID, roaming),
- new Network(TEST_NET_ID), TEST_IMSI)
- });
+ List<NetworkStateSnapshot> snapshots = List.of(new NetworkStateSnapshot(
+ new Network(TEST_NET_ID),
+ buildNetworkCapabilities(TEST_SUB_ID, roaming),
+ buildLinkProperties(TEST_IFACE), TEST_IMSI, TYPE_MOBILE));
+ when(mConnManager.getAllNetworkStateSnapshot()).thenReturn(snapshots);
}
private void expectDefaultCarrierConfig() throws Exception {
@@ -2078,7 +2077,7 @@
private TelephonyManager expectMobileDefaults() throws Exception {
TelephonyManager tmSub = setupTelephonySubscriptionManagers(TEST_SUB_ID, TEST_IMSI);
doNothing().when(tmSub).setPolicyDataEnabled(anyBoolean());
- expectNetworkState(false /* roaming */);
+ expectNetworkStateSnapshot(false /* roaming */);
return tmSub;
}
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index ea27331..6e5fbd0 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -764,7 +764,7 @@
createService();
startSystem();
- mService.getBinderServiceInstance().userActivity(mClock.now(),
+ mService.getBinderServiceInstance().userActivity(Display.DEFAULT_DISPLAY, mClock.now(),
PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
verify(mInattentiveSleepWarningControllerMock, never()).show();
@@ -773,7 +773,7 @@
verify(mInattentiveSleepWarningControllerMock, never()).dismiss(anyBoolean());
when(mInattentiveSleepWarningControllerMock.isShown()).thenReturn(true);
- mService.getBinderServiceInstance().userActivity(mClock.now(),
+ mService.getBinderServiceInstance().userActivity(Display.DEFAULT_DISPLAY, mClock.now(),
PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
verify(mInattentiveSleepWarningControllerMock, times(1)).dismiss(true);
}
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java
index 4634e12..2a3c2c4 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java
@@ -100,16 +100,17 @@
return EFFECT_DURATION;
}
- public void compose(VibrationEffect.Composition.PrimitiveEffect[] effect,
+ public long compose(VibrationEffect.Composition.PrimitiveEffect[] effect,
long vibrationId) {
VibrationEffect.Composed composed = new VibrationEffect.Composed(Arrays.asList(effect));
mEffects.add(composed);
applyLatency();
- long duration = EFFECT_DURATION * effect.length;
+ long duration = 0;
for (VibrationEffect.Composition.PrimitiveEffect e : effect) {
- duration += e.delay;
+ duration += EFFECT_DURATION + e.delay;
}
scheduleListener(duration, vibrationId);
+ return duration;
}
public void setExternalControl(boolean enabled) {
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java
index 815aa8e..bad3e4c 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
@@ -202,7 +203,7 @@
VibrationEffect.Prebaked effect = (VibrationEffect.Prebaked)
VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK);
- controller.on(effect, 11);
+ assertEquals(10L, controller.on(effect, 11));
assertTrue(controller.isVibrating());
verify(mNativeWrapperMock).perform(eq((long) VibrationEffect.EFFECT_CLICK),
@@ -212,13 +213,14 @@
@Test
public void on_withComposed_performsEffect() {
mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+ when(mNativeWrapperMock.compose(any(), anyLong())).thenReturn(15L);
VibratorController controller = createController();
VibrationEffect.Composed effect = (VibrationEffect.Composed)
VibrationEffect.startComposition()
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 0.5f, 10)
.compose();
- controller.on(effect, 12);
+ assertEquals(15L, controller.on(effect, 12));
ArgumentCaptor<VibrationEffect.Composition.PrimitiveEffect[]> primitivesCaptor =
ArgumentCaptor.forClass(VibrationEffect.Composition.PrimitiveEffect[].class);
diff --git a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
new file mode 100644
index 0000000..3025a95
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2021 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.server.policy;
+
+import static android.view.KeyEvent.ACTION_DOWN;
+import static android.view.KeyEvent.ACTION_UP;
+import static android.view.KeyEvent.KEYCODE_POWER;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.server.policy.SingleKeyGestureDetector.KEY_LONGPRESS;
+import static com.android.server.policy.SingleKeyGestureDetector.KEY_VERYLONGPRESS;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.os.SystemClock;
+import android.view.KeyEvent;
+import android.view.ViewConfiguration;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test class for {@link SingleKeyGestureDetector}.
+ *
+ * Build/Install/Run:
+ * atest WmTests:SingleKeyGestureTests
+ */
+public class SingleKeyGestureTests {
+ private SingleKeyGestureDetector mDetector;
+
+ private int mMaxMultiPressPowerCount = 2;
+
+ private CountDownLatch mShortPressed = new CountDownLatch(1);
+ private CountDownLatch mLongPressed = new CountDownLatch(1);
+ private CountDownLatch mVeryLongPressed = new CountDownLatch(1);
+ private CountDownLatch mMultiPressed = new CountDownLatch(1);
+
+ private final Instrumentation mInstrumentation = getInstrumentation();
+ private final Context mContext = mInstrumentation.getTargetContext();
+ private long mWaitTimeout;
+ private long mLongPressTime;
+ private long mVeryLongPressTime;
+
+ @Before
+ public void setUp() {
+ mDetector = new SingleKeyGestureDetector(mContext);
+ initSingleKeyGestureRules();
+ mWaitTimeout = ViewConfiguration.getMultiPressTimeout() + 50;
+ mLongPressTime = ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout() + 50;
+ mVeryLongPressTime = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_veryLongPressTimeout) + 50;
+ }
+
+ private void initSingleKeyGestureRules() {
+ mDetector.addRule(new SingleKeyGestureDetector.SingleKeyRule(KEYCODE_POWER,
+ KEY_LONGPRESS | KEY_VERYLONGPRESS) {
+ @Override
+ int getMaxMultiPressCount() {
+ return mMaxMultiPressPowerCount;
+ }
+ @Override
+ public void onPress(long downTime) {
+ mShortPressed.countDown();
+ }
+
+ @Override
+ void onLongPress(long downTime) {
+ mLongPressed.countDown();
+ }
+
+ @Override
+ void onVeryLongPress(long downTime) {
+ mVeryLongPressed.countDown();
+ }
+
+ @Override
+ void onMultiPress(long downTime, int count) {
+ mMultiPressed.countDown();
+ assertEquals(mMaxMultiPressPowerCount, count);
+ }
+ });
+ }
+
+ private void pressKey(long eventTime, int keyCode, long pressTime) {
+ final KeyEvent keyDown = new KeyEvent(eventTime, eventTime, ACTION_DOWN,
+ keyCode, 0 /* repeat */, 0 /* metaState */);
+ mDetector.interceptKey(keyDown);
+
+ // keep press down.
+ try {
+ Thread.sleep(pressTime);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ eventTime += pressTime;
+ final KeyEvent keyUp = new KeyEvent(eventTime, eventTime, ACTION_UP,
+ keyCode, 0 /* repeat */, 0 /* metaState */);
+
+ mDetector.interceptKey(keyUp);
+ }
+
+ @Test
+ public void testShortPress() throws InterruptedException {
+ final long eventTime = SystemClock.uptimeMillis();
+ pressKey(eventTime, KEYCODE_POWER, 0 /* pressTime */);
+ assertTrue(mShortPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testLongPress() throws InterruptedException {
+ final long eventTime = SystemClock.uptimeMillis();
+ pressKey(eventTime, KEYCODE_POWER, mLongPressTime);
+ assertTrue(mLongPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testVeryLongPress() throws InterruptedException {
+ final long eventTime = SystemClock.uptimeMillis();
+ pressKey(eventTime, KEYCODE_POWER, mVeryLongPressTime);
+ assertTrue(mVeryLongPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testMultiPress() throws InterruptedException {
+ final long eventTime = SystemClock.uptimeMillis();
+ pressKey(eventTime, KEYCODE_POWER, 0 /* pressTime */);
+ pressKey(eventTime, KEYCODE_POWER, 0 /* pressTime */);
+ assertTrue(mMultiPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 137cf65..09a436c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -518,6 +518,7 @@
TYPE_WALLPAPER, TYPE_APPLICATION);
final WindowState wallpaper = windows[0];
assertTrue(wallpaper.mIsWallpaper);
+ wallpaper.mToken.asWallpaperToken().setVisibility(false);
// By default WindowState#mWallpaperVisible is false.
assertFalse(wallpaper.isVisible());
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index b73c664..2f1d7eb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -655,7 +655,7 @@
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
// Portrait fixed app without max aspect.
- prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
+ prepareUnresizable(mActivity, /* maxAspect= */ 0, SCREEN_ORIENTATION_PORTRAIT);
final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
final Rect activityBounds = new Rect(mActivity.getBounds());
@@ -676,6 +676,96 @@
}
@Test
+ public void testDisplayIgnoreOrientationRequest_fixedOrientationAppRespectMinAspectRatio() {
+ // Set up a display in landscape and ignoring orientation request.
+ setUpDisplaySizeWithApp(2800, 1400);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ // Portrait fixed app with min aspect ratio higher that aspect ratio override for fixed
+ // orientation letterbox.
+ mActivity.mWmService.setFixedOrientationLetterboxAspectRatio(1.1f);
+ mActivity.info.minAspectRatio = 3;
+ prepareUnresizable(mActivity, /* maxAspect= */ 0, SCREEN_ORIENTATION_PORTRAIT);
+
+ final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
+ final Rect activityBounds = new Rect(mActivity.getBounds());
+
+ // Display shouldn't be rotated.
+ assertEquals(SCREEN_ORIENTATION_UNSPECIFIED,
+ mActivity.mDisplayContent.getLastOrientation());
+ assertTrue(displayBounds.width() > displayBounds.height());
+
+ // App should launch in fixed orientation letterbox.
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFalse(mActivity.inSizeCompatMode());
+
+ // Activity bounds should respect minimum aspect ratio for activity.
+ assertEquals(displayBounds.height(), activityBounds.height());
+ assertEquals((int) Math.rint(displayBounds.height() / mActivity.info.minAspectRatio),
+ activityBounds.width());
+ }
+
+ @Test
+ public void testDisplayIgnoreOrientationRequest_fixedOrientationAppRespectMaxAspectRatio() {
+ // Set up a display in landscape and ignoring orientation request.
+ setUpDisplaySizeWithApp(2800, 1400);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ // Portrait fixed app with max aspect ratio lower that aspect ratio override for fixed
+ // orientation letterbox.
+ mActivity.mWmService.setFixedOrientationLetterboxAspectRatio(3);
+ prepareUnresizable(mActivity, /* maxAspect= */ 2, SCREEN_ORIENTATION_PORTRAIT);
+
+ final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
+ final Rect activityBounds = new Rect(mActivity.getBounds());
+
+ // Display shouldn't be rotated.
+ assertEquals(SCREEN_ORIENTATION_UNSPECIFIED,
+ mActivity.mDisplayContent.getLastOrientation());
+ assertTrue(displayBounds.width() > displayBounds.height());
+
+ // App should launch in fixed orientation letterbox.
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFalse(mActivity.inSizeCompatMode());
+
+ // Activity bounds should respect maximum aspect ratio for activity.
+ assertEquals(displayBounds.height(), activityBounds.height());
+ assertEquals((int) Math.rint(displayBounds.height() / mActivity.info.maxAspectRatio),
+ activityBounds.width());
+ }
+
+ @Test
+ public void testDisplayIgnoreOrientationRequest_fixedOrientationAppWithAspectRatioOverride() {
+ // Set up a display in landscape and ignoring orientation request.
+ setUpDisplaySizeWithApp(2800, 1400);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ // Portrait fixed app with min aspect ratio higher that aspect ratio override for fixed
+ // orientation letterbox.
+ final float fixedOrientationLetterboxAspectRatio = 1.1f;
+ mActivity.mWmService.setFixedOrientationLetterboxAspectRatio(
+ fixedOrientationLetterboxAspectRatio);
+ prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
+
+ final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
+ final Rect activityBounds = new Rect(mActivity.getBounds());
+
+ // Display shouldn't be rotated.
+ assertEquals(SCREEN_ORIENTATION_UNSPECIFIED,
+ mActivity.mDisplayContent.getLastOrientation());
+ assertTrue(displayBounds.width() > displayBounds.height());
+
+ // App should launch in fixed orientation letterbox.
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFalse(mActivity.inSizeCompatMode());
+
+ // Activity bounds should respect aspect ratio override for fixed orientation letterbox.
+ assertEquals(displayBounds.height(), activityBounds.height());
+ assertEquals((int) Math.rint(displayBounds.height() / fixedOrientationLetterboxAspectRatio),
+ activityBounds.width());
+ }
+
+ @Test
public void
testDisplayIgnoreOrientationRequest_orientationLetterboxBecameSizeCompatAfterRotate() {
// Set up a display in landscape and ignoring orientation request.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index c3eb5c4..ecb8b60 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -16,8 +16,11 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -257,4 +260,21 @@
task.resolveOverrideConfiguration(parentConfig);
assertThat(resolvedOverride.getWindowingMode()).isEqualTo(WINDOWING_MODE_UNDEFINED);
}
+
+ @Test
+ public void testHandlesOrientationChangeFromDescendant() {
+ final Task rootTask = createTaskStackOnDisplay(WINDOWING_MODE_MULTI_WINDOW,
+ ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final Task leafTask1 = createTaskInStack(rootTask, 0 /* userId */);
+ final Task leafTask2 = createTaskInStack(rootTask, 0 /* userId */);
+ leafTask1.getWindowConfiguration().setActivityType(ACTIVITY_TYPE_HOME);
+ leafTask2.getWindowConfiguration().setActivityType(ACTIVITY_TYPE_STANDARD);
+
+ assertEquals(leafTask2, rootTask.getTopChild());
+ assertTrue(rootTask.handlesOrientationChangeFromDescendant());
+ // Treat orientation request from home as handled.
+ assertTrue(leafTask1.handlesOrientationChangeFromDescendant());
+ // Orientation request from standard activity in multi window will not be handled.
+ assertFalse(leafTask2.handlesOrientationChangeFromDescendant());
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 401ace03c..79ef868 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -25,11 +25,14 @@
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
+import static android.window.TransitionInfo.isIndependent;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -316,9 +319,9 @@
mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */));
final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, wallpaperWindowToken,
"wallpaperWindow");
- wallpaperWindow.mWallpaperVisible = false;
+ wallpaperWindowToken.setVisibleRequested(false);
transition.collect(wallpaperWindowToken);
- wallpaperWindow.mWallpaperVisible = true;
+ wallpaperWindowToken.setVisibleRequested(true);
wallpaperWindow.mHasSurface = true;
// doesn't matter which order collected since participants is a set
@@ -343,6 +346,76 @@
tasks[showWallpaperTask].mRemoteToken.toWindowContainerToken()).getFlags());
}
+ @Test
+ public void testIndependent() {
+ final Transition transition = createTestTransition(TRANSIT_OPEN);
+ ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+ ArraySet<WindowContainer> participants = transition.mParticipants;
+ ITaskOrganizer mockOrg = mock(ITaskOrganizer.class);
+
+ final Task openTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final Task openInOpenTask = createTaskInStack(openTask, 0);
+ final ActivityRecord openInOpen = createActivityRecord(openInOpenTask);
+
+ final Task changeTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ final Task changeInChangeTask = createTaskInStack(changeTask, 0);
+ final Task openInChangeTask = createTaskInStack(changeTask, 0);
+ final ActivityRecord changeInChange = createActivityRecord(changeInChangeTask);
+ final ActivityRecord openInChange = createActivityRecord(openInChangeTask);
+ // set organizer for everything so that they all get added to transition info
+ for (Task t : new Task[]{
+ openTask, openInOpenTask, changeTask, changeInChangeTask, openInChangeTask}) {
+ t.mTaskOrganizer = mockOrg;
+ }
+
+ // Start states.
+ changes.put(openTask, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
+ changes.put(changeTask, new Transition.ChangeInfo(true /* vis */, false /* exChg */));
+ changes.put(openInOpenTask, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
+ changes.put(openInChangeTask, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
+ changes.put(changeInChangeTask,
+ new Transition.ChangeInfo(true /* vis */, false /* exChg */));
+ changes.put(openInOpen, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
+ changes.put(openInChange, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
+ changes.put(changeInChange, new Transition.ChangeInfo(true /* vis */, false /* exChg */));
+ fillChangeMap(changes, openTask);
+ // End states.
+ changeInChange.mVisibleRequested = true;
+ openInOpen.mVisibleRequested = true;
+ openInChange.mVisibleRequested = true;
+
+ int transit = TRANSIT_OLD_TASK_OPEN;
+ int flags = 0;
+
+ // Check full promotion from leaf
+ participants.add(changeInChange);
+ participants.add(openInOpen);
+ participants.add(openInChange);
+ // Explicitly add changeTask (to test independence with parents)
+ participants.add(changeTask);
+ ArraySet<WindowContainer> targets = Transition.calculateTargets(participants, changes);
+ TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
+ // Root changes should always be considered independent
+ assertTrue(isIndependent(
+ info.getChange(openTask.mRemoteToken.toWindowContainerToken()), info));
+ assertTrue(isIndependent(
+ info.getChange(changeTask.mRemoteToken.toWindowContainerToken()), info));
+
+ // Children of a open/close change are not independent
+ assertFalse(isIndependent(
+ info.getChange(openInOpenTask.mRemoteToken.toWindowContainerToken()), info));
+
+ // Non-root changes are not independent
+ assertFalse(isIndependent(
+ info.getChange(changeInChangeTask.mRemoteToken.toWindowContainerToken()), info));
+
+ // open/close within a change are independent
+ assertTrue(isIndependent(
+ info.getChange(openInChangeTask.mRemoteToken.toWindowContainerToken()), info));
+ }
+
/** Fill the change map with all the parents of top. Change maps are usually fully populated */
private static void fillChangeMap(ArrayMap<WindowContainer, Transition.ChangeInfo> changes,
WindowContainer top) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index d1d0ac6..8b4e947 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -24,6 +24,8 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OPEN;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
@@ -49,7 +51,9 @@
import android.view.InsetsState;
import android.view.RoundedCorners;
import android.view.Surface;
+import android.view.SurfaceControl;
import android.view.WindowManager;
+import android.window.ITransitionPlayer;
import androidx.test.filters.SmallTest;
@@ -135,7 +139,8 @@
int expectedWidth = (int) (wallpaperWidth * (displayHeight / (double) wallpaperHeight));
// Check that the wallpaper is correctly scaled
- assertEquals(new Rect(0, 0, expectedWidth, displayHeight), wallpaperWindow.getFrame());
+ assertEquals(expectedWidth, wallpaperWindow.getFrame().width());
+ assertEquals(displayHeight, wallpaperWindow.getFrame().height());
Rect portraitFrame = wallpaperWindow.getFrame();
// Rotate the display
@@ -297,6 +302,46 @@
assertFalse(mAppWindow.mActivityRecord.hasFixedRotationTransform());
}
+ @Test
+ public void testWallpaperTokenVisibility() {
+ final DisplayContent dc = mWm.mRoot.getDefaultDisplay();
+ final WallpaperWindowToken token = new WallpaperWindowToken(mWm, mock(IBinder.class),
+ true, dc, true /* ownerCanManageAppTokens */);
+ final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, token,
+ "wallpaperWindow");
+ wallpaperWindow.setHasSurface(true);
+
+ // Set-up mock shell transitions
+ final IBinder mockBinder = mock(IBinder.class);
+ final ITransitionPlayer mockPlayer = mock(ITransitionPlayer.class);
+ doReturn(mockBinder).when(mockPlayer).asBinder();
+ mWm.mAtmService.getTransitionController().registerTransitionPlayer(mockPlayer);
+
+ Transition transit =
+ mWm.mAtmService.getTransitionController().createTransition(TRANSIT_OPEN);
+
+ // wallpaper windows are immediately visible when set to visible even during a transition
+ token.setVisibility(true);
+ assertTrue(wallpaperWindow.isVisible());
+ assertTrue(token.isVisibleRequested());
+ assertTrue(token.isVisible());
+ mWm.mAtmService.getTransitionController().abort(transit);
+
+ // In a transition, setting invisible should ONLY set requestedVisible false; otherwise
+ // wallpaper should remain "visible" until transition is over.
+ transit = mWm.mAtmService.getTransitionController().createTransition(TRANSIT_CLOSE);
+ transit.start();
+ token.setVisibility(false);
+ assertTrue(wallpaperWindow.isVisible());
+ assertFalse(token.isVisibleRequested());
+ assertTrue(token.isVisible());
+
+ transit.onTransactionReady(transit.getSyncId(), mock(SurfaceControl.Transaction.class));
+ transit.finishTransition();
+ assertFalse(wallpaperWindow.isVisible());
+ assertFalse(token.isVisible());
+ }
+
private WindowState createWallpaperTargetWindow(DisplayContent dc) {
final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService)
.setTask(dc.getDefaultTaskDisplayArea().getRootHomeTask())
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index ebc5c4f..1f38f46 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -245,6 +245,9 @@
private WindowToken createWindowToken(
DisplayContent dc, int windowingMode, int activityType, int type) {
+ if (type == TYPE_WALLPAPER) {
+ return createWallpaperToken(dc);
+ }
if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
return createTestWindowToken(type, dc);
}
@@ -252,6 +255,11 @@
return createActivityRecord(dc, windowingMode, activityType);
}
+ private WindowToken createWallpaperToken(DisplayContent dc) {
+ return new WallpaperWindowToken(mWm, mock(IBinder.class), true /* explicit */, dc,
+ true /* ownerCanManageAppTokens */);
+ }
+
WindowState createAppWindow(Task task, int type, String name) {
final ActivityRecord activity = createNonAttachedActivityRecord(task.getDisplayContent());
task.addChild(activity, 0);
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index b1e6683..f35b9e2 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -303,7 +303,9 @@
// FLUSH_TO_DISK is a private event.
&& event.mEventType != Event.FLUSH_TO_DISK
// DEVICE_SHUTDOWN is added to event list after reboot.
- && event.mEventType != Event.DEVICE_SHUTDOWN) {
+ && event.mEventType != Event.DEVICE_SHUTDOWN
+ // We aren't interested in every instance of the APP_COMPONENT_USED event.
+ && event.mEventType != Event.APP_COMPONENT_USED) {
currentDailyStats.addEvent(event);
}
@@ -1176,6 +1178,8 @@
return "USER_STOPPED";
case Event.LOCUS_ID_SET:
return "LOCUS_ID_SET";
+ case Event.APP_COMPONENT_USED:
+ return "APP_COMPONENT_USED";
default:
return "UNKNOWN_TYPE_" + eventType;
}
diff --git a/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java b/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java
index c7e7cd5..179248d 100644
--- a/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java
+++ b/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java
@@ -65,6 +65,11 @@
// compact form of the via header key
private static final String VIA_SIP_HEADER_KEY_COMPACT = "v";
+ // call-id header key
+ private static final String CALL_ID_SIP_HEADER_KEY = "call-id";
+ // compact form of the call-id header key
+ private static final String CALL_ID_SIP_HEADER_KEY_COMPACT = "i";
+
/**
* @return true if the SIP message start line is considered a request (based on known request
* methods).
@@ -124,6 +129,17 @@
return null;
}
+ /**
+ * Return the call-id header key's associated value.
+ * @param headerString The string containing the headers of the SIP message.
+ */
+ public static String getCallId(String headerString) {
+ // search for the call-Id header, there should only be one in the header.
+ List<Pair<String, String>> headers = parseHeaders(headerString, true,
+ CALL_ID_SIP_HEADER_KEY, CALL_ID_SIP_HEADER_KEY_COMPACT);
+ return !headers.isEmpty() ? headers.get(0).second : null;
+ }
+
private static String[] splitStartLineAndVerify(String startLine) {
String[] splitLine = startLine.split(" ");
if (isStartLineMalformed(splitLine)) return null;
diff --git a/telephony/java/android/telephony/TelephonyDisplayInfo.java b/telephony/java/android/telephony/TelephonyDisplayInfo.java
index 5b5570b..2f89bfb 100644
--- a/telephony/java/android/telephony/TelephonyDisplayInfo.java
+++ b/telephony/java/android/telephony/TelephonyDisplayInfo.java
@@ -30,8 +30,8 @@
* necessarily a precise or accurate representation of the current state and should be treated
* accordingly.
* To be notified of changes in TelephonyDisplayInfo, use
- * {@link TelephonyManager#registerPhoneStateListener} with a {@link PhoneStateListener}
- * that implements {@link PhoneStateListener.DisplayInfoChangedListener}.
+ * {@link TelephonyManager#registerTelephonyCallback} with a {@link TelephonyCallback}
+ * that implements {@link TelephonyCallback.DisplayInfoListener}.
* Override the onDisplayInfoChanged() method to handle the broadcast.
*/
public final class TelephonyDisplayInfo implements Parcelable {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index b46440d..c48bd21 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -5949,25 +5949,20 @@
* @param events The telephony state(s) of interest to the listener,
* as a bitwise-OR combination of {@link PhoneStateListener}
* LISTEN_ flags.
- * @deprecated Use {@link #registerPhoneStateListener(Executor, PhoneStateListener)}.
+ * @deprecated Use {@link #registerTelephonyCallback(Executor, TelephonyCallback)}.
*/
@Deprecated
public void listen(PhoneStateListener listener, int events) {
- if (!listener.isExecutorSet()) {
- throw new IllegalStateException("PhoneStateListener should be created on a thread "
- + "with Looper.myLooper() != null");
- }
- boolean notifyNow = getITelephony() != null;
- mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);
- if (mTelephonyRegistryMgr != null) {
- if (events != PhoneStateListener.LISTEN_NONE) {
- mTelephonyRegistryMgr.registerPhoneStateListenerWithEvents(mSubId,
- getOpPackageName(), getAttributionTag(), listener, events, notifyNow);
- } else {
- unregisterPhoneStateListener(listener);
- }
+ if (mContext == null) return;
+ boolean notifyNow = (getITelephony() != null);
+ TelephonyRegistryManager telephonyRegistry =
+ (TelephonyRegistryManager)
+ mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
+ if (telephonyRegistry != null) {
+ telephonyRegistry.listenFromListener(mSubId, getOpPackageName(),
+ getAttributionTag(), listener, events, notifyNow);
} else {
- throw new IllegalStateException("telephony service is null.");
+ Rlog.w(TAG, "telephony registry not ready.");
}
}
@@ -15049,66 +15044,69 @@
}
/**
- * Registers a listener object to receive notification of changes
- * in specified telephony states.
+ * Registers a callback object to receive notification of changes in specified telephony states.
* <p>
- * To register a listener, pass a {@link PhoneStateListener} which implements
+ * To register a callback, pass a {@link TelephonyCallback} which implements
* interfaces of events. For example,
- * FakeServiceStateChangedListener extends {@link PhoneStateListener} implements
- * {@link PhoneStateListener.ServiceStateChangedListener}.
+ * FakeServiceStateCallback extends {@link TelephonyCallback} implements
+ * {@link TelephonyCallback.ServiceStateListener}.
*
* At registration, and when a specified telephony state changes, the telephony manager invokes
- * the appropriate callback method on the listener object and passes the current (updated)
+ * the appropriate callback method on the callback object and passes the current (updated)
* values.
* <p>
*
* If this TelephonyManager object has been created with {@link #createForSubscriptionId},
* applies to the given subId. Otherwise, applies to
- * {@link SubscriptionManager#getDefaultSubscriptionId()}. To listen events for multiple subIds,
- * pass a separate listener object to each TelephonyManager object created with
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}. To register events for multiple
+ * subIds, pass a separate callback object to each TelephonyManager object created with
* {@link #createForSubscriptionId}.
*
* Note: if you call this method while in the middle of a binder transaction, you <b>must</b>
* call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A
* {@link SecurityException} will be thrown otherwise.
*
- * This API should be used sparingly -- large numbers of listeners will cause system
- * instability. If a process has registered too many listeners without unregistering them, it
- * may encounter an {@link IllegalStateException} when trying to register more listeners.
+ * This API should be used sparingly -- large numbers of callbacks will cause system
+ * instability. If a process has registered too many callbacks without unregistering them, it
+ * may encounter an {@link IllegalStateException} when trying to register more callbacks.
*
* @param executor The executor of where the callback will execute.
- * @param listener The {@link PhoneStateListener} object to register.
+ * @param callback The {@link TelephonyCallback} object to register.
*/
- public void registerPhoneStateListener(@NonNull @CallbackExecutor Executor executor,
- @NonNull PhoneStateListener listener) {
- if (executor == null || listener == null) {
- throw new IllegalArgumentException("PhoneStateListener and executor must be non-null");
+ public void registerTelephonyCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull TelephonyCallback callback) {
+ if (executor == null || callback == null) {
+ throw new IllegalArgumentException("TelephonyCallback and executor must be non-null");
}
mTelephonyRegistryMgr = (TelephonyRegistryManager)
mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
if (mTelephonyRegistryMgr != null) {
- mTelephonyRegistryMgr.registerPhoneStateListener(executor, mSubId,
- getOpPackageName(), getAttributionTag(), listener, getITelephony() != null);
+ mTelephonyRegistryMgr.registerTelephonyCallback(executor, mSubId, getOpPackageName(),
+ getAttributionTag(), callback, getITelephony() != null);
} else {
throw new IllegalStateException("telephony service is null.");
}
}
/**
- * Unregister an existing {@link PhoneStateListener}.
+ * Unregister an existing {@link TelephonyCallback}.
*
- * @param listener The {@link PhoneStateListener} object to unregister.
+ * @param callback The {@link TelephonyCallback} object to unregister.
*/
- public void unregisterPhoneStateListener(@NonNull PhoneStateListener listener) {
+ public void unregisterTelephonyCallback(@NonNull TelephonyCallback callback) {
if (mContext == null) {
throw new IllegalStateException("telephony service is null.");
}
+ if (callback.callback == null) {
+ return;
+ }
+
mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);
if (mTelephonyRegistryMgr != null) {
- mTelephonyRegistryMgr.unregisterPhoneStateListener(mSubId, getOpPackageName(),
- getAttributionTag(), listener, getITelephony() != null);
+ mTelephonyRegistryMgr.unregisterTelephonyCallback(mSubId, getOpPackageName(),
+ getAttributionTag(), callback, getITelephony() != null);
} else {
throw new IllegalStateException("telephony service is null.");
}
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 0ab679f..8fb3b4d 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -869,8 +869,12 @@
* An integer key representing the voice over IMS opt-in provisioning status for the
* associated subscription. Determines whether the user can see for voice services over
* IMS.
- * <p>
- * Use {@link #PROVISIONING_VALUE_ENABLED} to enable VoIMS provisioning and
+ *
+ * <p> The flag will force to show the VoLTE option in settings irrespective of others VoLTE
+ * carrier config which hide the VoLTE option (e.g.
+ * {@link CarrierConfigManager#KEY_HIDE_ENHANCED_4G_LTE_BOOL}).
+ *
+ * <p>Use {@link #PROVISIONING_VALUE_ENABLED} to enable VoIMS provisioning and
* {@link #PROVISIONING_VALUE_DISABLED} to disable VoIMS provisioning.
* @see #setProvisioningIntValue(int, int)
* @see #getProvisioningIntValue(int)
diff --git a/telephony/java/android/telephony/ims/SipMessage.java b/telephony/java/android/telephony/ims/SipMessage.java
index 9cfa640..ad6d73c 100644
--- a/telephony/java/android/telephony/ims/SipMessage.java
+++ b/telephony/java/android/telephony/ims/SipMessage.java
@@ -19,6 +19,7 @@
import static java.nio.charset.StandardCharsets.UTF_8;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Build;
import android.os.Parcel;
@@ -46,6 +47,8 @@
private final String mStartLine;
private final String mHeaderSection;
private final byte[] mContent;
+ private final String mViaBranchParam;
+ private final String mCallIdParam;
/**
* Represents a partially encoded SIP message.
@@ -63,6 +66,9 @@
mStartLine = startLine;
mHeaderSection = headerSection;
mContent = content;
+
+ mViaBranchParam = SipMessageParsingUtils.getTransactionId(mHeaderSection);
+ mCallIdParam = SipMessageParsingUtils.getCallId(mHeaderSection);
}
/**
@@ -73,6 +79,8 @@
mHeaderSection = source.readString();
mContent = new byte[source.readInt()];
source.readByteArray(mContent);
+ mViaBranchParam = source.readString();
+ mCallIdParam = source.readString();
}
/**
@@ -97,6 +105,25 @@
return mContent;
}
+ /**
+ * @return the branch parameter enclosed in the Via header key's value. See RFC 3261 section
+ * 20.42 for more information on the Via header. If {@code null}, then there was either no
+ * Via parameter found in this SIP message's headers or no branch parameter found in the
+ * Via header.
+ */
+ public @Nullable String getViaBranchParameter() {
+ return mViaBranchParam;
+ }
+
+ /**
+ * @return the value associated with the call-id header of this SIP message. See RFC 3261
+ * section 20.8 for more information on the call-id header. If {@code null}, then there was no
+ * call-id header found in this SIP message's headers.
+ */
+ public @Nullable String getCallIdParameter() {
+ return mCallIdParam;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -108,6 +135,8 @@
dest.writeString(mHeaderSection);
dest.writeInt(mContent.length);
dest.writeByteArray(mContent);
+ dest.writeString(mViaBranchParam);
+ dest.writeString(mCallIdParam);
}
public static final @NonNull Creator<SipMessage> CREATOR = new Creator<SipMessage>() {
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
index 9d91901..739946b 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
@@ -31,8 +31,6 @@
import android.text.TextUtils;
import android.util.Log;
-import com.android.internal.telephony.SipMessageParsingUtils;
-
import java.util.ArrayList;
import java.util.Set;
import java.util.concurrent.Executor;
@@ -188,7 +186,7 @@
}
private void notifyLocalMessageFailedToBeReceived(SipMessage m, int reason) {
- String transactionId = SipMessageParsingUtils.getTransactionId(m.getHeaderSection());
+ String transactionId = m.getViaBranchParameter();
if (TextUtils.isEmpty(transactionId)) {
Log.w(LOG_TAG, "failure to parse SipMessage.");
throw new IllegalArgumentException("Malformed SipMessage, can not determine "
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
index c877aca..3cd2726 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
@@ -32,8 +32,6 @@
import android.util.ArraySet;
import android.util.Log;
-import com.android.internal.telephony.SipMessageParsingUtils;
-
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.Executor;
@@ -268,7 +266,7 @@
}
private void notifyLocalMessageFailedToSend(SipMessage m, int reason) {
- String transactionId = SipMessageParsingUtils.getTransactionId(m.getHeaderSection());
+ String transactionId = m.getViaBranchParameter();
if (TextUtils.isEmpty(transactionId)) {
Log.w(LOG_TAG, "sendMessage detected a malformed SipMessage and can not get a "
+ "transaction ID.");
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index e87f3d9..7e04baa 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1200,15 +1200,6 @@
void shutdownMobileRadios();
/**
- * Set phone radio type and access technology.
- *
- * @param rafs an RadioAccessFamily array to indicate all phone's
- * new radio access family. The length of RadioAccessFamily
- * must equ]]al to phone count.
- */
- void setRadioCapability(in RadioAccessFamily[] rafs);
-
- /**
* Get phone radio type and access technology.
*
* @param phoneId which phone you want to get
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 62ccb1a0..6bf4492 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -771,6 +771,24 @@
</intent-filter>
</activity>
+ <activity android:name="StretchShaderActivity"
+ android:label="RenderEffect/Stretch"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name="EdgeEffectStretchActivity"
+ android:label="RenderEffect/EdgeEffect stretch"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
<activity android:name="TextActivity"
android:label="Text/Simple Text"
android:theme="@android:style/Theme.NoTitleBar"
diff --git a/tests/HwAccelerationTest/res/layout/stretch_layout.xml b/tests/HwAccelerationTest/res/layout/stretch_layout.xml
new file mode 100644
index 0000000..df5f297
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/stretch_layout.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/scroll_view"
+ android:edgeEffectType="stretch"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <HorizontalScrollView
+ android:id="@+id/horizontal_scroll_view"
+ android:edgeEffectType="stretch"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ </LinearLayout>
+ </HorizontalScrollView>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:src="@drawable/sunset1"/>
+
+ </LinearLayout>
+</ScrollView>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/EdgeEffectStretchActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/EdgeEffectStretchActivity.java
new file mode 100644
index 0000000..f0e6299
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/EdgeEffectStretchActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 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.test.hwui;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.HorizontalScrollView;
+import android.widget.ScrollView;
+
+public class EdgeEffectStretchActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.stretch_layout);
+ HorizontalScrollView hsv = findViewById(R.id.horizontal_scroll_view);
+ hsv.setStretchDistance(50f);
+
+ ScrollView sv = findViewById(R.id.scroll_view);
+ sv.setStretchDistance(50f);
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
new file mode 100644
index 0000000..9bd933a
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
@@ -0,0 +1,540 @@
+/*
+ * Copyright (C) 2021 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.test.hwui;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.RecordingCanvas;
+import android.graphics.Rect;
+import android.graphics.RenderEffect;
+import android.graphics.RuntimeShader;
+import android.graphics.Shader;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+public class StretchShaderActivity extends Activity {
+
+ private static final float MAX_STRETCH_INTENSITY = 1.5f;
+ private static final float STRETCH_AFFECTED_DISTANCE = 1.0f;
+
+ private float mScrollX = 0f;
+ private float mScrollY = 0f;
+
+ private float mMaxStretchIntensity = MAX_STRETCH_INTENSITY;
+ private float mStretchAffectedDistance = STRETCH_AFFECTED_DISTANCE;
+
+ private float mOverscrollX = 25f;
+ private float mOverscrollY = 25f;
+
+ private RuntimeShader mRuntimeShader;
+ private ImageView mImageView;
+ private ImageView mTestImageView;
+
+ private Bitmap mBitmap;
+
+ private StretchDrawable mStretchDrawable = new StretchDrawable();
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout linearLayout = new LinearLayout(this);
+ linearLayout.setOrientation(LinearLayout.VERTICAL);
+
+ mBitmap = ((BitmapDrawable) getDrawable(R.drawable.sunset1)).getBitmap();
+ mRuntimeShader = new RuntimeShader(SKSL, false);
+
+ BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP,
+ Shader.TileMode.CLAMP);
+ mRuntimeShader.setInputShader("uContentTexture", bitmapShader);
+
+ mImageView = new ImageView(this);
+
+ mImageView.setRenderEffect(RenderEffect.createShaderEffect(mRuntimeShader));
+ mImageView.setImageDrawable(new ColorDrawable(Color.CYAN));
+
+ TextView overscrollXText = new TextView(this);
+ overscrollXText.setText("Overscroll X");
+
+ SeekBar overscrollXBar = new SeekBar(this);
+ overscrollXBar.setProgress(0);
+ overscrollXBar.setMin(-50);
+ overscrollXBar.setMax(50);
+ overscrollXBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mOverscrollX = progress;
+ overscrollXText.setText("Overscroll X: " + mOverscrollX);
+ updateShader();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+
+ }
+ });
+
+ TextView overscrollYText = new TextView(this);
+ overscrollYText.setText("Overscroll Y");
+
+ SeekBar overscrollYBar = new SeekBar(this);
+ overscrollYBar.setProgress(0);
+ overscrollYBar.setMin(-50);
+ overscrollYBar.setMax(50);
+ overscrollYBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mOverscrollY = progress;
+ overscrollYText.setText("Overscroll Y: " + mOverscrollY);
+ updateShader();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+
+ }
+ });
+
+ TextView scrollXText = new TextView(this);
+ scrollXText.setText("Scroll X");
+ SeekBar scrollXSeekBar = new SeekBar(this);
+ scrollXSeekBar.setMin(0);
+ scrollXSeekBar.setMax(100);
+ scrollXSeekBar.setProgress(0);
+ scrollXSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mScrollX = (progress / 100f);
+ scrollXText.setText("Scroll X: " + mScrollY);
+ updateShader();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+
+ }
+ });
+
+ TextView scrollYText = new TextView(this);
+ scrollYText.setText("Scroll Y");
+ SeekBar scrollYSeekBar = new SeekBar(this);
+ scrollYSeekBar.setMin(0);
+ scrollYSeekBar.setMax(100);
+ scrollYSeekBar.setProgress(0);
+ scrollYSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mScrollY = (progress / 100f);
+ scrollYText.setText("Scroll Y: " + mScrollY);
+ updateShader();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+
+ }
+ });
+
+ TextView stretchIntensityText = new TextView(this);
+ int stretchProgress = (int) (mMaxStretchIntensity * 100);
+ stretchIntensityText.setText("StretchIntensity: " + mMaxStretchIntensity);
+ SeekBar stretchIntensitySeekbar = new SeekBar(this);
+ stretchIntensitySeekbar.setProgress(stretchProgress);
+ stretchIntensitySeekbar.setMin(1);
+ stretchIntensitySeekbar.setMax((int) (MAX_STRETCH_INTENSITY * 100));
+ stretchIntensitySeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mMaxStretchIntensity = progress / 100f;
+ stretchIntensityText.setText("StretchIntensity: " + mMaxStretchIntensity);
+ updateShader();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+
+ }
+ });
+
+ TextView stretchDistanceText = new TextView(this);
+ stretchDistanceText.setText("StretchDistance");
+ SeekBar stretchDistanceSeekbar = new SeekBar(this);
+ stretchDistanceSeekbar.setMin(0);
+ stretchDistanceSeekbar.setProgress((int) (mStretchAffectedDistance * 100));
+ stretchDistanceSeekbar.setMax(100);
+ stretchDistanceSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mStretchAffectedDistance = progress / 100f;
+ stretchDistanceText.setText("StretchDistance: " + mStretchAffectedDistance);
+ updateShader();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+
+ }
+ });
+
+
+ linearLayout.addView(mImageView,
+ new LinearLayout.LayoutParams(
+ mBitmap.getWidth(),
+ mBitmap.getHeight())
+ );
+
+ linearLayout.addView(overscrollXText,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ));
+ linearLayout.addView(overscrollXBar,
+ new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ );
+
+ linearLayout.addView(overscrollYText,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ));
+ linearLayout.addView(overscrollYBar,
+ new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ );
+
+ linearLayout.addView(scrollXText,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ));
+
+ linearLayout.addView(scrollXSeekBar,
+ new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ ));
+
+ linearLayout.addView(scrollYText,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ));
+
+ linearLayout.addView(scrollYSeekBar,
+ new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ ));
+
+ linearLayout.addView(stretchIntensityText,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ )
+ );
+
+ linearLayout.addView(stretchIntensitySeekbar,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ )
+ );
+
+ linearLayout.addView(stretchDistanceText,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ));
+
+ linearLayout.addView(stretchDistanceSeekbar,
+ new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ));
+
+ ImageView test = new ImageView(this);
+ mStretchDrawable.setBitmap(mBitmap);
+ test.setImageDrawable(mStretchDrawable);
+
+ mTestImageView = test;
+ linearLayout.addView(test,
+ new LinearLayout.LayoutParams(mBitmap.getWidth(), mBitmap.getHeight()));
+
+ setContentView(linearLayout);
+
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mImageView.getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ updateShader();
+ mImageView.getViewTreeObserver().removeOnPreDrawListener(this);
+ return false;
+ }
+ });
+ }
+
+ private void updateShader() {
+ final float width = mImageView.getWidth();
+ final float height = mImageView.getHeight();
+ final float distanceNotStretched = mStretchAffectedDistance;
+ final float normOverScrollDistX = mOverscrollX / width;
+ final float normOverScrollDistY = mOverscrollY / height;
+ final float distanceStretchedX =
+ mStretchAffectedDistance
+ / (1 + Math.abs(normOverScrollDistX) * mMaxStretchIntensity);
+ final float distanceStretchedY =
+ mStretchAffectedDistance
+ / (1 + Math.abs(normOverScrollDistY) * mMaxStretchIntensity);
+ final float diffX = distanceStretchedX - distanceNotStretched;
+ final float diffY = distanceStretchedY - distanceNotStretched;
+ float uScrollX = mScrollX;
+ float uScrollY = mScrollY;
+
+ mRuntimeShader.setUniform("uMaxStretchIntensity", mMaxStretchIntensity);
+ mRuntimeShader.setUniform("uStretchAffectedDist", mStretchAffectedDistance);
+ mRuntimeShader.setUniform("uDistanceStretchedX", distanceStretchedX);
+ mRuntimeShader.setUniform("uDistanceStretchedY", distanceStretchedY);
+ mRuntimeShader.setUniform("uDistDiffX", diffX);
+ mRuntimeShader.setUniform("uDistDiffY", diffY);
+ mRuntimeShader.setUniform("uOverscrollX", normOverScrollDistX);
+ mRuntimeShader.setUniform("uOverscrollY", normOverScrollDistY);
+ mRuntimeShader.setUniform("uScrollX", uScrollX);
+ mRuntimeShader.setUniform("uScrollY", uScrollY);
+ mRuntimeShader.setUniform("viewportWidth", width);
+ mRuntimeShader.setUniform("viewportHeight", height);
+
+ mImageView.setRenderEffect(RenderEffect.createShaderEffect(mRuntimeShader));
+
+ mStretchDrawable.setStretchDistance(mStretchAffectedDistance);
+ mStretchDrawable.setOverscrollX(normOverScrollDistX);
+ mStretchDrawable.setOverscrollY(normOverScrollDistY);
+ }
+
+ private static class StretchDrawable extends Drawable {
+
+ private float mStretchDistance = 0;
+ private float mOverScrollX = 0f;
+ private float mOverScrollY = 0f;
+ private Bitmap mBitmap = null;
+
+ public void setStretchDistance(float stretchDistance) {
+ mStretchDistance = stretchDistance;
+ invalidateSelf();
+ }
+
+ public void setOverscrollX(float overscrollX) {
+ mOverScrollX = overscrollX;
+ invalidateSelf();
+ }
+
+ public void setOverscrollY(float overscrollY) {
+ mOverScrollY = overscrollY;
+ invalidateSelf();
+ }
+
+ public void setBitmap(Bitmap bitmap) {
+ mBitmap = bitmap;
+ invalidateSelf();
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (mStretchDistance > 0 && canvas instanceof RecordingCanvas) {
+ Rect bounds = getBounds();
+ ((RecordingCanvas) canvas).mNode.stretch(
+ 0,
+ 0,
+ bounds.width(),
+ bounds.height(),
+ mOverScrollX,
+ mOverScrollY,
+ mStretchDistance
+ );
+ }
+ if (mBitmap != null) {
+ canvas.drawBitmap(mBitmap, 0f, 0f, null);
+ }
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+
+ }
+
+ @Override
+ public int getOpacity() {
+ return 0;
+ }
+ }
+
+ private static final String SKSL = "in shader uContentTexture;\n"
+ + "uniform float uMaxStretchIntensity; // multiplier to apply to scale effect\n"
+ + "uniform float uStretchAffectedDist; // Maximum percentage to stretch beyond bounds"
+ + " of target\n"
+ + "\n"
+ + "// Distance stretched as a function of the normalized overscroll times scale "
+ + "intensity\n"
+ + "uniform float uDistanceStretchedX;\n"
+ + "uniform float uDistanceStretchedY;\n"
+ + "uniform float uDistDiffX;\n"
+ + "uniform float uDistDiffY; // Difference between the peak stretch amount and "
+ + "overscroll amount normalized\n"
+ + "uniform float uScrollX; // Horizontal offset represented as a ratio of pixels "
+ + "divided by the target width\n"
+ + "uniform float uScrollY; // Vertical offset represented as a ratio of pixels "
+ + "divided by the target height\n"
+ + "uniform float uOverscrollX; // Normalized overscroll amount in the horizontal "
+ + "direction\n"
+ + "uniform float uOverscrollY; // Normalized overscroll amount in the vertical "
+ + "direction\n"
+ + "\n"
+ + "uniform float viewportWidth; // target height in pixels\n"
+ + "uniform float viewportHeight; // target width in pixels\n"
+ + "\n"
+ + "vec4 main(vec2 coord) {\n"
+ + "\n"
+ + " // Normalize SKSL pixel coordinate into a unit vector\n"
+ + " vec2 uv = vec2(coord.x / viewportWidth, coord.y / viewportHeight);\n"
+ + " float inU = uv.x;\n"
+ + " float inV = uv.y;\n"
+ + " float outU;\n"
+ + " float outV;\n"
+ + " float stretchIntensity;\n"
+ + "\n"
+ + " // Add the normalized scroll position within scrolling list\n"
+ + " inU += uScrollX;\n"
+ + " inV += uScrollY;\n"
+ + "\n"
+ + " outU = inU;\n"
+ + " outV = inV;\n"
+ + " if (uOverscrollX > 0) {\n"
+ + " if (inU <= uStretchAffectedDist) {\n"
+ + " inU = uStretchAffectedDist - inU;\n"
+ + " float posBasedVariation = smoothstep(0., uStretchAffectedDist, inU);\n"
+ + " stretchIntensity = uMaxStretchIntensity * uOverscrollX * "
+ + "posBasedVariation;\n"
+ + " outU = uDistanceStretchedX - (inU / (1. + stretchIntensity));\n"
+ + " } else {\n"
+ + " outU = uDistDiffX + inU;\n"
+ + " }\n"
+ + " }\n"
+ + "\n"
+ + " if (uOverscrollX < 0) {\n"
+ + " float stretchAffectedDist = 1. - uStretchAffectedDist;\n"
+ + " if (inU >= stretchAffectedDist) {\n"
+ + " inU = inU - stretchAffectedDist;\n"
+ + " float posBasedVariation = (smoothstep(0., uStretchAffectedDist, "
+ + "inU));\n"
+ + " stretchIntensity = uMaxStretchIntensity * (-uOverscrollX) * "
+ + "posBasedVariation;\n"
+ + " outU = 1 - (uDistanceStretchedX - (inU / (1. + stretchIntensity)))"
+ + ";\n"
+ + " } else if (inU < stretchAffectedDist) {\n"
+ + " outU = -uDistDiffX + inU;\n"
+ + " }\n"
+ + " }\n"
+ + "\n"
+ + " if (uOverscrollY > 0) {\n"
+ + " if (inV <= uStretchAffectedDist) {\n"
+ + " inV = uStretchAffectedDist - inV;\n"
+ + " float posBasedVariation = smoothstep(0., uStretchAffectedDist, inV);\n"
+ + " stretchIntensity = uMaxStretchIntensity * uOverscrollY * "
+ + "posBasedVariation;\n"
+ + " outV = uDistanceStretchedY - (inV / (1. + stretchIntensity));\n"
+ + " } else if (inV >= uStretchAffectedDist) {\n"
+ + " outV = uDistDiffY + inV;\n"
+ + " }\n"
+ + " }\n"
+ + "\n"
+ + " if (uOverscrollY < 0) {\n"
+ + " float stretchAffectedDist = 1. - uStretchAffectedDist;\n"
+ + " if (inV >= stretchAffectedDist) {\n"
+ + " inV = inV - stretchAffectedDist;\n"
+ + " float posBasedVariation = (smoothstep(0., uStretchAffectedDist, inV));\n"
+ + " stretchIntensity = uMaxStretchIntensity * (-uOverscrollY) * "
+ + "posBasedVariation;\n"
+ + " outV = 1 - (uDistanceStretchedY - (inV / (1. + stretchIntensity)));\n"
+ + " } else if (inV < stretchAffectedDist) {\n"
+ + " outV = -uDistDiffY + inV;\n"
+ + " }\n"
+ + " }\n"
+ + "\n"
+ + " uv.x = outU;\n"
+ + " uv.y = outV;\n"
+ + " coord.x = uv.x * viewportWidth;\n"
+ + " coord.y = uv.y * viewportHeight;\n"
+ + " return sample(uContentTexture, coord);\n"
+ + "}";
+}
diff --git a/tests/Input/src/com/android/test/input/InputEventAssignerTest.kt b/tests/Input/src/com/android/test/input/InputEventAssignerTest.kt
new file mode 100644
index 0000000..2e985fb
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/InputEventAssignerTest.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2021 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.test.input
+
+import android.view.InputDevice.SOURCE_MOUSE
+import android.view.InputDevice.SOURCE_TOUCHSCREEN
+import android.view.InputEventAssigner
+import android.view.KeyEvent
+import android.view.MotionEvent
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+/**
+ * Create a MotionEvent with the provided action, eventTime, and source
+ */
+fun createMotionEvent(action: Int, eventTime: Long, source: Int): MotionEvent {
+ val downTime: Long = 10
+ val x = 1f
+ val y = 2f
+ val pressure = 3f
+ val size = 1f
+ val metaState = 0
+ val xPrecision = 0f
+ val yPrecision = 0f
+ val deviceId = 1
+ val edgeFlags = 0
+ val displayId = 0
+ return MotionEvent.obtain(downTime, eventTime, action, x, y, pressure, size, metaState,
+ xPrecision, yPrecision, deviceId, edgeFlags, source, displayId)
+}
+
+fun createKeyEvent(action: Int, eventTime: Long): KeyEvent {
+ val code = KeyEvent.KEYCODE_A
+ val repeat = 0
+ return KeyEvent(eventTime, eventTime, action, code, repeat)
+}
+
+class InputEventAssignerTest {
+ companion object {
+ private const val TAG = "InputEventAssignerTest"
+ }
+
+ /**
+ * A single MOVE event should be assigned to the next available frame.
+ */
+ @Test
+ fun testTouchGesture() {
+ val assigner = InputEventAssigner()
+ val event = createMotionEvent(MotionEvent.ACTION_MOVE, 10, SOURCE_TOUCHSCREEN)
+ val eventId = assigner.processEvent(event)
+ assertEquals(event.id, eventId)
+ }
+
+ /**
+ * DOWN event should be used until a vsync comes in. After vsync, the latest event should be
+ * produced.
+ */
+ @Test
+ fun testTouchDownWithMove() {
+ val assigner = InputEventAssigner()
+ val down = createMotionEvent(MotionEvent.ACTION_DOWN, 10, SOURCE_TOUCHSCREEN)
+ val move1 = createMotionEvent(MotionEvent.ACTION_MOVE, 12, SOURCE_TOUCHSCREEN)
+ val move2 = createMotionEvent(MotionEvent.ACTION_MOVE, 13, SOURCE_TOUCHSCREEN)
+ val move3 = createMotionEvent(MotionEvent.ACTION_MOVE, 14, SOURCE_TOUCHSCREEN)
+ val move4 = createMotionEvent(MotionEvent.ACTION_MOVE, 15, SOURCE_TOUCHSCREEN)
+ var eventId = assigner.processEvent(down)
+ assertEquals(down.id, eventId)
+ eventId = assigner.processEvent(move1)
+ assertEquals(down.id, eventId)
+ eventId = assigner.processEvent(move2)
+ // Even though we already had 2 move events, there was no choreographer callback yet.
+ // Therefore, we should still get the id of the down event
+ assertEquals(down.id, eventId)
+
+ // Now send CALLBACK_INPUT to the assigner. It should provide the latest motion event
+ assigner.onChoreographerCallback()
+ eventId = assigner.processEvent(move3)
+ assertEquals(move3.id, eventId)
+ eventId = assigner.processEvent(move4)
+ assertEquals(move4.id, eventId)
+ }
+
+ /**
+ * Similar to the above test, but with SOURCE_MOUSE. Since we don't have down latency
+ * concept for non-touchscreens, the latest input event will be used.
+ */
+ @Test
+ fun testMouseDownWithMove() {
+ val assigner = InputEventAssigner()
+ val down = createMotionEvent(MotionEvent.ACTION_DOWN, 10, SOURCE_MOUSE)
+ val move1 = createMotionEvent(MotionEvent.ACTION_MOVE, 12, SOURCE_MOUSE)
+ var eventId = assigner.processEvent(down)
+ assertEquals(down.id, eventId)
+ eventId = assigner.processEvent(move1)
+ assertEquals(move1.id, eventId)
+ }
+
+ /**
+ * KeyEvents are processed immediately, so the latest event should be returned.
+ */
+ @Test
+ fun testKeyEvent() {
+ val assigner = InputEventAssigner()
+ val down = createKeyEvent(KeyEvent.ACTION_DOWN, 20)
+ var eventId = assigner.processEvent(down)
+ assertEquals(down.id, eventId)
+ val up = createKeyEvent(KeyEvent.ACTION_UP, 21)
+ eventId = assigner.processEvent(up)
+ // DOWN is only sticky for Motions, not for keys
+ assertEquals(up.id, eventId)
+ assigner.onChoreographerCallback()
+ val down2 = createKeyEvent(KeyEvent.ACTION_DOWN, 22)
+ eventId = assigner.processEvent(down2)
+ assertEquals(down2.id, eventId)
+ }
+}
diff --git a/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt b/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt
index c19e5cc..c01d32b 100644
--- a/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt
+++ b/tests/Input/src/com/android/test/input/ViewFrameInfoTest.kt
@@ -17,6 +17,7 @@
package com.android.test.input
import android.graphics.FrameInfo
+import android.os.IInputConstants.INVALID_INPUT_EVENT_ID
import android.os.SystemClock
import android.view.ViewFrameInfo
import com.google.common.truth.Truth.assertThat
@@ -33,8 +34,7 @@
@Before
fun setUp() {
mViewFrameInfo.reset()
- mViewFrameInfo.updateOldestInputEvent(10)
- mViewFrameInfo.updateNewestInputEvent(20)
+ mViewFrameInfo.setInputEvent(139)
mViewFrameInfo.flags = mViewFrameInfo.flags or FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED
mTimeStarted = SystemClock.uptimeNanos()
mViewFrameInfo.markDrawStart()
@@ -43,8 +43,6 @@
@Test
fun testPopulateFields() {
assertThat(mViewFrameInfo.drawStart).isGreaterThan(mTimeStarted)
- assertThat(mViewFrameInfo.oldestInputEventTime).isEqualTo(10)
- assertThat(mViewFrameInfo.newestInputEventTime).isEqualTo(20)
assertThat(mViewFrameInfo.flags).isEqualTo(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED)
}
@@ -53,8 +51,6 @@
mViewFrameInfo.reset()
// Ensure that the original object is reset correctly
assertThat(mViewFrameInfo.drawStart).isEqualTo(0)
- assertThat(mViewFrameInfo.oldestInputEventTime).isEqualTo(0)
- assertThat(mViewFrameInfo.newestInputEventTime).isEqualTo(0)
assertThat(mViewFrameInfo.flags).isEqualTo(0)
}
@@ -62,12 +58,13 @@
fun testUpdateFrameInfoFromViewFrameInfo() {
val frameInfo = FrameInfo()
// By default, all values should be zero
- // TODO(b/169866723): Use InputEventAssigner and assert INPUT_EVENT_ID
+ assertThat(frameInfo.frameInfo[FrameInfo.INPUT_EVENT_ID]).isEqualTo(INVALID_INPUT_EVENT_ID)
assertThat(frameInfo.frameInfo[FrameInfo.FLAGS]).isEqualTo(0)
assertThat(frameInfo.frameInfo[FrameInfo.DRAW_START]).isEqualTo(0)
// The values inside FrameInfo should match those from ViewFrameInfo after we update them
mViewFrameInfo.populateFrameInfo(frameInfo)
+ assertThat(frameInfo.frameInfo[FrameInfo.INPUT_EVENT_ID]).isEqualTo(139)
assertThat(frameInfo.frameInfo[FrameInfo.FLAGS]).isEqualTo(
FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED)
assertThat(frameInfo.frameInfo[FrameInfo.DRAW_START]).isGreaterThan(mTimeStarted)
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 5381009..96bbf82 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -23,7 +23,6 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
@@ -79,11 +78,15 @@
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
+import java.util.function.Supplier;
/**
* Test PackageWatchdog.
*/
public class PackageWatchdogTest {
+ private static final long RETRY_MAX_COUNT = 30;
+ private static final long RETRY_TIMEOUT_MILLIS = 500;
+
private static final String APP_A = "com.package.a";
private static final String APP_B = "com.package.b";
private static final String APP_C = "com.package.c";
@@ -109,6 +112,16 @@
private MockitoSession mSession;
private HashMap<String, String> mSystemSettingsMap;
+ private boolean retry(Supplier<Boolean> supplier) throws Exception {
+ for (int i = 0; i < RETRY_MAX_COUNT; ++i) {
+ if (supplier.get()) {
+ return true;
+ }
+ Thread.sleep(RETRY_TIMEOUT_MILLIS);
+ }
+ return false;
+ }
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -176,6 +189,10 @@
public void tearDown() throws Exception {
dropShellPermissions();
mSession.finishMocking();
+ // Clean up listeners since too many listeners will delay notifications significantly
+ for (PackageWatchdog watchdog : mAllocatedWatchdogs) {
+ watchdog.removePropertyChangedListener();
+ }
mAllocatedWatchdogs.clear();
}
@@ -1282,6 +1299,66 @@
assertTrue(readPkg.isEqualTo(expectedPkg));
}
+ /**
+ * Tests device config changes are propagated correctly.
+ */
+ @Test
+ public void testDeviceConfigChange_explicitHealthCheckEnabled() throws Exception {
+ TestController controller = new TestController();
+ PackageWatchdog watchdog = createWatchdog(controller, true /* withPackagesReady */);
+ assertThat(controller.mIsEnabled).isTrue();
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED,
+ Boolean.toString(false), /*makeDefault*/false);
+ retry(() -> !controller.mIsEnabled);
+ assertThat(controller.mIsEnabled).isFalse();
+ }
+
+ /**
+ * Tests device config changes are propagated correctly.
+ */
+ @Test
+ public void testDeviceConfigChange_triggerFailureCount() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
+ Integer.toString(777), false);
+ retry(() -> watchdog.getTriggerFailureCount() == 777);
+ assertThat(watchdog.getTriggerFailureCount()).isEqualTo(777);
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
+ Integer.toString(0), false);
+ retry(() -> watchdog.getTriggerFailureCount()
+ == PackageWatchdog.DEFAULT_TRIGGER_FAILURE_COUNT);
+ assertThat(watchdog.getTriggerFailureCount()).isEqualTo(
+ PackageWatchdog.DEFAULT_TRIGGER_FAILURE_COUNT);
+ }
+
+ /**
+ * Tests device config changes are propagated correctly.
+ */
+ @Test
+ public void testDeviceConfigChange_triggerFailureDurationMs() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_DURATION_MILLIS,
+ Integer.toString(888), false);
+ retry(() -> watchdog.getTriggerFailureDurationMs() == 888);
+ assertThat(watchdog.getTriggerFailureDurationMs()).isEqualTo(888);
+
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+ PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_DURATION_MILLIS,
+ Integer.toString(0), false);
+ retry(() -> watchdog.getTriggerFailureDurationMs()
+ == PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS);
+ assertThat(watchdog.getTriggerFailureDurationMs()).isEqualTo(
+ PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS);
+ }
+
private void adoptShellPermissions(String... permissions) {
InstrumentationRegistry
.getInstrumentation()
diff --git a/tests/net/common/java/android/net/CaptivePortalTest.java b/tests/net/common/java/android/net/CaptivePortalTest.java
index 7a60cc1..15d3398 100644
--- a/tests/net/common/java/android/net/CaptivePortalTest.java
+++ b/tests/net/common/java/android/net/CaptivePortalTest.java
@@ -24,8 +24,8 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import org.junit.Rule;
@@ -55,7 +55,7 @@
mCode = request;
}
- @Override
+ // This is only @Override on R-
public void logEvent(int eventId, String packageName) throws RemoteException {
mCode = eventId;
mPackageName = packageName;
@@ -98,12 +98,24 @@
assertEquals(result.mCode, CaptivePortal.APP_REQUEST_REEVALUATION_REQUIRED);
}
+ @IgnoreUpTo(Build.VERSION_CODES.R)
@Test
public void testLogEvent() {
+ /**
+ * From S testLogEvent is expected to do nothing but shouldn't crash (the API
+ * logEvent has been deprecated).
+ */
final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.logEvent(
- MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY,
+ 0,
TEST_PACKAGE_NAME));
- assertEquals(result.mCode, MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY);
+ }
+
+ @IgnoreAfter(Build.VERSION_CODES.R)
+ @Test
+ public void testLogEvent_UntilR() {
+ final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.logEvent(
+ 42, TEST_PACKAGE_NAME));
+ assertEquals(result.mCode, 42);
assertEquals(result.mPackageName, TEST_PACKAGE_NAME);
}
}
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
index c10c573..2a2dc56 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -16,6 +16,7 @@
package com.android.server.net.integrationtests
+import android.app.usage.NetworkStatsManager
import android.content.ComponentName
import android.content.Context
import android.content.Context.BIND_AUTO_CREATE
@@ -25,7 +26,6 @@
import android.net.ConnectivityManager
import android.net.IDnsResolver
import android.net.INetd
-import android.net.INetworkStatsService
import android.net.LinkProperties
import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
@@ -37,7 +37,6 @@
import android.net.metrics.IpConnectivityLog
import android.os.ConditionVariable
import android.os.IBinder
-import android.os.INetworkManagementService
import android.os.SystemConfigManager
import android.os.UserHandle
import android.testing.TestableContext
@@ -87,9 +86,7 @@
// lateinit used here for mocks as they need to be reinitialized between each test and the test
// should crash if they are used before being initialized.
@Mock
- private lateinit var netManager: INetworkManagementService
- @Mock
- private lateinit var statsService: INetworkStatsService
+ private lateinit var statsManager: NetworkStatsManager
@Mock
private lateinit var log: IpConnectivityLog
@Mock
@@ -172,12 +169,13 @@
service = TestConnectivityService(makeDependencies())
cm = ConnectivityManager(context, service)
context.addMockSystemService(Context.CONNECTIVITY_SERVICE, cm)
+ context.addMockSystemService(Context.NETWORK_STATS_SERVICE, statsManager)
service.systemReadyInternal()
}
private inner class TestConnectivityService(deps: Dependencies) : ConnectivityService(
- context, statsService, dnsResolver, log, netd, deps)
+ context, dnsResolver, log, netd, deps)
private fun makeDependencies(): ConnectivityService.Dependencies {
val deps = spy(ConnectivityService.Dependencies())
diff --git a/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt b/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt
index 9b0cfa9..c1315f6 100644
--- a/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt
+++ b/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt
@@ -21,7 +21,7 @@
import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER
import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE
import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY
-import android.net.util.MultinetworkPolicyTracker.ActiveDataSubscriptionIdChangedListener
+import android.net.util.MultinetworkPolicyTracker.ActiveDataSubscriptionIdListener
import android.provider.Settings
import android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI
import android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE
@@ -120,9 +120,9 @@
MULTIPATH_PREFERENCE_PERFORMANCE.toString())
val listenerCaptor = ArgumentCaptor.forClass(
- ActiveDataSubscriptionIdChangedListener::class.java)
+ ActiveDataSubscriptionIdListener::class.java)
verify(telephonyManager, times(1))
- .registerPhoneStateListener(any(), listenerCaptor.capture())
+ .registerTelephonyCallback(any(), listenerCaptor.capture())
val listener = listenerCaptor.value
listener.onActiveDataSubscriptionIdChanged(testSubId)
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index c6e2bc7..d725171 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -103,6 +103,7 @@
import static com.android.testutils.ConcurrentUtils.durationOf;
import static com.android.testutils.ExceptionUtils.ignoreExceptions;
import static com.android.testutils.HandlerUtils.waitForIdleSerialExecutor;
+import static com.android.testutils.MiscAsserts.assertContainsAll;
import static com.android.testutils.MiscAsserts.assertContainsExactly;
import static com.android.testutils.MiscAsserts.assertEmpty;
import static com.android.testutils.MiscAsserts.assertLength;
@@ -149,6 +150,7 @@
import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.usage.NetworkStatsManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentProvider;
@@ -180,7 +182,6 @@
import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
import android.net.INetworkPolicyListener;
-import android.net.INetworkStatsService;
import android.net.IOnSetOemNetworkPreferenceListener;
import android.net.IQosCallback;
import android.net.InetAddresses;
@@ -416,6 +417,8 @@
private QosCallbackMockHelper mQosCallbackMockHelper;
private QosCallbackTracker mQosCallbackTracker;
private VpnManagerService mVpnManagerService;
+ private TestNetworkCallback mDefaultNetworkCallback;
+ private TestNetworkCallback mSystemDefaultNetworkCallback;
// State variables required to emulate NetworkPolicyManagerService behaviour.
private int mUidRules = RULE_NONE;
@@ -423,7 +426,7 @@
@Mock DeviceIdleInternal mDeviceIdleInternal;
@Mock INetworkManagementService mNetworkManagementService;
- @Mock INetworkStatsService mStatsService;
+ @Mock NetworkStatsManager mStatsManager;
@Mock IBatteryStats mBatteryStatsService;
@Mock IDnsResolver mMockDnsResolver;
@Mock INetd mMockNetd;
@@ -539,6 +542,7 @@
if (Context.ETHERNET_SERVICE.equals(name)) return mEthernetManager;
if (Context.NETWORK_POLICY_SERVICE.equals(name)) return mNetworkPolicyManager;
if (Context.SYSTEM_CONFIG_SERVICE.equals(name)) return mSystemConfigManager;
+ if (Context.NETWORK_STATS_SERVICE.equals(name)) return mStatsManager;
return super.getSystemService(name);
}
@@ -1081,9 +1085,11 @@
}
}
- private Set<UidRange> uidRangesForUid(int uid) {
+ private Set<UidRange> uidRangesForUids(int... uids) {
final ArraySet<UidRange> ranges = new ArraySet<>();
- ranges.add(new UidRange(uid, uid));
+ for (final int uid : uids) {
+ ranges.add(new UidRange(uid, uid));
+ }
return ranges;
}
@@ -1213,13 +1219,13 @@
public void establishForMyUid(LinkProperties lp) throws Exception {
final int uid = Process.myUid();
- establish(lp, uid, uidRangesForUid(uid), true, true, false);
+ establish(lp, uid, uidRangesForUids(uid), true, true, false);
}
public void establishForMyUid(boolean validated, boolean hasInternet, boolean isStrictMode)
throws Exception {
final int uid = Process.myUid();
- establish(makeLinkProperties(), uid, uidRangesForUid(uid), validated, hasInternet,
+ establish(makeLinkProperties(), uid, uidRangesForUids(uid), validated, hasInternet,
isStrictMode);
}
@@ -1328,7 +1334,7 @@
}
- private void processBroadcastForVpn(Intent intent) {
+ private void processBroadcast(Intent intent) {
mServiceContext.sendBroadcast(intent);
HandlerUtils.waitForIdle(mVMSHandlerThread, TIMEOUT_MS);
waitForIdle();
@@ -1419,6 +1425,7 @@
private static final int VPN_UID = UserHandle.getUid(PRIMARY_USER, 10043);
private static final UserInfo PRIMARY_USER_INFO = new UserInfo(PRIMARY_USER, "",
UserInfo.FLAG_PRIMARY);
+ private static final UserHandle PRIMARY_USER_HANDLE = new UserHandle(PRIMARY_USER);
private static final int RESTRICTED_USER = 1;
private static final UserInfo RESTRICTED_USER_INFO = new UserInfo(RESTRICTED_USER, "",
@@ -1436,6 +1443,8 @@
MockitoAnnotations.initMocks(this);
when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO));
+ when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
+ Arrays.asList(PRIMARY_USER_HANDLE));
when(mUserManager.getUserInfo(PRIMARY_USER)).thenReturn(PRIMARY_USER_INFO);
// canHaveRestrictedProfile does not take a userId. It applies to the userId of the context
// it was started from, i.e., PRIMARY_USER.
@@ -1472,7 +1481,6 @@
mDeps = makeDependencies();
returnRealCallingUid();
mService = new ConnectivityService(mServiceContext,
- mStatsService,
mMockDnsResolver,
mock(IpConnectivityLog.class),
mMockNetd,
@@ -1556,6 +1564,7 @@
@After
public void tearDown() throws Exception {
+ unregisterDefaultNetworkCallbacks();
setAlwaysOnNetworks(false);
if (mCellNetworkAgent != null) {
mCellNetworkAgent.disconnect();
@@ -1661,6 +1670,7 @@
assertNull(mCm.getActiveNetworkForUid(Process.myUid()));
// Test getAllNetworks()
assertEmpty(mCm.getAllNetworks());
+ assertEmpty(mCm.getAllNetworkStateSnapshot());
}
/**
@@ -5487,18 +5497,19 @@
assertEquals(expectedSet, actualSet);
}
- private void expectForceUpdateIfaces(Network[] networks, String defaultIface,
+ private void expectNetworkStatus(Network[] networks, String defaultIface,
Integer vpnUid, String vpnIfname, String[] underlyingIfaces) throws Exception {
- ArgumentCaptor<Network[]> networksCaptor = ArgumentCaptor.forClass(Network[].class);
- ArgumentCaptor<UnderlyingNetworkInfo[]> vpnInfosCaptor = ArgumentCaptor.forClass(
- UnderlyingNetworkInfo[].class);
+ ArgumentCaptor<List<Network>> networksCaptor = ArgumentCaptor.forClass(List.class);
+ ArgumentCaptor<List<UnderlyingNetworkInfo>> vpnInfosCaptor =
+ ArgumentCaptor.forClass(List.class);
- verify(mStatsService, atLeastOnce()).forceUpdateIfaces(networksCaptor.capture(),
- any(NetworkStateSnapshot[].class), eq(defaultIface), vpnInfosCaptor.capture());
+ verify(mStatsManager, atLeastOnce()).notifyNetworkStatus(networksCaptor.capture(),
+ any(List.class), eq(defaultIface), vpnInfosCaptor.capture());
- assertSameElementsNoDuplicates(networksCaptor.getValue(), networks);
+ assertSameElementsNoDuplicates(networksCaptor.getValue().toArray(), networks);
- UnderlyingNetworkInfo[] infos = vpnInfosCaptor.getValue();
+ UnderlyingNetworkInfo[] infos =
+ vpnInfosCaptor.getValue().toArray(new UnderlyingNetworkInfo[0]);
if (vpnUid != null) {
assertEquals("Should have exactly one VPN:", 1, infos.length);
UnderlyingNetworkInfo info = infos[0];
@@ -5512,8 +5523,9 @@
}
}
- private void expectForceUpdateIfaces(Network[] networks, String defaultIface) throws Exception {
- expectForceUpdateIfaces(networks, defaultIface, null, null, new String[0]);
+ private void expectNetworkStatus(
+ Network[] networks, String defaultIface) throws Exception {
+ expectNetworkStatus(networks, defaultIface, null, null, new String[0]);
}
@Test
@@ -5533,46 +5545,46 @@
mCellNetworkAgent.connect(false);
mCellNetworkAgent.sendLinkProperties(cellLp);
waitForIdle();
- expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
- reset(mStatsService);
+ expectNetworkStatus(onlyCell, MOBILE_IFNAME);
+ reset(mStatsManager);
// Default network switch should update ifaces.
mWiFiNetworkAgent.connect(false);
mWiFiNetworkAgent.sendLinkProperties(wifiLp);
waitForIdle();
assertEquals(wifiLp, mService.getActiveLinkProperties());
- expectForceUpdateIfaces(onlyWifi, WIFI_IFNAME);
- reset(mStatsService);
+ expectNetworkStatus(onlyWifi, WIFI_IFNAME);
+ reset(mStatsManager);
// Disconnect should update ifaces.
mWiFiNetworkAgent.disconnect();
waitForIdle();
- expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
- reset(mStatsService);
+ expectNetworkStatus(onlyCell, MOBILE_IFNAME);
+ reset(mStatsManager);
// Metered change should update ifaces
mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
waitForIdle();
- expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
- reset(mStatsService);
+ expectNetworkStatus(onlyCell, MOBILE_IFNAME);
+ reset(mStatsManager);
mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
waitForIdle();
- expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
- reset(mStatsService);
+ expectNetworkStatus(onlyCell, MOBILE_IFNAME);
+ reset(mStatsManager);
// Temp metered change shouldn't update ifaces
mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED);
waitForIdle();
- verify(mStatsService, never()).forceUpdateIfaces(eq(onlyCell), any(
- NetworkStateSnapshot[].class), eq(MOBILE_IFNAME), eq(new UnderlyingNetworkInfo[0]));
- reset(mStatsService);
+ verify(mStatsManager, never()).notifyNetworkStatus(eq(Arrays.asList(onlyCell)),
+ any(List.class), eq(MOBILE_IFNAME), any(List.class));
+ reset(mStatsManager);
// Roaming change should update ifaces
mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
waitForIdle();
- expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
- reset(mStatsService);
+ expectNetworkStatus(onlyCell, MOBILE_IFNAME);
+ reset(mStatsManager);
// Test VPNs.
final LinkProperties lp = new LinkProperties();
@@ -5585,7 +5597,7 @@
mCellNetworkAgent.getNetwork(), mMockVpn.getNetwork()};
// A VPN with default (null) underlying networks sets the underlying network's interfaces...
- expectForceUpdateIfaces(cellAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+ expectNetworkStatus(cellAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
new String[]{MOBILE_IFNAME});
// ...and updates them as the default network switches.
@@ -5602,9 +5614,9 @@
waitForIdle();
assertEquals(wifiLp, mService.getActiveLinkProperties());
- expectForceUpdateIfaces(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
+ expectNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
new String[]{WIFI_IFNAME});
- reset(mStatsService);
+ reset(mStatsManager);
// A VPN that sets its underlying networks passes the underlying interfaces, and influences
// the default interface sent to NetworkStatsService by virtue of applying to the system
@@ -5614,22 +5626,22 @@
// applies to the system server UID should not have any bearing on network stats.
mMockVpn.setUnderlyingNetworks(onlyCell);
waitForIdle();
- expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+ expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
new String[]{MOBILE_IFNAME});
- reset(mStatsService);
+ reset(mStatsManager);
mMockVpn.setUnderlyingNetworks(cellAndWifi);
waitForIdle();
- expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+ expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
new String[]{MOBILE_IFNAME, WIFI_IFNAME});
- reset(mStatsService);
+ reset(mStatsManager);
// Null underlying networks are ignored.
mMockVpn.setUnderlyingNetworks(cellNullAndWifi);
waitForIdle();
- expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+ expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
new String[]{MOBILE_IFNAME, WIFI_IFNAME});
- reset(mStatsService);
+ reset(mStatsManager);
// If an underlying network disconnects, that interface should no longer be underlying.
// This doesn't actually work because disconnectAndDestroyNetwork only notifies
@@ -5641,17 +5653,17 @@
mCellNetworkAgent.disconnect();
waitForIdle();
assertNull(mService.getLinkProperties(mCellNetworkAgent.getNetwork()));
- expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+ expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
new String[]{MOBILE_IFNAME, WIFI_IFNAME});
// Confirm that we never tell NetworkStatsService that cell is no longer the underlying
// network for the VPN...
- verify(mStatsService, never()).forceUpdateIfaces(any(Network[].class),
- any(NetworkStateSnapshot[].class), any() /* anyString() doesn't match null */,
- argThat(infos -> infos[0].underlyingIfaces.size() == 1
- && WIFI_IFNAME.equals(infos[0].underlyingIfaces.get(0))));
- verifyNoMoreInteractions(mStatsService);
- reset(mStatsService);
+ verify(mStatsManager, never()).notifyNetworkStatus(any(List.class),
+ any(List.class), any() /* anyString() doesn't match null */,
+ argThat(infos -> infos.get(0).underlyingIfaces.size() == 1
+ && WIFI_IFNAME.equals(infos.get(0).underlyingIfaces.get(0))));
+ verifyNoMoreInteractions(mStatsManager);
+ reset(mStatsManager);
// ... but if something else happens that causes notifyIfacesChangedForNetworkStats to be
// called again, it does. For example, connect Ethernet, but with a low score, such that it
@@ -5660,13 +5672,13 @@
mEthernetNetworkAgent.adjustScore(-40);
mEthernetNetworkAgent.connect(false);
waitForIdle();
- verify(mStatsService).forceUpdateIfaces(any(Network[].class),
- any(NetworkStateSnapshot[].class), any() /* anyString() doesn't match null */,
- argThat(vpnInfos -> vpnInfos[0].underlyingIfaces.size() == 1
- && WIFI_IFNAME.equals(vpnInfos[0].underlyingIfaces.get(0))));
+ verify(mStatsManager).notifyNetworkStatus(any(List.class),
+ any(List.class), any() /* anyString() doesn't match null */,
+ argThat(vpnInfos -> vpnInfos.get(0).underlyingIfaces.size() == 1
+ && WIFI_IFNAME.equals(vpnInfos.get(0).underlyingIfaces.get(0))));
mEthernetNetworkAgent.disconnect();
waitForIdle();
- reset(mStatsService);
+ reset(mStatsManager);
// When a VPN declares no underlying networks (i.e., no connectivity), getAllVpnInfo
// does not return the VPN, so CS does not pass it to NetworkStatsService. This causes
@@ -5676,27 +5688,27 @@
// Also, for the same reason as above, the active interface passed in is null.
mMockVpn.setUnderlyingNetworks(new Network[0]);
waitForIdle();
- expectForceUpdateIfaces(wifiAndVpn, null);
- reset(mStatsService);
+ expectNetworkStatus(wifiAndVpn, null);
+ reset(mStatsManager);
// Specifying only a null underlying network is the same as no networks.
mMockVpn.setUnderlyingNetworks(onlyNull);
waitForIdle();
- expectForceUpdateIfaces(wifiAndVpn, null);
- reset(mStatsService);
+ expectNetworkStatus(wifiAndVpn, null);
+ reset(mStatsManager);
// Specifying networks that are all disconnected is the same as specifying no networks.
mMockVpn.setUnderlyingNetworks(onlyCell);
waitForIdle();
- expectForceUpdateIfaces(wifiAndVpn, null);
- reset(mStatsService);
+ expectNetworkStatus(wifiAndVpn, null);
+ reset(mStatsManager);
// Passing in null again means follow the default network again.
mMockVpn.setUnderlyingNetworks(null);
waitForIdle();
- expectForceUpdateIfaces(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
+ expectNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
new String[]{WIFI_IFNAME});
- reset(mStatsService);
+ reset(mStatsManager);
}
@Test
@@ -6383,7 +6395,7 @@
vpnNetworkCallback.assertNoCallback();
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- final Set<UidRange> ranges = uidRangesForUid(uid);
+ final Set<UidRange> ranges = uidRangesForUids(uid);
mMockVpn.registerAgent(ranges);
mMockVpn.setUnderlyingNetworks(new Network[0]);
@@ -6855,7 +6867,7 @@
final int uid = Process.myUid();
NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
assertNotNull("nc=" + nc, nc.getUids());
- assertEquals(nc.getUids(), uidRangesForUid(uid));
+ assertEquals(nc.getUids(), uidRangesForUids(uid));
assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
// Set an underlying network and expect to see the VPN transports change.
@@ -6876,7 +6888,7 @@
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
// Send a USER_ADDED broadcast for it.
- processBroadcastForVpn(addedIntent);
+ processBroadcast(addedIntent);
// Expect that the VPN UID ranges contain both |uid| and the UID range for the newly-added
// restricted user.
@@ -6901,7 +6913,7 @@
final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
removedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(RESTRICTED_USER));
removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
- processBroadcastForVpn(removedIntent);
+ processBroadcast(removedIntent);
// Expect that the VPN gains the UID range for the restricted user, and that the capability
// change made just before that (i.e., loss of TRANSPORT_WIFI) is preserved.
@@ -6959,7 +6971,7 @@
final Intent addedIntent = new Intent(ACTION_USER_ADDED);
addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(RESTRICTED_USER));
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
- processBroadcastForVpn(addedIntent);
+ processBroadcast(addedIntent);
assertNull(mCm.getActiveNetworkForUid(uid));
assertNull(mCm.getActiveNetworkForUid(restrictedUid));
@@ -6970,7 +6982,7 @@
final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
removedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(RESTRICTED_USER));
removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
- processBroadcastForVpn(removedIntent);
+ processBroadcast(removedIntent);
assertNull(mCm.getActiveNetworkForUid(uid));
assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
@@ -7125,7 +7137,7 @@
assertFalse(mCm.isActiveNetworkMetered());
// Connect VPN network.
- mMockVpn.registerAgent(true /* isAlwaysMetered */, uidRangesForUid(Process.myUid()),
+ mMockVpn.registerAgent(true /* isAlwaysMetered */, uidRangesForUids(Process.myUid()),
new LinkProperties());
mMockVpn.connect(true);
waitForIdle();
@@ -7564,7 +7576,7 @@
final Intent addedIntent = new Intent(ACTION_USER_UNLOCKED);
addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(userId));
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
- processBroadcastForVpn(addedIntent);
+ processBroadcast(addedIntent);
// Lockdown VPN disables teardown and enables lockdown.
assertFalse(mMockVpn.getEnableTeardown());
@@ -9283,7 +9295,7 @@
private void assertUidRangesUpdatedForMyUid(boolean add) throws Exception {
final int uid = Process.myUid();
- assertVpnUidRangesUpdated(add, uidRangesForUid(uid), uid);
+ assertVpnUidRangesUpdated(add, uidRangesForUids(uid), uid);
}
private void assertVpnUidRangesUpdated(boolean add, Set<UidRange> vpnRanges, int exemptUid)
@@ -9494,6 +9506,10 @@
fail("TOO_MANY_REQUESTS never thrown");
}
+ private UidRange createUidRange(int userId) {
+ return UidRange.createForUser(UserHandle.of(userId));
+ }
+
private void mockGetApplicationInfo(@NonNull final String packageName, @NonNull final int uid)
throws Exception {
final ApplicationInfo applicationInfo = new ApplicationInfo();
@@ -9668,7 +9684,7 @@
}
@Test
- public void testOemNetworkRequestFactoryCorrectlySetsUids()
+ public void testOemNetworkRequestFactoryMultiplePrefsCorrectlySetsUids()
throws Exception {
// Arrange PackageManager mocks
final String testPackageName2 = "com.google.apps.dialer";
@@ -9699,6 +9715,46 @@
}
@Test
+ public void testOemNetworkRequestFactoryMultipleUsersCorrectlySetsUids()
+ throws Exception {
+ // Arrange users
+ final int secondUser = 10;
+ final UserHandle secondUserHandle = new UserHandle(secondUser);
+ when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
+ Arrays.asList(PRIMARY_USER_HANDLE, secondUserHandle));
+
+ // Arrange PackageManager mocks
+ mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
+
+ // Build OemNetworkPreferences object
+ final int testOemPref = OEM_NETWORK_PREFERENCE_OEM_PAID;
+ final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
+ .addNetworkPreference(TEST_PACKAGE_NAME, testOemPref)
+ .build();
+
+ // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
+ final List<ConnectivityService.NetworkRequestInfo> nris =
+ new ArrayList<>(
+ mService.new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(
+ pref));
+
+ // UIDs for all users and all managed packages should be present.
+ // Two users each with two packages.
+ final int expectedUidSize = 2;
+ final List<UidRange> uids =
+ new ArrayList<>(nris.get(0).mRequests.get(0).networkCapabilities.getUids());
+ assertEquals(expectedUidSize, uids.size());
+
+ // Sort by uid to access nris by index
+ uids.sort(Comparator.comparingInt(uid -> uid.start));
+ final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
+ assertEquals(TEST_PACKAGE_UID, uids.get(0).start);
+ assertEquals(TEST_PACKAGE_UID, uids.get(0).stop);
+ assertEquals(secondUserTestPackageUid, uids.get(1).start);
+ assertEquals(secondUserTestPackageUid, uids.get(1).stop);
+ }
+
+ @Test
public void testOemNetworkRequestFactoryAddsPackagesToCorrectPreference()
throws Exception {
// Expectations
@@ -9828,6 +9884,54 @@
assertEquals(expectedPerAppNetwork, defaultNetwork);
assertEquals(expectedOemRequestsSize, defaultRequest.mRequests.size());
}
+ verifyMultipleDefaultCallbacks(expectedDefaultNetwork, expectedPerAppNetwork);
+ }
+
+ /**
+ * Verify default callbacks for 'available' fire as expected. This will only run if
+ * registerDefaultNetworkCallbacks() was executed prior and will only be different if the
+ * setOemNetworkPreference() per-app API was used for the current process.
+ * @param expectedSystemDefault the expected network for the system default.
+ * @param expectedPerAppDefault the expected network for the current process's default.
+ */
+ private void verifyMultipleDefaultCallbacks(
+ @NonNull final Network expectedSystemDefault,
+ @NonNull final Network expectedPerAppDefault) {
+ if (null != mSystemDefaultNetworkCallback && null != expectedSystemDefault
+ && mService.mNoServiceNetwork.network() != expectedSystemDefault) {
+ // getLastAvailableNetwork() is used as this method can be called successively with
+ // the same network to validate therefore expectAvailableThenValidatedCallbacks
+ // can't be used.
+ assertEquals(mSystemDefaultNetworkCallback.getLastAvailableNetwork(),
+ expectedSystemDefault);
+ }
+ if (null != mDefaultNetworkCallback && null != expectedPerAppDefault
+ && mService.mNoServiceNetwork.network() != expectedPerAppDefault) {
+ assertEquals(mDefaultNetworkCallback.getLastAvailableNetwork(),
+ expectedPerAppDefault);
+ }
+ }
+
+ private void registerDefaultNetworkCallbacks() {
+ // Using Manifest.permission.NETWORK_SETTINGS for registerSystemDefaultNetworkCallback()
+ mServiceContext.setPermission(
+ Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+ mSystemDefaultNetworkCallback = new TestNetworkCallback();
+ mDefaultNetworkCallback = new TestNetworkCallback();
+ mCm.registerSystemDefaultNetworkCallback(mSystemDefaultNetworkCallback,
+ new Handler(ConnectivityThread.getInstanceLooper()));
+ mCm.registerDefaultNetworkCallback(mDefaultNetworkCallback);
+ mServiceContext.setPermission(
+ Manifest.permission.NETWORK_SETTINGS, PERMISSION_DENIED);
+ }
+
+ private void unregisterDefaultNetworkCallbacks() {
+ if (null != mDefaultNetworkCallback) {
+ mCm.unregisterNetworkCallback(mDefaultNetworkCallback);
+ }
+ if (null != mSystemDefaultNetworkCallback) {
+ mCm.unregisterNetworkCallback(mSystemDefaultNetworkCallback);
+ }
}
private void setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(
@@ -9855,7 +9959,7 @@
assertEquals(1, mService.mDefaultNetworkRequests.size());
final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(uidRangesForUid(testPackageUid));
+ toUidRangeStableParcels(uidRangesForUids(testPackageUid));
setupSetOemNetworkPreferenceForPreferenceTest(
networkPrefToSetup, uidRanges, testPackageName);
}
@@ -9876,12 +9980,11 @@
.build();
// Act on ConnectivityService.setOemNetworkPreference()
- final TestOemListenerCallback mOnSetOemNetworkPreferenceTestListener =
- new TestOemListenerCallback();
- mService.setOemNetworkPreference(pref, mOnSetOemNetworkPreferenceTestListener);
+ final TestOemListenerCallback oemPrefListener = new TestOemListenerCallback();
+ mService.setOemNetworkPreference(pref, oemPrefListener);
// Verify call returned successfully
- mOnSetOemNetworkPreferenceTestListener.expectOnComplete();
+ oemPrefListener.expectOnComplete();
}
private static class TestOemListenerCallback implements IOnSetOemNetworkPreferenceListener {
@@ -9911,6 +10014,7 @@
@OemNetworkPreferences.OemNetworkPreference final int networkPref =
OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
final int expectedOemPrefRequestSize = 1;
+ registerDefaultNetworkCallbacks();
// Setup the test process to use networkPref for their default network.
setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
@@ -9925,6 +10029,7 @@
// Verify that the active network is correct
verifyActiveNetwork(TRANSPORT_ETHERNET);
+ // default NCs will be unregistered in tearDown
}
@Test
@@ -9932,6 +10037,7 @@
@OemNetworkPreferences.OemNetworkPreference final int networkPref =
OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
final int expectedOemPrefRequestSize = 1;
+ registerDefaultNetworkCallbacks();
// Setup the test process to use networkPref for their default network.
setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
@@ -9952,6 +10058,7 @@
mEthernetNetworkAgent.getNetwork());
assertFalse(mCm.isActiveNetworkMetered());
+ // default NCs will be unregistered in tearDown
}
@Test
@@ -10082,6 +10189,10 @@
mCm.unregisterNetworkCallback(defaultNetworkCallback);
}
+ /**
+ * This method assumes that the same uidRanges input will be used to verify that dependencies
+ * are called as expected.
+ */
private void verifySetOemNetworkPreferenceForPreference(
@NonNull final UidRangeParcel[] uidRanges,
final int addUidRangesNetId,
@@ -10089,16 +10200,30 @@
final int removeUidRangesNetId,
final int removeUidRangesTimes,
final boolean shouldDestroyNetwork) throws RemoteException {
+ verifySetOemNetworkPreferenceForPreference(uidRanges, uidRanges,
+ addUidRangesNetId, addUidRangesTimes, removeUidRangesNetId, removeUidRangesTimes,
+ shouldDestroyNetwork);
+ }
+
+ private void verifySetOemNetworkPreferenceForPreference(
+ @NonNull final UidRangeParcel[] addedUidRanges,
+ @NonNull final UidRangeParcel[] removedUidRanges,
+ final int addUidRangesNetId,
+ final int addUidRangesTimes,
+ final int removeUidRangesNetId,
+ final int removeUidRangesTimes,
+ final boolean shouldDestroyNetwork) throws RemoteException {
final boolean useAnyIdForAdd = OEM_PREF_ANY_NET_ID == addUidRangesNetId;
final boolean useAnyIdForRemove = OEM_PREF_ANY_NET_ID == removeUidRangesNetId;
// Validate netd.
verify(mMockNetd, times(addUidRangesTimes))
.networkAddUidRanges(
- (useAnyIdForAdd ? anyInt() : eq(addUidRangesNetId)), eq(uidRanges));
+ (useAnyIdForAdd ? anyInt() : eq(addUidRangesNetId)), eq(addedUidRanges));
verify(mMockNetd, times(removeUidRangesTimes))
.networkRemoveUidRanges(
- (useAnyIdForRemove ? anyInt() : eq(removeUidRangesNetId)), eq(uidRanges));
+ (useAnyIdForRemove ? anyInt() : eq(removeUidRangesNetId)),
+ eq(removedUidRanges));
if (shouldDestroyNetwork) {
verify(mMockNetd, times(1))
.networkDestroy((useAnyIdForRemove ? anyInt() : eq(removeUidRangesNetId)));
@@ -10108,7 +10233,6 @@
/**
* Test the tracked default requests clear previous OEM requests on setOemNetworkPreference().
- * @throws Exception
*/
@Test
public void testSetOemNetworkPreferenceClearPreviousOemValues() throws Exception {
@@ -10117,7 +10241,7 @@
final int testPackageUid = 123;
final String testPackageName = "com.google.apps.contacts";
final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(uidRangesForUid(testPackageUid));
+ toUidRangeStableParcels(uidRangesForUids(testPackageUid));
// Validate the starting requests only includes the fallback request.
assertEquals(1, mService.mDefaultNetworkRequests.size());
@@ -10136,9 +10260,8 @@
}
/**
- * Test network priority for preference OEM_NETWORK_PREFERENCE_OEM_PAID following in order:
+ * Test network priority for preference OEM_NETWORK_PREFERENCE_OEM_PAID in the following order:
* NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID -> fallback
- * @throws Exception
*/
@Test
public void testMultilayerForPreferenceOemPaidEvaluatesCorrectly()
@@ -10147,9 +10270,8 @@
OEM_NETWORK_PREFERENCE_OEM_PAID;
// Arrange PackageManager mocks
- final int testPackageNameUid = 123;
final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(uidRangesForUid(testPackageNameUid));
+ toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
// Verify the starting state. No networks should be connected.
@@ -10204,9 +10326,8 @@
}
/**
- * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK following in order:
+ * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK in the following order:
* NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID
- * @throws Exception
*/
@Test
public void testMultilayerForPreferenceOemPaidNoFallbackEvaluatesCorrectly()
@@ -10215,9 +10336,8 @@
OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
// Arrange PackageManager mocks
- final int testPackageNameUid = 123;
final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(uidRangesForUid(testPackageNameUid));
+ toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
// Verify the starting state. This preference doesn't support using the fallback network
@@ -10267,10 +10387,9 @@
}
/**
- * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY following in order:
+ * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY in the following order:
* NET_CAPABILITY_OEM_PAID
* This preference should only apply to OEM_PAID networks.
- * @throws Exception
*/
@Test
public void testMultilayerForPreferenceOemPaidOnlyEvaluatesCorrectly()
@@ -10279,9 +10398,8 @@
OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
// Arrange PackageManager mocks
- final int testPackageNameUid = 123;
final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(uidRangesForUid(testPackageNameUid));
+ toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
// Verify the starting state. This preference doesn't support using the fallback network
@@ -10321,10 +10439,9 @@
}
/**
- * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY following in order:
+ * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY in the following order:
* NET_CAPABILITY_OEM_PRIVATE
* This preference should only apply to OEM_PRIVATE networks.
- * @throws Exception
*/
@Test
public void testMultilayerForPreferenceOemPrivateOnlyEvaluatesCorrectly()
@@ -10333,9 +10450,8 @@
OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
// Arrange PackageManager mocks
- final int testPackageNameUid = 123;
final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(uidRangesForUid(testPackageNameUid));
+ toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
// Verify the starting state. This preference doesn't support using the fallback network
@@ -10374,7 +10490,417 @@
true /* shouldDestroyNetwork */);
}
- private UidRange createUidRange(int userId) {
- return UidRange.createForUser(UserHandle.of(userId));
+ @Test
+ public void testMultilayerForMultipleUsersEvaluatesCorrectly()
+ throws Exception {
+ @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+ OEM_NETWORK_PREFERENCE_OEM_PAID;
+
+ // Arrange users
+ final int secondUser = 10;
+ final UserHandle secondUserHandle = new UserHandle(secondUser);
+ when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
+ Arrays.asList(PRIMARY_USER_HANDLE, secondUserHandle));
+
+ // Arrange PackageManager mocks
+ final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
+ final UidRangeParcel[] uidRanges =
+ toUidRangeStableParcels(
+ uidRangesForUids(TEST_PACKAGE_UID, secondUserTestPackageUid));
+ setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
+
+ // Verify the starting state. No networks should be connected.
+ verifySetOemNetworkPreferenceForPreference(uidRanges,
+ OEM_PREF_ANY_NET_ID, 0 /* times */,
+ OEM_PREF_ANY_NET_ID, 0 /* times */,
+ false /* shouldDestroyNetwork */);
+
+ // Test that we correctly add the expected values for multiple users.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+ verifySetOemNetworkPreferenceForPreference(uidRanges,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ OEM_PREF_ANY_NET_ID, 0 /* times */,
+ false /* shouldDestroyNetwork */);
+
+ // Test that we correctly remove the expected values for multiple users.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
+ verifySetOemNetworkPreferenceForPreference(uidRanges,
+ OEM_PREF_ANY_NET_ID, 0 /* times */,
+ mCellNetworkAgent.getNetwork().netId, 0 /* times */,
+ true /* shouldDestroyNetwork */);
+ }
+
+ @Test
+ public void testMultilayerForBroadcastedUsersEvaluatesCorrectly()
+ throws Exception {
+ @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+ OEM_NETWORK_PREFERENCE_OEM_PAID;
+
+ // Arrange users
+ final int secondUser = 10;
+ final UserHandle secondUserHandle = new UserHandle(secondUser);
+ when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
+ Arrays.asList(PRIMARY_USER_HANDLE));
+
+ // Arrange PackageManager mocks
+ final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
+ final UidRangeParcel[] uidRangesSingleUser =
+ toUidRangeStableParcels(
+ uidRangesForUids(TEST_PACKAGE_UID));
+ final UidRangeParcel[] uidRangesBothUsers =
+ toUidRangeStableParcels(
+ uidRangesForUids(TEST_PACKAGE_UID, secondUserTestPackageUid));
+ setupSetOemNetworkPreferenceForPreferenceTest(
+ networkPref, uidRangesSingleUser, TEST_PACKAGE_NAME);
+
+ // Verify the starting state. No networks should be connected.
+ verifySetOemNetworkPreferenceForPreference(uidRangesSingleUser,
+ OEM_PREF_ANY_NET_ID, 0 /* times */,
+ OEM_PREF_ANY_NET_ID, 0 /* times */,
+ false /* shouldDestroyNetwork */);
+
+ // Test that we correctly add the expected values for multiple users.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+ verifySetOemNetworkPreferenceForPreference(uidRangesSingleUser,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ OEM_PREF_ANY_NET_ID, 0 /* times */,
+ false /* shouldDestroyNetwork */);
+
+ // Send a broadcast indicating a user was added.
+ when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
+ Arrays.asList(PRIMARY_USER_HANDLE, secondUserHandle));
+ final Intent addedIntent = new Intent(ACTION_USER_ADDED);
+ addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(secondUser));
+ processBroadcast(addedIntent);
+
+ // Test that we correctly add values for all users and remove for the single user.
+ verifySetOemNetworkPreferenceForPreference(uidRangesBothUsers, uidRangesSingleUser,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ false /* shouldDestroyNetwork */);
+
+ // Send a broadcast indicating a user was removed.
+ when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
+ Arrays.asList(PRIMARY_USER_HANDLE));
+ final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
+ removedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(secondUser));
+ processBroadcast(removedIntent);
+
+ // Test that we correctly add values for the single user and remove for the all users.
+ verifySetOemNetworkPreferenceForPreference(uidRangesSingleUser, uidRangesBothUsers,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ false /* shouldDestroyNetwork */);
+ }
+
+ /**
+ * Test network priority for preference OEM_NETWORK_PREFERENCE_OEM_PAID in the following order:
+ * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID -> fallback
+ */
+ @Test
+ public void testMultipleDefaultNetworksTracksOemNetworkPreferenceOemPaidCorrectly()
+ throws Exception {
+ @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+ OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
+ setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
+ final int expectedDefaultRequestSize = 2;
+ final int expectedOemPrefRequestSize = 3;
+ registerDefaultNetworkCallbacks();
+
+ // The fallback as well as the OEM preference should now be tracked.
+ assertEquals(expectedDefaultRequestSize, mService.mDefaultNetworkRequests.size());
+
+ // Test lowest to highest priority requests.
+ // Bring up metered cellular. This will satisfy the fallback network.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ mCellNetworkAgent.getNetwork(),
+ mCellNetworkAgent.getNetwork());
+
+ // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ mCellNetworkAgent.getNetwork(),
+ mEthernetNetworkAgent.getNetwork());
+
+ // Bring up unmetered Wi-Fi. This will satisfy NET_CAPABILITY_NOT_METERED.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ mWiFiNetworkAgent.getNetwork(),
+ mWiFiNetworkAgent.getNetwork());
+
+ // Disconnecting unmetered Wi-Fi will put the pref on OEM_PAID and fallback on cellular.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ mCellNetworkAgent.getNetwork(),
+ mEthernetNetworkAgent.getNetwork());
+
+ // Disconnecting cellular should keep OEM network on OEM_PAID and fallback will be null.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ null,
+ mEthernetNetworkAgent.getNetwork());
+
+ // Disconnecting OEM_PAID will put both on null as it is the last network.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ null,
+ null);
+
+ // default NCs will be unregistered in tearDown
+ }
+
+ /**
+ * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK in the following order:
+ * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID
+ */
+ @Test
+ public void testMultipleDefaultNetworksTracksOemNetworkPreferenceOemPaidNoFallbackCorrectly()
+ throws Exception {
+ @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+ OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
+ setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
+ final int expectedDefaultRequestSize = 2;
+ final int expectedOemPrefRequestSize = 2;
+ registerDefaultNetworkCallbacks();
+
+ // The fallback as well as the OEM preference should now be tracked.
+ assertEquals(expectedDefaultRequestSize, mService.mDefaultNetworkRequests.size());
+
+ // Test lowest to highest priority requests.
+ // Bring up metered cellular. This will satisfy the fallback network but not the pref.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ mCellNetworkAgent.getNetwork(),
+ mService.mNoServiceNetwork.network());
+
+ // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ mCellNetworkAgent.getNetwork(),
+ mEthernetNetworkAgent.getNetwork());
+
+ // Bring up unmetered Wi-Fi. This will satisfy NET_CAPABILITY_NOT_METERED.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ mWiFiNetworkAgent.getNetwork(),
+ mWiFiNetworkAgent.getNetwork());
+
+ // Disconnecting unmetered Wi-Fi will put the OEM pref on OEM_PAID and fallback on cellular.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ mCellNetworkAgent.getNetwork(),
+ mEthernetNetworkAgent.getNetwork());
+
+ // Disconnecting cellular should keep OEM network on OEM_PAID and fallback will be null.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ null,
+ mEthernetNetworkAgent.getNetwork());
+
+ // Disconnecting OEM_PAID puts the fallback on null and the pref on the disconnected net.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ null,
+ mService.mNoServiceNetwork.network());
+
+ // default NCs will be unregistered in tearDown
+ }
+
+ /**
+ * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY in the following order:
+ * NET_CAPABILITY_OEM_PAID
+ * This preference should only apply to OEM_PAID networks.
+ */
+ @Test
+ public void testMultipleDefaultNetworksTracksOemNetworkPreferenceOemPaidOnlyCorrectly()
+ throws Exception {
+ @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+ OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
+ setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
+ final int expectedDefaultRequestSize = 2;
+ final int expectedOemPrefRequestSize = 1;
+ registerDefaultNetworkCallbacks();
+
+ // The fallback as well as the OEM preference should now be tracked.
+ assertEquals(expectedDefaultRequestSize, mService.mDefaultNetworkRequests.size());
+
+ // Test lowest to highest priority requests.
+ // Bring up metered cellular. This will satisfy the fallback network.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ mCellNetworkAgent.getNetwork(),
+ mService.mNoServiceNetwork.network());
+
+ // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ mCellNetworkAgent.getNetwork(),
+ mEthernetNetworkAgent.getNetwork());
+
+ // Bring up unmetered Wi-Fi. The OEM network shouldn't change, the fallback will take Wi-Fi.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ mWiFiNetworkAgent.getNetwork(),
+ mEthernetNetworkAgent.getNetwork());
+
+ // Disconnecting unmetered Wi-Fi shouldn't change the OEM network with fallback on cellular.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ mCellNetworkAgent.getNetwork(),
+ mEthernetNetworkAgent.getNetwork());
+
+ // Disconnecting OEM_PAID will keep the fallback on cellular and nothing for OEM_PAID.
+ // OEM_PAID_ONLY not supporting a fallback now uses the disconnected network.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ mCellNetworkAgent.getNetwork(),
+ mService.mNoServiceNetwork.network());
+
+ // Disconnecting cellular will put the fallback on null and the pref on disconnected.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ null,
+ mService.mNoServiceNetwork.network());
+
+ // default NCs will be unregistered in tearDown
+ }
+
+ /**
+ * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY in the following order:
+ * NET_CAPABILITY_OEM_PRIVATE
+ * This preference should only apply to OEM_PRIVATE networks.
+ */
+ @Test
+ public void testMultipleDefaultNetworksTracksOemNetworkPreferenceOemPrivateOnlyCorrectly()
+ throws Exception {
+ @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+ OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
+ setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
+ final int expectedDefaultRequestSize = 2;
+ final int expectedOemPrefRequestSize = 1;
+ registerDefaultNetworkCallbacks();
+
+ // The fallback as well as the OEM preference should now be tracked.
+ assertEquals(expectedDefaultRequestSize, mService.mDefaultNetworkRequests.size());
+
+ // Test lowest to highest priority requests.
+ // Bring up metered cellular. This will satisfy the fallback network.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ mCellNetworkAgent.getNetwork(),
+ mService.mNoServiceNetwork.network());
+
+ // Bring up ethernet with OEM_PRIVATE. This will satisfy NET_CAPABILITY_OEM_PRIVATE.
+ startOemManagedNetwork(false);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ mCellNetworkAgent.getNetwork(),
+ mEthernetNetworkAgent.getNetwork());
+
+ // Bring up unmetered Wi-Fi. The OEM network shouldn't change, the fallback will take Wi-Fi.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ mWiFiNetworkAgent.getNetwork(),
+ mEthernetNetworkAgent.getNetwork());
+
+ // Disconnecting unmetered Wi-Fi shouldn't change the OEM network with fallback on cellular.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ mCellNetworkAgent.getNetwork(),
+ mEthernetNetworkAgent.getNetwork());
+
+ // Disconnecting OEM_PRIVATE will keep the fallback on cellular.
+ // OEM_PRIVATE_ONLY not supporting a fallback now uses to the disconnected network.
+ stopOemManagedNetwork();
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ mCellNetworkAgent.getNetwork(),
+ mService.mNoServiceNetwork.network());
+
+ // Disconnecting cellular will put the fallback on null and pref on disconnected.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
+ verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
+ null,
+ mService.mNoServiceNetwork.network());
+
+ // default NCs will be unregistered in tearDown
+ }
+
+ @Test
+ public void testGetAllNetworkStateSnapshot() throws Exception {
+ verifyNoNetwork();
+
+ // Setup test cellular network with specified LinkProperties and NetworkCapabilities,
+ // verify the content of the snapshot matches.
+ final LinkProperties cellLp = new LinkProperties();
+ final LinkAddress myIpv4Addr = new LinkAddress(InetAddress.getByName("192.0.2.129"), 25);
+ final LinkAddress myIpv6Addr = new LinkAddress(InetAddress.getByName("2001:db8::1"), 64);
+ cellLp.setInterfaceName("test01");
+ cellLp.addLinkAddress(myIpv4Addr);
+ cellLp.addLinkAddress(myIpv6Addr);
+ cellLp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234")));
+ cellLp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
+ cellLp.addRoute(new RouteInfo(myIpv4Addr, null));
+ cellLp.addRoute(new RouteInfo(myIpv6Addr, null));
+ final NetworkCapabilities cellNcTemplate = new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_CELLULAR).addCapability(NET_CAPABILITY_MMS).build();
+
+ final TestNetworkCallback cellCb = new TestNetworkCallback();
+ mCm.requestNetwork(new NetworkRequest.Builder().addCapability(NET_CAPABILITY_MMS).build(),
+ cellCb);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp, cellNcTemplate);
+ mCellNetworkAgent.connect(true);
+ cellCb.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
+ List<NetworkStateSnapshot> snapshots = mCm.getAllNetworkStateSnapshot();
+ assertLength(1, snapshots);
+
+ // Compose the expected cellular snapshot for verification.
+ final NetworkCapabilities cellNc =
+ mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork());
+ final NetworkStateSnapshot cellSnapshot = new NetworkStateSnapshot(
+ mCellNetworkAgent.getNetwork(), cellNc, cellLp,
+ null, ConnectivityManager.TYPE_MOBILE);
+ assertEquals(cellSnapshot, snapshots.get(0));
+
+ // Connect wifi and verify the snapshots.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
+ waitForIdle();
+ // Compose the expected wifi snapshot for verification.
+ final NetworkCapabilities wifiNc =
+ mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork());
+ final NetworkStateSnapshot wifiSnapshot = new NetworkStateSnapshot(
+ mWiFiNetworkAgent.getNetwork(), wifiNc, new LinkProperties(), null,
+ ConnectivityManager.TYPE_WIFI);
+
+ snapshots = mCm.getAllNetworkStateSnapshot();
+ assertLength(2, snapshots);
+ assertContainsAll(snapshots, cellSnapshot, wifiSnapshot);
+
+ // Set cellular as suspended, verify the snapshots will not contain suspended networks.
+ // TODO: Consider include SUSPENDED networks, which should be considered as
+ // temporary shortage of connectivity of a connected network.
+ mCellNetworkAgent.suspend();
+ waitForIdle();
+ snapshots = mCm.getAllNetworkStateSnapshot();
+ assertLength(1, snapshots);
+ assertEquals(wifiSnapshot, snapshots.get(0));
+
+ // Disconnect wifi, verify the snapshots contain nothing.
+ mWiFiNetworkAgent.disconnect();
+ waitForIdle();
+ snapshots = mCm.getAllNetworkStateSnapshot();
+ assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertLength(0, snapshots);
+
+ mCellNetworkAgent.resume();
+ waitForIdle();
+ snapshots = mCm.getAllNetworkStateSnapshot();
+ assertLength(1, snapshots);
+ assertEquals(cellSnapshot, snapshots.get(0));
+
+ mCellNetworkAgent.disconnect();
+ waitForIdle();
+ verifyNoNetwork();
+ mCm.unregisterNetworkCallback(cellCb);
}
}
diff --git a/tests/vcn/assets/self-signed-ca.pem b/tests/vcn/assets/self-signed-ca.pem
new file mode 100644
index 0000000..5135ea7
--- /dev/null
+++ b/tests/vcn/assets/self-signed-ca.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDPjCCAiagAwIBAgIICrKLpR7LxlowDQYJKoZIhvcNAQELBQAwPTELMAkGA1UE
+BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxHDAaBgNVBAMTE2NhLnRlc3QuYW5kcm9p
+ZC5uZXQwHhcNMTkwNzE2MTcxNTUyWhcNMjkwNzEzMTcxNTUyWjA9MQswCQYDVQQG
+EwJVUzEQMA4GA1UEChMHQW5kcm9pZDEcMBoGA1UEAxMTY2EudGVzdC5hbmRyb2lk
+Lm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANsvTwad2Nie0VOy
+Xb1VtHL0R760Jm4vr14JWMcX4oiE6jUdTNdXQ0CGb65wvulP2aEeukFH0D/cvBMR
+Bv9+haEwo9/grIXg9ALNKp+GfuZYw/dfnUMHFn3g2+SUgP6BoMZc4lkHktjkDKxp
+99Q6h4NP/ip1labkhBeB9+Z6l78LTixKRKspNITWASJed9bjzshYxKHi6dJy3maQ
+1LwYKmK7PEGRpoDoT8yZhFbxsVDUojGnJKH1RLXVOn/psG6dI/+IsbTipAttj5zc
+g2VAD56PZG2Jd+vsup+g4Dy72hyy242x5c/H2LKZn4X0B0B+IXyii/ZVc+DJldQ5
+JqplOL8CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
+HQYDVR0OBBYEFGYUzuvZUaVJl8mcxejuFiUNGcTfMA0GCSqGSIb3DQEBCwUAA4IB
+AQDQYeqjvHsK2ZqSqxakDp0nu36Plbj48Wvx1ru7GW2faz7i0w/Zkxh06zniILCb
+QJRjDebSTHc5SSbCFrRTvqagaLDhbH42/hQncWqIoJqW+pmznJET4JiBO0sqzm05
+yQWsLI/h9Ir28Y2g5N+XPBU0VVVejQqH4iI0iwQx7y7ABssQ0Xa/K73VPbeGaKd6
+Prt4wjJvTlIL2yE2+0MggJ3F2rNptL5SDpg3g+4/YQ6wVRBFil95kUqplEsCtU4P
+t+8RghiEmsRx/8CywKfZ5Hex87ODhsSDmDApcefbd5gxoWVkqxZUkPcKwYv1ucm8
+u4r44fj4/9W0Zeooav5Yoh1q
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
index 66590c9..7515971 100644
--- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
@@ -203,9 +203,6 @@
IVcnStatusCallback cbBinder =
new VcnStatusCallbackBinder(INLINE_EXECUTOR, mMockStatusCallback);
- cbBinder.onEnteredSafeMode();
- verify(mMockStatusCallback).onEnteredSafeMode();
-
cbBinder.onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE);
verify(mMockStatusCallback).onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE);
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java
new file mode 100644
index 0000000..bc8e9d3
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2021 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 android.net.vcn.persistablebundleutils;
+
+import static android.telephony.TelephonyManager.APPTYPE_USIM;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.eap.EapSessionConfig;
+import android.os.PersistableBundle;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class EapSessionConfigUtilsTest {
+ private static final byte[] EAP_ID = "test@android.net".getBytes(StandardCharsets.US_ASCII);
+ private static final String USERNAME = "username";
+ private static final String PASSWORD = "password";
+ private static final int SUB_ID = 1;
+ private static final String NETWORK_NAME = "android.net";
+ private static final boolean ALLOW_MISMATCHED_NETWORK_NAMES = true;
+
+ private EapSessionConfig.Builder createBuilderWithId() {
+ return new EapSessionConfig.Builder().setEapIdentity(EAP_ID);
+ }
+
+ private static void verifyPersistableBundleEncodeDecodeIsLossless(EapSessionConfig config) {
+ final PersistableBundle bundle = EapSessionConfigUtils.toPersistableBundle(config);
+ final EapSessionConfig resultConfig = EapSessionConfigUtils.fromPersistableBundle(bundle);
+
+ assertEquals(config, resultConfig);
+ }
+
+ @Test
+ public void testSetEapMsChapV2EncodeDecodeIsLossless() throws Exception {
+ final EapSessionConfig config =
+ createBuilderWithId().setEapMsChapV2Config(USERNAME, PASSWORD).build();
+
+ verifyPersistableBundleEncodeDecodeIsLossless(config);
+ }
+
+ @Test
+ public void testSetEapSimEncodeDecodeIsLossless() throws Exception {
+ final EapSessionConfig config =
+ createBuilderWithId().setEapSimConfig(SUB_ID, APPTYPE_USIM).build();
+
+ verifyPersistableBundleEncodeDecodeIsLossless(config);
+ }
+
+ @Test
+ public void testSetEapAkaEncodeDecodeIsLossless() throws Exception {
+ final EapSessionConfig config =
+ createBuilderWithId().setEapAkaConfig(SUB_ID, APPTYPE_USIM).build();
+
+ verifyPersistableBundleEncodeDecodeIsLossless(config);
+ }
+
+ @Test
+ public void testSetEapAkaPrimeEncodeDecodeIsLossless() throws Exception {
+ final EapSessionConfig config =
+ createBuilderWithId()
+ .setEapAkaPrimeConfig(
+ SUB_ID, APPTYPE_USIM, NETWORK_NAME, ALLOW_MISMATCHED_NETWORK_NAMES)
+ .build();
+
+ verifyPersistableBundleEncodeDecodeIsLossless(config);
+ }
+
+ @Test
+ public void testSetEapTtlsEncodeDecodeIsLossless() throws Exception {
+ final InputStream inputStream =
+ InstrumentationRegistry.getContext()
+ .getResources()
+ .getAssets()
+ .open("self-signed-ca.pem");
+ final CertificateFactory factory = CertificateFactory.getInstance("X.509");
+ final X509Certificate trustedCa =
+ (X509Certificate) factory.generateCertificate(inputStream);
+
+ final EapSessionConfig innerConfig =
+ new EapSessionConfig.Builder().setEapMsChapV2Config(USERNAME, PASSWORD).build();
+
+ final EapSessionConfig config =
+ new EapSessionConfig.Builder().setEapTtlsConfig(trustedCa, innerConfig).build();
+
+ verifyPersistableBundleEncodeDecodeIsLossless(config);
+ }
+}
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java
new file mode 100644
index 0000000..4f3930f
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2021 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 android.net.vcn.persistablebundleutils;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.ipsec.ike.IkeDerAsn1DnIdentification;
+import android.net.ipsec.ike.IkeFqdnIdentification;
+import android.net.ipsec.ike.IkeIdentification;
+import android.net.ipsec.ike.IkeIpv4AddrIdentification;
+import android.net.ipsec.ike.IkeIpv6AddrIdentification;
+import android.net.ipsec.ike.IkeKeyIdIdentification;
+import android.net.ipsec.ike.IkeRfc822AddrIdentification;
+import android.os.PersistableBundle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+
+import javax.security.auth.x500.X500Principal;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IkeIdentificationUtilsTest {
+ private static void verifyPersistableBundleEncodeDecodeIsLossless(IkeIdentification id) {
+ final PersistableBundle bundle = IkeIdentificationUtils.toPersistableBundle(id);
+ final IkeIdentification result = IkeIdentificationUtils.fromPersistableBundle(bundle);
+
+ assertEquals(result, id);
+ }
+
+ @Test
+ public void testPersistableBundleEncodeDecodeIpv4AddressId() throws Exception {
+ final Inet4Address ipv4Address = (Inet4Address) InetAddress.getByName("192.0.2.100");
+ verifyPersistableBundleEncodeDecodeIsLossless(new IkeIpv4AddrIdentification(ipv4Address));
+ }
+
+ @Test
+ public void testPersistableBundleEncodeDecodeIpv6AddressId() throws Exception {
+ final Inet6Address ipv6Address = (Inet6Address) InetAddress.getByName("2001:db8:2::100");
+ verifyPersistableBundleEncodeDecodeIsLossless(new IkeIpv6AddrIdentification(ipv6Address));
+ }
+
+ @Test
+ public void testPersistableBundleEncodeDecodeRfc822AddrId() throws Exception {
+ verifyPersistableBundleEncodeDecodeIsLossless(new IkeFqdnIdentification("ike.android.net"));
+ }
+
+ @Test
+ public void testPersistableBundleEncodeDecodeFqdnId() throws Exception {
+ verifyPersistableBundleEncodeDecodeIsLossless(
+ new IkeRfc822AddrIdentification("androidike@example.com"));
+ }
+
+ @Test
+ public void testPersistableBundleEncodeDecodeKeyId() throws Exception {
+ verifyPersistableBundleEncodeDecodeIsLossless(
+ new IkeKeyIdIdentification("androidIkeKeyId".getBytes()));
+ }
+
+ @Test
+ public void testPersistableBundleEncodeDecodeDerAsn1DnId() throws Exception {
+ verifyPersistableBundleEncodeDecodeIsLossless(
+ new IkeDerAsn1DnIdentification(
+ new X500Principal("CN=small.server.test.android.net, O=Android, C=US")));
+ }
+}
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java
new file mode 100644
index 0000000..8ae8692
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2021 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 android.net.vcn.persistablebundleutils;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.ipsec.ike.ChildSaProposal;
+import android.net.ipsec.ike.IkeSaProposal;
+import android.net.ipsec.ike.SaProposal;
+import android.os.PersistableBundle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SaProposalUtilsTest {
+ @Test
+ public void testPersistableBundleEncodeDecodeIsLosslessIkeProposal() throws Exception {
+ final IkeSaProposal proposal =
+ new IkeSaProposal.Builder()
+ .addEncryptionAlgorithm(
+ SaProposal.ENCRYPTION_ALGORITHM_3DES, SaProposal.KEY_LEN_UNUSED)
+ .addEncryptionAlgorithm(
+ SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128)
+ .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96)
+ .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128)
+ .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC)
+ .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256)
+ .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP)
+ .addDhGroup(SaProposal.DH_GROUP_3072_BIT_MODP)
+ .build();
+
+ final PersistableBundle bundle = IkeSaProposalUtils.toPersistableBundle(proposal);
+ final SaProposal resultProposal = IkeSaProposalUtils.fromPersistableBundle(bundle);
+
+ assertEquals(proposal, resultProposal);
+ }
+
+ /** Package private so that TunnelModeChildSessionParamsUtilsTest can use it */
+ static ChildSaProposal buildTestChildSaProposal() {
+ return new ChildSaProposal.Builder()
+ .addEncryptionAlgorithm(
+ SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128)
+ .addEncryptionAlgorithm(
+ SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_192)
+ .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP)
+ .addDhGroup(SaProposal.DH_GROUP_4096_BIT_MODP)
+ .build();
+ }
+
+ @Test
+ public void testPersistableBundleEncodeDecodeIsLosslessChildProposal() throws Exception {
+ final ChildSaProposal proposal = buildTestChildSaProposal();
+
+ final PersistableBundle bundle = ChildSaProposalUtils.toPersistableBundle(proposal);
+ final SaProposal resultProposal = ChildSaProposalUtils.fromPersistableBundle(bundle);
+
+ assertEquals(proposal, resultProposal);
+ }
+}
diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java
new file mode 100644
index 0000000..b3cd0ab
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2021 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 android.net.vcn.persistablebundleutils;
+
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.InetAddresses;
+import android.net.ipsec.ike.ChildSaProposal;
+import android.net.ipsec.ike.IkeTrafficSelector;
+import android.net.ipsec.ike.TunnelModeChildSessionParams;
+import android.os.PersistableBundle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TunnelModeChildSessionParamsUtilsTest {
+ private TunnelModeChildSessionParams.Builder createBuilderMinimum() {
+ final ChildSaProposal saProposal = SaProposalUtilsTest.buildTestChildSaProposal();
+ return new TunnelModeChildSessionParams.Builder().addSaProposal(saProposal);
+ }
+
+ private static void verifyPersistableBundleEncodeDecodeIsLossless(
+ TunnelModeChildSessionParams params) {
+ final PersistableBundle bundle =
+ TunnelModeChildSessionParamsUtils.toPersistableBundle(params);
+ final TunnelModeChildSessionParams result =
+ TunnelModeChildSessionParamsUtils.fromPersistableBundle(bundle);
+
+ assertEquals(params, result);
+ }
+
+ @Test
+ public void testMinimumParamsEncodeDecodeIsLossless() throws Exception {
+ final TunnelModeChildSessionParams sessionParams = createBuilderMinimum().build();
+ verifyPersistableBundleEncodeDecodeIsLossless(sessionParams);
+ }
+
+ @Test
+ public void testSetTsEncodeDecodeIsLossless() throws Exception {
+ final IkeTrafficSelector tsInbound =
+ new IkeTrafficSelector(
+ 16,
+ 65520,
+ InetAddresses.parseNumericAddress("192.0.2.100"),
+ InetAddresses.parseNumericAddress("192.0.2.101"));
+ final IkeTrafficSelector tsOutbound =
+ new IkeTrafficSelector(
+ 32,
+ 256,
+ InetAddresses.parseNumericAddress("192.0.2.200"),
+ InetAddresses.parseNumericAddress("192.0.2.255"));
+
+ final TunnelModeChildSessionParams sessionParams =
+ createBuilderMinimum()
+ .addInboundTrafficSelectors(tsInbound)
+ .addOutboundTrafficSelectors(tsOutbound)
+ .build();
+ verifyPersistableBundleEncodeDecodeIsLossless(sessionParams);
+ }
+
+ @Test
+ public void testSetLifetimesEncodeDecodeIsLossless() throws Exception {
+ final int hardLifetime = (int) TimeUnit.HOURS.toSeconds(3L);
+ final int softLifetime = (int) TimeUnit.HOURS.toSeconds(1L);
+
+ final TunnelModeChildSessionParams sessionParams =
+ createBuilderMinimum().setLifetimeSeconds(hardLifetime, softLifetime).build();
+ verifyPersistableBundleEncodeDecodeIsLossless(sessionParams);
+ }
+
+ @Test
+ public void testSetConfigRequestsEncodeDecodeIsLossless() throws Exception {
+ final int ipv6PrefixLen = 64;
+ final Inet4Address ipv4Address =
+ (Inet4Address) InetAddresses.parseNumericAddress("192.0.2.100");
+ final Inet6Address ipv6Address =
+ (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::1");
+
+ final TunnelModeChildSessionParams sessionParams =
+ createBuilderMinimum()
+ .addInternalAddressRequest(AF_INET)
+ .addInternalAddressRequest(AF_INET6)
+ .addInternalAddressRequest(ipv4Address)
+ .addInternalAddressRequest(ipv6Address, ipv6PrefixLen)
+ .addInternalDnsServerRequest(AF_INET)
+ .addInternalDnsServerRequest(AF_INET6)
+ .addInternalDhcpServerRequest(AF_INET)
+ .build();
+ verifyPersistableBundleEncodeDecodeIsLossless(sessionParams);
+ }
+}
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 9b500a7..73a6b88 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -100,6 +100,8 @@
public class VcnManagementServiceTest {
private static final String TEST_PACKAGE_NAME =
VcnManagementServiceTest.class.getPackage().getName();
+ private static final String TEST_CB_PACKAGE_NAME =
+ VcnManagementServiceTest.class.getPackage().getName() + ".callback";
private static final ParcelUuid TEST_UUID_1 = new ParcelUuid(new UUID(0, 0));
private static final ParcelUuid TEST_UUID_2 = new ParcelUuid(new UUID(1, 1));
private static final VcnConfig TEST_VCN_CONFIG;
@@ -288,6 +290,14 @@
private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
Set<ParcelUuid> activeSubscriptionGroups, Map<Integer, ParcelUuid> subIdToGroupMap) {
+ return triggerSubscriptionTrackerCbAndGetSnapshot(
+ activeSubscriptionGroups, subIdToGroupMap, true /* hasCarrierPrivileges */);
+ }
+
+ private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot(
+ Set<ParcelUuid> activeSubscriptionGroups,
+ Map<Integer, ParcelUuid> subIdToGroupMap,
+ boolean hasCarrierPrivileges) {
final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class);
doReturn(activeSubscriptionGroups).when(snapshot).getActiveSubscriptionGroups();
@@ -295,7 +305,7 @@
(activeSubscriptionGroups == null || activeSubscriptionGroups.isEmpty())
? Collections.emptySet()
: Collections.singleton(TEST_PACKAGE_NAME);
- doReturn(true)
+ doReturn(hasCarrierPrivileges)
.when(snapshot)
.packageHasPermissionsForSubscriptionGroup(
argThat(val -> activeSubscriptionGroups.contains(val)),
@@ -549,13 +559,6 @@
mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
}
- private void setUpVcnSubscription(int subId, ParcelUuid subGroup) {
- mVcnMgmtSvc.setVcnConfig(subGroup, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
-
- triggerSubscriptionTrackerCbAndGetSnapshot(
- Collections.singleton(subGroup), Collections.singletonMap(subId, subGroup));
- }
-
private void verifyMergedNetworkCapabilities(
NetworkCapabilities mergedCapabilities,
@Transport int transportType,
@@ -573,9 +576,23 @@
}
private void setupSubscriptionAndStartVcn(int subId, ParcelUuid subGrp, boolean isVcnActive) {
- setUpVcnSubscription(subId, subGrp);
+ setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive, true /* hasCarrierPrivileges */);
+ }
+
+ private void setupSubscriptionAndStartVcn(
+ int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) {
+ mVcnMgmtSvc.systemReady();
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ Collections.singleton(subGrp),
+ Collections.singletonMap(subId, subGrp),
+ hasCarrierPrivileges);
+
final Vcn vcn = startAndGetVcnInstance(subGrp);
doReturn(isVcnActive).when(vcn).isActive();
+
+ doReturn(true)
+ .when(mLocationPermissionChecker)
+ .checkLocationPermission(eq(TEST_PACKAGE_NAME), any(), eq(TEST_UID), any());
}
private VcnUnderlyingNetworkPolicy startVcnAndGetPolicyForTransport(
@@ -721,7 +738,7 @@
verify(mMockPolicyListener).onPolicyChanged();
}
- private void verifyVcnCallback(
+ private void triggerVcnSafeMode(
@NonNull ParcelUuid subGroup, @NonNull TelephonySubscriptionSnapshot snapshot)
throws Exception {
verify(mMockDeps)
@@ -732,20 +749,20 @@
eq(snapshot),
mVcnCallbackCaptor.capture());
- mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
-
VcnCallback vcnCallback = mVcnCallbackCaptor.getValue();
vcnCallback.onEnteredSafeMode();
-
- verify(mMockPolicyListener).onPolicyChanged();
}
@Test
- public void testVcnCallbackOnEnteredSafeMode() throws Exception {
+ public void testVcnEnteringSafeModeNotifiesPolicyListeners() throws Exception {
TelephonySubscriptionSnapshot snapshot =
triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
- verifyVcnCallback(TEST_UUID_1, snapshot);
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+ triggerVcnSafeMode(TEST_UUID_1, snapshot);
+
+ verify(mMockPolicyListener).onPolicyChanged();
}
private void triggerVcnStatusCallbackOnEnteredSafeMode(
@@ -758,6 +775,9 @@
TelephonySubscriptionSnapshot snapshot =
triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(subGroup));
+ setupSubscriptionAndStartVcn(
+ TEST_SUBSCRIPTION_ID, subGroup, true /* isActive */, hasPermissionsforSubGroup);
+
doReturn(hasPermissionsforSubGroup)
.when(snapshot)
.packageHasPermissionsForSubscriptionGroup(eq(subGroup), eq(pkgName));
@@ -768,10 +788,7 @@
mVcnMgmtSvc.registerVcnStatusCallback(subGroup, mMockStatusCallback, pkgName);
- // Trigger systemReady() to set up LocationPermissionChecker
- mVcnMgmtSvc.systemReady();
-
- verifyVcnCallback(subGroup, snapshot);
+ triggerVcnSafeMode(subGroup, snapshot);
}
@Test
@@ -825,6 +842,83 @@
assertEquals(TEST_PACKAGE_NAME, cbInfo.mPkgName);
assertEquals(TEST_UID, cbInfo.mUid);
verify(mMockIBinder).linkToDeath(eq(cbInfo), anyInt());
+
+ verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
+ }
+
+ @Test
+ public void testRegisterVcnStatusCallback_MissingPermission() throws Exception {
+ setupSubscriptionAndStartVcn(
+ TEST_SUBSCRIPTION_ID,
+ TEST_UUID_1,
+ true /* isActive */,
+ false /* hasCarrierPrivileges */);
+
+ mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
+
+ verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
+ }
+
+ @Test
+ public void testRegisterVcnStatusCallback_VcnInactive() throws Exception {
+ setupSubscriptionAndStartVcn(
+ TEST_SUBSCRIPTION_ID,
+ TEST_UUID_1,
+ true /* isActive */,
+ true /* hasCarrierPrivileges */);
+
+ // VCN is currently active. Lose carrier privileges for TEST_PACKAGE and hit teardown
+ // timeout so the VCN goes inactive.
+ final TelephonySubscriptionSnapshot snapshot =
+ triggerSubscriptionTrackerCbAndGetSnapshot(
+ Collections.singleton(TEST_UUID_1),
+ Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_1),
+ false /* hasCarrierPrivileges */);
+ mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS);
+ mTestLooper.dispatchAll();
+
+ // Giving TEST_PACKAGE privileges again will restart the VCN (which will indicate ACTIVE
+ // when the status callback is registered). Instead, setup permissions for TEST_CB_PACKAGE
+ // so that it's permissioned to receive INACTIVE (instead of NOT_CONFIGURED) without
+ // reactivating the VCN.
+ doReturn(true)
+ .when(snapshot)
+ .packageHasPermissionsForSubscriptionGroup(
+ eq(TEST_UUID_1), eq(TEST_CB_PACKAGE_NAME));
+ doReturn(true)
+ .when(mLocationPermissionChecker)
+ .checkLocationPermission(eq(TEST_CB_PACKAGE_NAME), any(), eq(TEST_UID), any());
+
+ mVcnMgmtSvc.registerVcnStatusCallback(
+ TEST_UUID_1, mMockStatusCallback, TEST_CB_PACKAGE_NAME);
+
+ verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_INACTIVE);
+ }
+
+ @Test
+ public void testRegisterVcnStatusCallback_VcnActive() throws Exception {
+ setupSubscriptionAndStartVcn(
+ TEST_SUBSCRIPTION_ID,
+ TEST_UUID_1,
+ true /* isActive */,
+ true /* hasCarrierPrivileges */);
+
+ mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
+
+ verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
+ }
+
+ @Test
+ public void testRegisterVcnStatusCallback_VcnSafeMode() throws Exception {
+ setupSubscriptionAndStartVcn(
+ TEST_SUBSCRIPTION_ID,
+ TEST_UUID_1,
+ false /* isActive */,
+ true /* hasCarrierPrivileges */);
+
+ mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME);
+
+ verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE);
}
@Test(expected = IllegalStateException.class)
diff --git a/tools/bit/make.cpp b/tools/bit/make.cpp
index c39f494..2a88732 100644
--- a/tools/bit/make.cpp
+++ b/tools/bit/make.cpp
@@ -90,8 +90,7 @@
Json::Value json;
Json::CharReaderBuilder builder;
- std::string errorMessage;
- if (!Json::parseFromStream(builder, stream, &json, &errorMessage)) {
+ if (!Json::parseFromStream(builder, stream, &json, /* errorMessage = */ nullptr)) {
return;
}
@@ -215,8 +214,7 @@
Json::Value json;
Json::CharReaderBuilder builder;
- std::string errorMessage;
- if (!Json::parseFromStream(builder, stream, &json, &errorMessage)) {
+ if (!Json::parseFromStream(builder, stream, &json, /* errorMessage = */ nullptr)) {
json_error(filename, "can't parse json format", quiet);
return;
}